diff --git a/l10n_br_account_payment_brcobranca/README.rst b/l10n_br_account_payment_brcobranca/README.rst new file mode 100644 index 000000000000..38d762394e94 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/README.rst @@ -0,0 +1,217 @@ +================================== +L10n Br Account Payment BRCobranca +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:896c08dd79ba5a1f4513fa2c976536704bade78131f0dd7dd71c0dce18040b8d + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--brazil-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-brazil/tree/16.0/l10n_br_account_payment_brcobranca + :alt: OCA/l10n-brazil +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-brazil-16-0/l10n-brazil-16-0-l10n_br_account_payment_brcobranca + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-brazil&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +**Português** +Esse modulo implementa o CNAB usando a biblioteca BRCobranca +https://github.com/kivanio/brcobranca . + +**English** +This module implement brazilian bank splips('Boletos Bancarios') by using +BRCobranca(https://github.com/kivanio/brcobranca). + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +**Português** +O modulo depende do: + +* l10n_br_account_payment_order +* account_move_base_import + +**English** +This module depends on: + +* l10n_br_account_payment_order +* account_move_base_import + +Configuration +============= + +**Português** +Para configurar esse modulo é preciso: + +* Rodar a biblioteca BRCobranca como um micro-serviço https://github.com/akretion/boleto_cnab_api . +* Informar a variável de ambiente **BRCOBRANCA_API_URL** no arquivo de configuração do Odoo ou se estiver usando o docky na seção enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , exemplo: + **BRCOBRANCA_API_URL=http://boleto_cnab_api:9292** +* Verifique se os Códigos de Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Instrução do Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml . +* Verifique se os Códigos de Retorno do Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Retorno de Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml . +* Criar a Conta Bancária referente ao CNAB em Faturamento > Configurações > Contabilidade > Contas Bancárias . +* Automaticamente será criado um Diário Contábil referente a conta bancária em Faturamento > Configurações > Contabilidade > Diários na aba **Informações Referentes a Importação** informe as configurações de Retorno do CNAB nos campos "Tipo de Importação", "Conta de Recebimento/Pagamento", "Criação de Contra-Partida" e se deve ser feita a reconciliação automática ao importar o arquivo em "Reconciliar Automaticamente o Retorno de Pagamento". +* Em Faturamento > Configurações > Administração > Modos de Pagamento criar um Modo de Pagamento com as informações do CNAB, no campo "Diário de Banco Fixo" informar o Diário Contábil da conta bancária e se for o caso, e é recomendado, marcar a opção "Adicionar automaticamente ao validar a fatura" para não ser preciso fazer manualmente. +* Caso o CNAB e Banco escolhidos possua um campo especifico que seja preciso implementar considere fazer um PR no modulo l10n_br_account_payment_order aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/models/l10n_br_cnab_boleto_fields.py#L307 . +* Configure as permissões de acesso dos usuários, as opções são CNAB "Usuário" e "Gerente". + +**English** +To configure this module, you need to: + +* Run BRCobranca as micro-service https://github.com/akretion/boleto_cnab_api. +* Inform the envoriment variable BRCOBRANCA_API_URL in the config odoo file or if are use docky in the section enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , example: + **BRCOBRANCA_API_URL=http://boleto_cnab_api:9292** +* Check if the CNAB Instruction Movement Code to be use exist in Invoicing > Configuration > Management > CNAB Movement Instruction Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml . +* Check if the CNAB Return Move Code to be use exist in Invoicing > Configuration > Management > CNAB Return Move Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml . +* Create an Bank Account referent of CNAB in Invoicing > Configuration > Accounting > Bank Accounts . +* Automatic will be create an Account Journal refer to bank account in Invoicing > Configuration > Accounting > Journals in tab **Import related infos** inform parameters of CNAB Return in fields "Type of Import", "Receivable/Payable Account", "Create Counterpart", and if should make automatic reconciliation when import the file in "Automatic Reconcile payment returns". +* In Invoicing > Configuration > Management > Payment Modes create an Payment Mode with CNAB information, in the field "Fixed Bank Journal" inform the Account Journal of bank account and mark if "Automatically add when validating the invoice" so that you don't have to do it manually. +* Configure user access permissions, CNAB options are "User" and "Manager". + +Usage +===== + +**Português** + +* Ao criar e Confirmar uma Fatura que tem um Modo de Pagamento que seja CNAB deverá aparecer o botão de "Imprimir Boleto". +* Caso esteja marcado no Modo de Pagamento a opção de "Adicionar automaticamente ao validar a fatura" será criada ou adicionada em uma Ordem de Pagamento as linhas de pagamentos do CNAB, se a opção não estiver marcada será preciso fazer isso manualmente podendo ser feito tanto na Fatura quanto na Ordem de Pagamento. +* Ao Confirmar essa Ordem de Pagamento será possível gerar o arquivo de Remessa CNAB a ser enviado ao Banco, é importante confirmar o envio do arquivo alterando o status da ordem para "Arquivo Enviado", essa informação é usada para validar se existe uma instrução CNAB pendente antes de se poder criar outra. +* Alterações de CNAB como Alteração da Data de Vencimento, Protesto, Conceder Abatimento e etc podem ser feitas na própria Fatura em Faturamento > Clientes > Faturas na aba Recebimentos na última coluna existe o botão "Atualizar Informação CNAB" ao clicar em uma linha essa opção também aparece, ao fazer uma alteração é criada ou adicionada em uma Ordem de Pagamento a Instrução de Movimento CNAB selecionada. +* A importação do arquivo CNAB de Retorno pode ser feita em Pagamentos > Importar arquivo Batch ou no próprio Diário em Faturamento > Configurações > Contabilidade > Diários na aba **Informações Referentes a Importação** o botão Importar arquivo Batch. +* Toda importação de arquivo de retorno cria uma LOG que pode ser consultado em Pagamentos > LOG de Retorno CNAB. +* Caso o Código de Retorno CNAB recebido seja um dos "Códigos de Liquidação do Retorno do Movimento" do Modo de Pagamento será criado uma Entrada de Diário com os valores quando existirem de desconto, juros/mora, tarifa bancaria, abatimento e valor a ser reconciliado com a linha da Fatura referente, os lançamentos são separados de acordo com as Contas Contabéis definidas no Modo de Pagamento, a linha para reconciliar a linha da Fatura precisam ser iguais por isso o valor é: + valor_recebido_calculado = (valor_recebido + valor_desconto + valor_abatimento) - valor_juros_mora +* Quando marcada a opção de "Reconciliação Automatica" /a Entrada de Diário será movida para o status Lançado automaticamente ao importar o arquivo, se não estiver marcada isso deverá ser feito manualmente. + +**English** + +* When creating and confirming an Invoice that has a Payment Mode that is CNAB, the button should appear "Print Boleto". +* If the option to "Add automatically when validating the invoice" is marked in the Payment Mode CNAB payment lines will be created or added to a Payment Order, if the option is not marked, you will need to do this manually, which can be done both in the Invoice and in the Payment Order. +* By confirming this Payment Order it will be possible to generate the CNAB Remessa file to be sent to the Bank, it is important to confirm the upload of the file by changing the order status to "File Uploaded", this information is used to validate if there is a pending CNAB instruction before another one can be created. +* CNAB changes such as Change Due Date, Protest, Grant Rebate, etc. can be made in the Invoice itself in Invoicing > Customers > Invoices in the Receivable tab in the last column there is the button "Update CNAB Information" when clicking on a line this option also appears, when making a change it is created or added to a Payment Order the selected CNAB Movement Instruction. +* The import of the Return CNAB file can be done in Payments > Import Batch file or in the same Journal in Invoicing > Configuration > Accounting > Journals in the tab **Import related infos** the Import Batch File button. +* Every return file import creates a LOG that can be consulted in Payments > CNAB Return LOG. +* If the CNAB Return Code received is one of the "CNAB Liquidity Return Move Code" of the Payment Mode, a Journal Entry will be created with the values when there are discount, interest, tariff charge, rebate and amount to be reconciled with the referring Invoice line, entries are separated according to the Accounts defined in the Payment Mode, the line to reconcile the Invoice line need be equal so the value is: + calculated_value_receive = (receive_amount + discount_amount + rebate_amount) - interest_amount +* When the "Automatic Reconciliation" option is checked, the Entry of Journal will be moved to the status Posted automatically when importing the file, if not checked it should be done manually. + +Known issues / Roadmap +====================== + +* Incluir a posssibilidade de imprimir o boleto no menu Imprimir da Fatura, na v12 aparentemente não é possível chamar um metodo apenas um QWeb, verificar na migração para outras versões. + +Changelog +========= + +14.0.1.0.0 (2022-05-26) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration + +12.0.1.0.0 (2021-05-07) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Finish migration +* [IMP] Integrate with module account_move_base_import used to import CNAB file +* [IMP] Make possible automatic reconciliation and register the values of Fees, Tariff Bank, Rebate in configured accounts. + +12.0.1.0.0 (2020-06-12) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Start Migration + +10.0.1.0.0 (2019-05-30) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration + +8.0.1.0.0 (2018-01-29) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REF] Maked functional to print Boleto, create CNAB file and import CNAB as Extrat Bank the user should be resolved manully the divergences between the values( Fee, Tariff Bank, Rebate, etc). + +8.0.1.0.0 (2017-07-01) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [NEW] First version + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* `Akretion `_: + * Raphaël Valyi + * Magno Costa + +* `Engenere `_: + * Antônio S. Pereira Neto + +Other credits +~~~~~~~~~~~~~ + +The development of this module has been financially supported by: + +* AKRETION LTDA - https://akretion.com/pt-BR + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-rvalyi| image:: https://github.com/rvalyi.png?size=40px + :target: https://github.com/rvalyi + :alt: rvalyi +.. |maintainer-mbcosta| image:: https://github.com/mbcosta.png?size=40px + :target: https://github.com/mbcosta + :alt: mbcosta + +Current `maintainers `__: + +|maintainer-rvalyi| |maintainer-mbcosta| + +This module is part of the `OCA/l10n-brazil `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_br_account_payment_brcobranca/__init__.py b/l10n_br_account_payment_brcobranca/__init__.py new file mode 100644 index 000000000000..cc9711dc1bbc --- /dev/null +++ b/l10n_br_account_payment_brcobranca/__init__.py @@ -0,0 +1,3 @@ +from . import models +from . import parser +from . import wizard diff --git a/l10n_br_account_payment_brcobranca/__manifest__.py b/l10n_br_account_payment_brcobranca/__manifest__.py new file mode 100644 index 000000000000..e2be99e8d020 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/__manifest__.py @@ -0,0 +1,34 @@ +# Copyright 2017 Akretion +# @author Raphaël Valyi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "L10n Br Account Payment BRCobranca", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Akretion, " "Odoo Community Association (OCA)", + "maintainers": ["rvalyi", "mbcosta"], + "website": "https://github.com/OCA/l10n-brazil", + "depends": [ + "l10n_br_account_payment_order", + "account_move_base_import", + ], + "data": [ + # Security + "security/ir.model.access.csv", + # Views + "views/account_journal_view.xml", + # Wizard + "wizard/import_statement_view.xml", + ], + "demo": [ + "demo/account_journal_demo.xml", + "demo/account_move_demo.xml", + "demo/account_payment_mode.xml", + ], + "external_dependencies": { + "python": [ + "erpbrasil.base>=2.3.0", + ] + }, +} diff --git a/l10n_br_account_payment_brcobranca/constants/br_cobranca.py b/l10n_br_account_payment_brcobranca/constants/br_cobranca.py new file mode 100644 index 000000000000..622c859328b3 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/constants/br_cobranca.py @@ -0,0 +1,85 @@ +# Copyright 2020 Akretion +# @author Magno Costa +# Copyright 2020 KMEE +# @author Luis Felipe Mileo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import os +from collections import namedtuple + +from odoo import _ +from odoo.exceptions import UserError +from odoo.tools import config + +DICT_BRCOBRANCA_CNAB_TYPE = { + "240": "cnab240", + "400": "cnab400", +} + +BankRecord = namedtuple("Bank", "name, retorno, remessa") + +DICT_BRCOBRANCA_BANK = { + "001": BankRecord("banco_brasil", retorno=["400"], remessa=["240", "400"]), + "004": BankRecord("banco_nordeste", retorno=["400"], remessa=["400"]), + "021": BankRecord("banestes", retorno=[], remessa=[]), + "033": BankRecord("santander", retorno=["400", "240"], remessa=["400", "240"]), + "041": BankRecord("banrisul", retorno=["400"], remessa=["400"]), + "070": BankRecord("banco_brasilia", retorno=[], remessa=["400"]), + "085": BankRecord("ailos", retorno=["240"], remessa=["240"]), + "097": BankRecord("credisis", retorno=["400"], remessa=["400"]), + "104": BankRecord("caixa", retorno=["240"], remessa=["240"]), + "136": BankRecord("unicred", retorno=["400"], remessa=["240", "400"]), + "237": BankRecord("bradesco", retorno=["400"], remessa=["400"]), + "341": BankRecord("itau", retorno=["400"], remessa=["400"]), + "399": BankRecord("hsbc", retorno=[], remessa=[]), + "745": BankRecord("citibank", retorno=[], remessa=["400"]), + "748": BankRecord("sicredi", retorno=["240"], remessa=["240"]), + "756": BankRecord("sicoob", retorno=["240"], remessa=["240", "400"]), +} + +DICT_BRCOBRANCA_CURRENCY = { + "R$": "9", +} + + +def get_brcobranca_bank(bank_account_id, payment_method_code): + bank_name_brcobranca = DICT_BRCOBRANCA_BANK.get(bank_account_id.bank_id.code_bc) + + # Metodo get_brcobranca_bank chamado apenas nos casos de Remessa, + # por isso apenas esse caso é validado. + cnab_remessa = bank_name_brcobranca[2] + if not bank_name_brcobranca or payment_method_code not in cnab_remessa: + # Lista de bancos não implentados no BRCobranca + raise UserError( + _( + "The Bank %(bank)s CNAB %(cnab_code)s is not implemented " + "in BRCobranca.", + bank=bank_account_id.bank_id.name, + cnab_code=payment_method_code, + ) + ) + return bank_name_brcobranca + + +def get_brcobranca_api_url(env): + brcobranca_api_url = ( + os.environ.get("BRCOBRANCA_API_URL") + or config.get("brcobranca_api_url") + or env["ir.config_parameter"].sudo().get_param("brcobranca_api_url") + ) + + if not brcobranca_api_url: + raise UserError( + _( + "BRCobranca API URL is not configured.\n\n" + " Set the URL using one of the these methods:\n\n" + "1. Set the environment variable:" + " BRCOBRANCA_API_URL=http://boleto_cnab_api:9292\n" + "2. Configure the URL in Odoo configuration file:" + " brcobranca_api_url=http://boleto_cnab_api:9292\n" + "3. Set the URL in System Parameters:" + " brcobranca_api_url=http://boleto_cnab_api:9292\n" + ) + ) + + return brcobranca_api_url diff --git a/l10n_br_account_payment_brcobranca/demo/account_journal_demo.xml b/l10n_br_account_payment_brcobranca/demo/account_journal_demo.xml new file mode 100644 index 000000000000..af9cb8c7b671 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/demo/account_journal_demo.xml @@ -0,0 +1,26 @@ + + + + + + + True + cnab400 + + True + + + + True + cnab240 + + True + + + diff --git a/l10n_br_account_payment_brcobranca/demo/account_move_demo.xml b/l10n_br_account_payment_brcobranca/demo/account_move_demo.xml new file mode 100644 index 000000000000..3e3675e1b10f --- /dev/null +++ b/l10n_br_account_payment_brcobranca/demo/account_move_demo.xml @@ -0,0 +1,27 @@ + + + + + + Teste Unicred CNAB400 - BRCobranca + + + out_invoice + + + TESTE Intruções Boleto + + + + diff --git a/l10n_br_account_payment_brcobranca/demo/account_payment_mode.xml b/l10n_br_account_payment_brcobranca/demo/account_payment_mode.xml new file mode 100644 index 000000000000..a2d25b15485c --- /dev/null +++ b/l10n_br_account_payment_brcobranca/demo/account_payment_mode.xml @@ -0,0 +1,116 @@ + + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + + + brcobranca + + + diff --git a/l10n_br_account_payment_brcobranca/i18n/l10n_br_account_payment_brcobranca.pot b/l10n_br_account_payment_brcobranca/i18n/l10n_br_account_payment_brcobranca.pot new file mode 100644 index 000000000000..38d15f99a012 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/i18n/l10n_br_account_payment_brcobranca.pot @@ -0,0 +1,176 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_br_account_payment_brcobranca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__return_auto_reconcile +msgid "Automatic Reconcile payment returns" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/constants/br_cobranca.py:0 +#, python-format +msgid "" +"BRCobranca API URL is not configured.\n" +"\n" +" Set the URL using one of the these methods:\n" +"\n" +"1. Set the environment variable: BRCOBRANCA_API_URL=http://boleto_cnab_api:9292\n" +"2. Configure the URL in Odoo configuration file: brcobranca_api_url=http://boleto_cnab_api:9292\n" +"3. Set the URL in System Parameters: brcobranca_api_url=http://boleto_cnab_api:9292\n" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields.selection,name:l10n_br_account_payment_brcobranca.selection__account_journal__import_type__cnab240 +msgid "CNAB 240" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields.selection,name:l10n_br_account_payment_brcobranca.selection__account_journal__import_type__cnab400 +msgid "CNAB 400" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__cnab_returned_ref +msgid "CNAB Returned Reference" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,help:l10n_br_account_payment_brcobranca.field_account_journal__import_type +msgid "" +"Choose here the method by which you want to import account moves for this " +"journal." +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,help:l10n_br_account_payment_brcobranca.field_account_journal__return_auto_reconcile +msgid "Enable automatic payment return reconciliation." +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import__id +msgid "ID" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.ui.menu,name:l10n_br_account_payment_brcobranca.move_importer_menu_brcobranca +msgid "Import Batch File" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_credit_statement_import +msgid "Import Batch File wizard" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_move.py:0 +#, python-format +msgid "" +"It is not possible generated boletos\n" +"Make sure the Invoice are in Confirm state and Payment Mode method are CNAB." +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_journal +msgid "Journal" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "" +"Missing column! Column %s you try to import is not present in the move line!" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "Nothing to import: The file is empty" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_line +msgid "Payment Lines" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_mode +msgid "Payment Modes" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_order +msgid "Payment Order" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "Statement import error The statement cannot be created: %s" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/constants/br_cobranca.py:0 +#, python-format +msgid "The Bank {} CNAB {} is not implemented in BRCobranca." +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_payment_order.py:0 +#, python-format +msgid "The CNAB {} for Bank {} are not implemented in BRCobranca." +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__import_type +msgid "Type of import" +msgstr "" diff --git a/l10n_br_account_payment_brcobranca/i18n/pt_BR.po b/l10n_br_account_payment_brcobranca/i18n/pt_BR.po new file mode 100644 index 000000000000..bf6b99014660 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/i18n/pt_BR.po @@ -0,0 +1,229 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_br_account_payment_brcobranca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-02-06 13:34+0000\n" +"Last-Translator: Marcel Savegnago \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__return_auto_reconcile +msgid "Automatic Reconcile payment returns" +msgstr "Reconciliar automaticamente as devoluções de pagamento" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/constants/br_cobranca.py:0 +#, python-format +msgid "" +"BRCobranca API URL is not configured.\n" +"\n" +" Set the URL using one of the these methods:\n" +"\n" +"1. Set the environment variable: BRCOBRANCA_API_URL=http://" +"boleto_cnab_api:9292\n" +"2. Configure the URL in Odoo configuration file: brcobranca_api_url=http://" +"boleto_cnab_api:9292\n" +"3. Set the URL in System Parameters: brcobranca_api_url=http://" +"boleto_cnab_api:9292\n" +msgstr "" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields.selection,name:l10n_br_account_payment_brcobranca.selection__account_journal__import_type__cnab240 +msgid "CNAB 240" +msgstr "CNAB 240" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields.selection,name:l10n_br_account_payment_brcobranca.selection__account_journal__import_type__cnab400 +msgid "CNAB 400" +msgstr "CNAB 400" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__cnab_returned_ref +msgid "CNAB Returned Reference" +msgstr "Referência Retornada CNAB" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,help:l10n_br_account_payment_brcobranca.field_account_journal__import_type +msgid "" +"Choose here the method by which you want to import account moves for this " +"journal." +msgstr "" +"Escolha aqui o método pelo qual você deseja importar lançamentos de diário " +"para este diário." + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order__display_name +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import__display_name +msgid "Display Name" +msgstr "Nome Exibido" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,help:l10n_br_account_payment_brcobranca.field_account_journal__return_auto_reconcile +msgid "Enable automatic payment return reconciliation." +msgstr "Habilitar reconciliação do retorno de pagamento automático." + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order__id +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import__id +msgid "ID" +msgstr "ID" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.ui.menu,name:l10n_br_account_payment_brcobranca.move_importer_menu_brcobranca +msgid "Import Batch File" +msgstr "Importar Arquivo de Lote" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_credit_statement_import +msgid "Import Batch File wizard" +msgstr "Importar Arquivo de Lote wizard" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_move.py:0 +#, python-format +msgid "" +"It is not possible generated boletos\n" +"Make sure the Invoice are in Confirm state and Payment Mode method are CNAB." +msgstr "" +"Não é possível gerar boletos\n" +"Esteja certo de que as Faturas estejam no estado Confirmado e Método do Modo " +"de Pagamento sejam CNAB." + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_journal +msgid "Journal" +msgstr "Diário" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_move +msgid "Journal Entry" +msgstr "Lançamento de Diário" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_move_line +msgid "Journal Item" +msgstr "Item de Diário" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_move_line____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_line____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_mode____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_payment_order____last_update +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_credit_statement_import____last_update +msgid "Last Modified on" +msgstr "Última Modificação em" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "" +"Missing column! Column %s you try to import is not present in the move line!" +msgstr "" +"Coluna faltando! Coluna %s que você tenta importar não está presente no item " +"de diário!" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "Nothing to import: The file is empty" +msgstr "Nada a importar: O arquivo está vazio" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_line +msgid "Payment Lines" +msgstr "Linhas de Pagamento" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_mode +msgid "Payment Modes" +msgstr "Modos de Pagamento" + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model,name:l10n_br_account_payment_brcobranca.model_account_payment_order +msgid "Payment Order" +msgstr "Ordem de Pagamento" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_journal.py:0 +#, python-format +msgid "Statement import error The statement cannot be created: %s" +msgstr "Erro de importação de extrato. O extrato não pode ser criado: %s" + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/constants/br_cobranca.py:0 +#, python-format +msgid "The Bank {} CNAB {} is not implemented in BRCobranca." +msgstr "O banco {} CNAB {} não está implantado no BRCobranca." + +#. module: l10n_br_account_payment_brcobranca +#: code:addons/l10n_br_account_payment_brcobranca/models/account_payment_order.py:0 +#, python-format +msgid "The CNAB {} for Bank {} are not implemented in BRCobranca." +msgstr "O CNAB {} para o banco {} não está implementado no BRCobranca." + +#. module: l10n_br_account_payment_brcobranca +#: model:ir.model.fields,field_description:l10n_br_account_payment_brcobranca.field_account_journal__import_type +msgid "Type of import" +msgstr "Tipo de importação" + +#, python-format +#~ msgid "" +#~ "Inform the URL where BRCobranca API are running in Odoo Configuration " +#~ "file or if you are using docky in the docker-compose.yml file. Example:\n" +#~ "BRCOBRANCA_API_URL=http://boleto_cnab_api:9292" +#~ msgstr "" +#~ "Informar a URL onde a API BR Cobranca está executando no arquivo de " +#~ "Configuração Odoo ou , caso esteja usando docky no arquivo docker-compose." +#~ "yml. Exemplo:\n" +#~ "BRCOBRANCA_API_URL=http://boleto_cnab_api:9292" + +#~ msgid "Boleto PDF" +#~ msgstr "Boleto PDF" + +#~ msgid "Code (Do Not Modify)" +#~ msgstr "Código (não modificar)" + +#~ msgid "Imprimir Boleto" +#~ msgstr "Imprimir Boleto" + +#~ msgid "" +#~ "This code is used in the code of the Odoo module that handles this " +#~ "payment method. Therefore, if you change it, the generation of the " +#~ "payment file may fail." +#~ msgstr "" +#~ "Este código é usado no código do módulo Odoo que lida com este método de " +#~ "pagamento. Portanto, se você alterá-lo, a geração do arquivo de pagamento " +#~ "pode falhar." + +#~ msgid "Bank Payment Lines" +#~ msgstr "Linhas de Pagamento Bancário" + +#, python-format +#~ msgid "The Bank %s CNAB %s is not implemented in BRCobranca." +#~ msgstr "O Banco %s CNAB %s não implementado no BRCobranca." + +#, python-format +#~ msgid "The CNAB %s for Bank %s are not implemented in BRCobranca." +#~ msgstr "O CNAB %s para Banco %s não implementado no BRCobranca." diff --git a/l10n_br_account_payment_brcobranca/models/__init__.py b/l10n_br_account_payment_brcobranca/models/__init__.py new file mode 100644 index 000000000000..2bb4d1b7bf70 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/__init__.py @@ -0,0 +1,6 @@ +from . import account_move_line +from . import account_move +from . import account_payment_order +from . import account_payment_line +from . import account_journal +from . import account_payment_mode diff --git a/l10n_br_account_payment_brcobranca/models/account_journal.py b/l10n_br_account_payment_brcobranca/models/account_journal.py new file mode 100644 index 000000000000..76aa2215c4ce --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_journal.py @@ -0,0 +1,245 @@ +# @ 2020 Akretion - www.akretion.com.br - +# Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +import os +import sys +import traceback + +from odoo import _, fields, models +from odoo.exceptions import UserError, ValidationError + +from odoo.addons.account_move_base_import.parser.parser import new_move_parser + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + import_type = fields.Selection( + selection_add=[("cnab400", "CNAB 400"), ("cnab240", "CNAB 240")] + ) + + return_auto_reconcile = fields.Boolean( + string="Automatic Reconcile payment returns", + help="Enable automatic payment return reconciliation.", + default=False, + ) + + def multi_move_import(self, file_stream, ftype="csv"): + """Create multiple bank statements from values given by the parser for + the given profile. + + :param int/long profile_id: ID of the profile used to import the file + :param filebuffer file_stream: binary of the provided file + :param char: ftype represent the file extension (csv by default) + :return: list: list of ids of the created account.bank.statement + """ + filename = self._context.get("file_name", None) + if filename: + (filename, __) = os.path.splitext(filename) + parser = new_move_parser(self, ftype=ftype, move_ref=filename) + res_move = self.env["account.move"] + res_cnab_log = self.env["l10n_br_cnab.return.log"] + for result_row_list in parser.parse(file_stream): + result = self._move_import( + parser, + file_stream, + result_row_list=result_row_list, + ftype=ftype, + ) + + if len(result) > 1 or result._name == "account.move": + res_move |= result + if result._name == "l10n_br_cnab.return.log": + res_cnab_log |= result + if res_move: + return res_move + else: + return res_cnab_log + + def _move_import(self, parser, file_stream, result_row_list=None, ftype="csv"): + # Overwrite this method to create the CNAB Return Log and change + # the warning message when the file don't has any line to create + # the Journal Entry, because in CNAB exist the case where + # the file just has only Log information. + + # Call super when file is not CNAB + if ftype == "csv": + super()._move_import(parser, file_stream, result_row_list=None, ftype="csv") + + attachment_obj = self.env["ir.attachment"] + if result_row_list is None: + result_row_list = parser.result_row_list + + # Original Method + # Check all key are present in account.bank.statement.line!! + # if not result_row_list: + # raise UserError(_("Nothing to import: " "The file is empty")) + if not result_row_list and not parser.cnab_return_events: + raise UserError(_("Nothing to import: " "The file is empty")) + + # Creation of CNAB Return Log + cnab_return_log, file_name = self._create_cnab_return_log(parser) + + attachment_data = { + "name": file_name, + "datas": file_stream, + "store_fname": file_name, + "res_model": "l10n_br_cnab.return.log", + "res_id": cnab_return_log.id, + } + attachment_obj.create(attachment_data) + + if not result_row_list: + return cnab_return_log + + moves = self._get_moves(parser, result_row_list) + + cnab_return_log.move_ids = moves.ids + for move in moves: + # CNAB Return Log + move.cnab_return_log_id = cnab_return_log.id + # Lançamento Automatico do Diário + if self.return_auto_reconcile: + move.action_post() + + return moves + + def _create_cnab_return_log(self, parser): + context = self.env.context + cnab_return_log = self.env["l10n_br_cnab.return.log"].create( + { + "name": "Banco " + + parser.bank.short_name + + " - Conta " + + parser.journal.bank_account_id.acc_number, + "filename": context.get("file_name"), + "cnab_date_import": fields.Datetime.now(), + "bank_account_id": parser.journal.bank_account_id.id, + } + ) + qty_cnab_return_events = ( + amount_total_title + ) = ( + amount_total_received + ) = ( + amount_total_tariff_charge + ) = ( + amount_total_interest_fee + ) = amount_total_discount = amount_total_rebate = 0.0 + + for cnab_return_event in parser.cnab_return_events: + amount_total_title += cnab_return_event.get("title_value") + if cnab_return_event.get("payment_value"): + amount_total_received += cnab_return_event.get("payment_value") + if cnab_return_event.get("tariff_charge"): + amount_total_tariff_charge += cnab_return_event.get("tariff_charge") + if cnab_return_event.get("rebate_value"): + amount_total_rebate += cnab_return_event.get("rebate_value") + if cnab_return_event.get("discount_value"): + amount_total_discount += cnab_return_event.get("discount_value") + if cnab_return_event.get("interest_fee_value"): + amount_total_interest_fee += cnab_return_event.get("interest_fee_value") + cnab_return_event["cnab_return_log_id"] = cnab_return_log.id + cnab_return_event["payment_line_ids"] = cnab_return_event.get( + "payment_line_ids" + ) + self.env["l10n_br_cnab.return.event"].create(cnab_return_event) + qty_cnab_return_events += 1 + + cnab_return_log.number_events = qty_cnab_return_events + cnab_return_log.amount_total_title = amount_total_title + cnab_return_log.amount_total_received = amount_total_received + cnab_return_log.amount_total_tariff_charge = amount_total_tariff_charge + cnab_return_log.amount_total_interest_fee = amount_total_interest_fee + cnab_return_log.amount_total_discount = amount_total_discount + cnab_return_log.amount_total_rebate = amount_total_rebate + + return cnab_return_log, context.get("file_name") + + def _get_moves(self, parser, result_row_list): + move_obj = self.env["account.move"] + move_line_obj = self.env["account.move.line"] + moves = self.env["account.move"] + # Cada retorno precisa ser feito um único account.move para que o campo + # Date tanto da account.move quanto o account.move.line tenha o mesmo + # valor e sejam referentes a Data de Credito daquele lançamento + # especifico. + for result_row in result_row_list: + parsed_cols = list(parser.get_move_line_vals(result_row[0]).keys()) + for col in parsed_cols: + if col not in move_line_obj._fields: + raise UserError( + _( + "Missing column! Column %s you try to import is not " + "present in the move line!" + ) + % col + ) + + move_vals = self.prepare_move_vals(result_row, parser) + + # O campo referente a Data de Credito no account.move é o date que + # no account.move.line existe um related desse campo a forma de + # obter e preencher ele por enquanto e feito da forma abaixo, + # verificar se possível melhorar isso. + data_credito = "" + for row in result_row: + if row.get("type") == "liquidado": + data_credito = row.get("date") + break + move_vals["date"] = data_credito + + move = move_obj.create(move_vals) + moves |= move + try: + # Record every line in the bank statement + move_store = [] + for line in result_row: + parser_vals = parser.get_move_line_vals(line) + values = self.prepare_move_line_vals(parser_vals, move) + move_store.append(values) + move_store += self._get_extra_move_line_vals_list(parser, move) + if self.create_counterpart: + move_store += self._get_counterpart_vals_list( + parser, move, move_store + ) + # Check if move is balanced + container = {"records": move} + with move._check_balanced(container): + move_line_obj.create(move_store) + # Computed total amount of the move + # move._amount_compute() + # No caso do CNAB o arquivo usado está sendo armazenado no + # objeto l10n_br_cnab.return.log já que um arquivo pode gerar + # diversos account.move + # Attach data to the move + # attachment_data = { + # "name": "statement file", + # "datas": file_stream, + # "datas_fname": "%s.%s" % (fields.Date.today(), ftype), + # "res_model": "account.move", + # "res_id": move.id, + # } + # attachment_obj.create(attachment_data) + # If user ask to launch completion at end of import, do it! + if self.launch_import_completion: + move.button_auto_completion() + # Write the needed log infos on profile + self.write_logs_after_import(move, len(result_row_list)) + except UserError: + # "Clean" exception, raise as such + raise + except Exception as e: + error_type, error_value, trbk = sys.exc_info() + st = "Error: %s\nDescription: %s\nTraceback:" % ( + error_type.__name__, + error_value, + ) + st += "".join(traceback.format_tb(trbk, 30)) + raise ValidationError( + _("Statement import error " "The statement cannot be created: %s") + % st + ) from e + + return moves diff --git a/l10n_br_account_payment_brcobranca/models/account_move.py b/l10n_br_account_payment_brcobranca/models/account_move.py new file mode 100644 index 000000000000..ba681e6ea005 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_move.py @@ -0,0 +1,114 @@ +# Copyright 2020 Akretion +# @author Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import json +import logging +import tempfile + +import requests + +from odoo import _, models +from odoo.exceptions import UserError + +from ..constants.br_cobranca import get_brcobranca_api_url + +logger = logging.getLogger(__name__) + + +class AccountMove(models.Model): + _inherit = "account.move" + + def generate_boleto_pdf(self): + if self.payment_mode_id.cnab_processor != "brcobranca": + return super().generate_boleto_pdf() + + file_pdf = self.file_boleto_pdf_id + self.file_boleto_pdf_id = False + file_pdf.unlink() + + receivable_ids = self.mapped("financial_move_line_ids") + + boletos = receivable_ids.send_payment() + if not boletos: + raise UserError( + _( + "It is not possible generated boletos\n" + "Make sure the Invoice are in Confirm state and " + "Payment Mode method are CNAB." + ) + ) + + pdf_string = self._get_brcobranca_boleto(boletos) + + inv_number = self.get_invoice_fiscal_number().split("/")[-1].zfill(8) + file_name = "boleto_nf-" + inv_number + ".pdf" + + self.file_boleto_pdf_id = self.env["ir.attachment"].create( + { + "name": file_name, + "store_fname": file_name, + "res_model": self._name, + "res_id": self.id, + "datas": base64.b64encode(pdf_string), + "mimetype": "application/pdf", + "type": "binary", + } + ) + + def _get_brcobranca_boleto(self, boletos): + content = json.dumps(boletos) + f = open(tempfile.mktemp(), "w") + f.write(content) + f.close() + files = {"data": open(f.name, "rb")} + + brcobranca_api_url = get_brcobranca_api_url(self.env) + brcobranca_service_url = brcobranca_api_url + "/api/boleto/multi" + logger.info( + "Connecting to %s to get Boleto of invoice %s", + brcobranca_service_url, + self.name, + ) + res = requests.post( + brcobranca_service_url, data={"type": "pdf"}, files=files, timeout=60 + ) + + if str(res.status_code)[0] == "2": + pdf_string = res.content + else: + raise UserError(res.text.encode("utf-8")) + + return pdf_string + + def _post(self, soft=True): + result = super()._post(soft) + + for line in self.line_ids: + if line.move_id and line.cnab_returned_ref: + # Podem existir sequencias do nosso numero/own_number iguais entre + # bancos diferentes, porém os Diario/account.journal + # não pode ser o mesmo. + # IMPORTANTE: No parser estou definindo o CNAB_RETURNED_REF do + # que não quero usar aqui com account_move_line.document_number + line_to_reconcile = self.env["account.move.line"].search( + [ + ("own_number", "=", line.cnab_returned_ref), + ("journal_payment_mode_id", "=", self.journal_id.id), + ] + ) + # Vincula a última Ordem de Debito enviada + order_ids = line_to_reconcile.payment_line_ids.mapped("order_id") + for order in order_ids: + for pay_line in order.payment_line_ids: + if pay_line.move_line_id == line_to_reconcile: + order.move_ids |= line.move_id + + # Conciliação Automatica entre a Linha da Fatura e a Linha criada + if self.journal_id.return_auto_reconcile: + if line_to_reconcile: + (line + line_to_reconcile).reconcile() + line_to_reconcile.cnab_state = "done" + line_to_reconcile.payment_situation = "liquidada" + return result diff --git a/l10n_br_account_payment_brcobranca/models/account_move_line.py b/l10n_br_account_payment_brcobranca/models/account_move_line.py new file mode 100644 index 000000000000..2b44b8a45d75 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_move_line.py @@ -0,0 +1,203 @@ +# Copyright 2017 Akretion +# @author Raphaël Valyi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +from odoo import fields, models + +from odoo.addons.l10n_br_account_payment_order.constants import ( + get_boleto_especie_short_name, +) + +from ..constants.br_cobranca import DICT_BRCOBRANCA_CURRENCY, get_brcobranca_bank + +_logger = logging.getLogger(__name__) + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + # Campo tecnico para ser usado na busca da account.move.line de + # reconciliação, no caso da Linha de Liquidação é preenchido com + # Nosso Número e nos outros casos é o campo Número do Documento + # TODO: Teria alguma forma de fazer sem esse campo? Ou outro campo + # a ser usado sem a necessidade de criar um novo + cnab_returned_ref = fields.Char(string="CNAB Returned Reference", copy=False) + + # see the list of brcobranca boleto fields: + # https://github.com/kivanio/brcobranca/blob/master/lib/ + # brcobranca/boleto/base.rb + # and test a here: + # https://github.com/kivanio/brcobranca/blob/master/spec/ + # brcobranca/boleto/itau_spec.rb + + def send_payment(self): + # Desnecessario chamar o super aqui o metodo + # que esta chamando já verifica isso. + + wrapped_boleto_list = [] + + for move_line in self: + bank_account_id = move_line.payment_mode_id.fixed_journal_id.bank_account_id + bank_name_brcobranca = get_brcobranca_bank( + bank_account_id, move_line.payment_mode_id.payment_method_code + ) + + boleto_cnab_api_data = { + "bank": bank_name_brcobranca[0], + "valor": str("%.2f" % move_line.debit), + "cedente": move_line.company_id.partner_id.legal_name, + "cedente_endereco": (move_line.company_id.partner_id.street_name or "") + + " " + + (move_line.company_id.partner_id.street_number or "") + + ", " + + (move_line.company_id.partner_id.district or "") + + ", " + + (move_line.company_id.partner_id.city_id.name or "") + + " - " + + (move_line.company_id.partner_id.state_id.code or "") + + " " + + ("CEP:" + move_line.company_id.partner_id.zip or ""), + "documento_cedente": move_line.company_id.cnpj_cpf, + "sacado": move_line.partner_id.legal_name, + "sacado_documento": move_line.partner_id.cnpj_cpf, + "agencia": bank_account_id.bra_number, + "conta_corrente": bank_account_id.acc_number, + "convenio": move_line.payment_mode_id.cnab_company_bank_code, + "carteira": str(move_line.payment_mode_id.boleto_wallet), + "nosso_numero": int( + "".join(i for i in move_line.own_number if i.isdigit()) + ), + "documento_numero": move_line.document_number, + "data_vencimento": move_line.date_maturity.strftime("%Y/%m/%d"), + "data_documento": move_line.move_id.invoice_date.strftime("%Y/%m/%d"), + "especie": move_line.currency_id.symbol, + "especie_documento": get_boleto_especie_short_name( + move_line.payment_mode_id.boleto_species + ), + "moeda": DICT_BRCOBRANCA_CURRENCY["R$"], + "aceite": move_line.payment_mode_id.boleto_accept, + "sacado_endereco": (move_line.partner_id.street_name or "") + + " " + + (move_line.partner_id.street_number or "") + + ", " + + (move_line.partner_id.district or "") + + ", " + + (move_line.partner_id.city_id.name or "") + + " - " + + (move_line.partner_id.state_id.code or "") + + " " + + ("CEP:" + move_line.partner_id.zip or ""), + "data_processamento": move_line.move_id.invoice_date.strftime( + "%Y/%m/%d" + ), + "instrucao1": move_line.payment_mode_id.instructions or "", + } + + # Instrução de Juros + if move_line.payment_mode_id.boleto_interest_perc > 0.0: + valor_juros = move_line.currency_id.round( + move_line.debit + * ((move_line.payment_mode_id.boleto_interest_perc / 100) / 30), + ) + instrucao_juros = ( + "APÓS VENCIMENTO COBRAR PERCENTUAL" + + " DE %s %% AO MÊS ( R$ %s AO DIA )" + % ( + ( + "%.2f" % move_line.payment_mode_id.boleto_interest_perc + ).replace(".", ","), + ("%.2f" % valor_juros).replace(".", ","), + ) + ) + boleto_cnab_api_data.update( + { + "instrucao3": instrucao_juros, + } + ) + + # Instrução Multa + if move_line.payment_mode_id.boleto_fee_perc > 0.0: + valor_multa = move_line.currency_id.round( + move_line.debit * (move_line.payment_mode_id.boleto_fee_perc / 100), + ) + instrucao_multa = ( + "APÓS VENCIMENTO COBRAR MULTA" + + " DE %s %% ( R$ %s )" + % ( + ("%.2f" % move_line.payment_mode_id.boleto_fee_perc).replace( + ".", "," + ), + ("%.2f" % valor_multa).replace(".", ","), + ) + ) + boleto_cnab_api_data.update( + { + "instrucao4": instrucao_multa, + } + ) + + # Instrução Desconto + if move_line.boleto_discount_perc > 0.0: + valor_desconto = move_line.currency_id.round( + move_line.debit * (move_line.boleto_discount_perc / 100), + ) + instrucao_desconto_vencimento = ( + "CONCEDER DESCONTO DE" + " %s %% " + "ATÉ O VENCIMENTO EM %s ( R$ %s )" + % ( + ("%.2f" % move_line.boleto_discount_perc).replace(".", ","), + move_line.date_maturity.strftime("%d/%m/%Y"), + ("%.2f" % valor_desconto).replace(".", ","), + ) + ) + boleto_cnab_api_data.update( + { + "instrucao5": instrucao_desconto_vencimento, + } + ) + + bank_account = move_line.payment_mode_id.fixed_journal_id.bank_account_id + # Abaixo Campos Especificos de cada caso + + # 021 - BANCO DO ESTADO DO ESPIRITO SANTO + # 004 - BANCO INTER + if bank_account_id.bank_id.code_bc in ("021", "004"): + boleto_cnab_api_data.update( + { + "digito_conta_corrente": bank_account.acc_number_dig, + } + ) + + # Fields used in Sicredi and Sicoob Banks + if bank_account_id.bank_id.code_bc in ("748", "756"): + boleto_cnab_api_data.update( + { + "byte_idt": move_line.payment_mode_id.boleto_byte_idt, + "posto": move_line.payment_mode_id.boleto_post, + } + ) + # Campo usado no Unicred + if bank_account_id.bank_id.code_bc == "136": + boleto_cnab_api_data.update( + { + "conta_corrente_dv": bank_account.acc_number_dig, + } + ) + + # Campo Santander + if bank_account_id.bank_id.code_bc == "033": + # Caso Santander possui: + # Codigo de Transmissao tamanho 20 no 400 no 240 e 15 + # Codigo do Convenio tamanho 7 + # no boleto é usado o convenio + boleto_cnab_api_data.update( + { + "convenio": move_line.payment_mode_id.convention_code, + } + ) + + wrapped_boleto_list.append(boleto_cnab_api_data) + + return wrapped_boleto_list diff --git a/l10n_br_account_payment_brcobranca/models/account_payment_line.py b/l10n_br_account_payment_brcobranca/models/account_payment_line.py new file mode 100644 index 000000000000..e3641ed7677f --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_payment_line.py @@ -0,0 +1,187 @@ +# Copyright 2020 Akretion +# @author Magno Costa +# Copyright 2020 KMEE +# @author Luis Felipe Mileo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging + +from odoo import models + +_logger = logging.getLogger(__name__) + + +class AccountPaymentLine(models.Model): + _inherit = "account.payment.line" + + def _prepare_bank_line_ailos(self, payment_mode_id, linhas_pagamentos): + if self.discount_value: + # Código adotado pela FEBRABAN para identificação do desconto. + # Domínio: + # 0 = Isento + # 1 = Valor Fixo + linhas_pagamentos["cod_desconto"] = "1" + + def _prepare_bank_line_unicred(self, payment_mode_id, linhas_pagamentos): + # TODO - Valores padrões ? + # Estou preenchendo valores que se forem vazios geram erro + # os campos parecem estar usando uma Seleção que é definida + # na Febraban, isso acontece em todos os casos( CNAB 240/400 ) ? + # Isso deveria ser feito para o CNAB de outros Bancos ? + # Na criação dos campos houve a opção de deixa-los com o tipo + # CHAR ao invês de Selection por essa falta de padrão. + linhas_pagamentos["codigo_protesto"] = ( + payment_mode_id.boleto_protest_code or "3" + ) + linhas_pagamentos["dias_protesto"] = payment_mode_id.boleto_days_protest or "0" + + # Código adotado pela FEBRABAN para identificação + # do tipo de pagamento de multa. + # Domínio: + # ‘1’ = Valor Fixo (R$) + # ‘2’ = Taxa (%) + # ‘3’ = Isento + # Isento de Multa caso não exista percentual + linhas_pagamentos["codigo_multa"] = "3" + + # Isento de Mora + linhas_pagamentos["tipo_mora"] = "5" + + # TODO + # Código adotado pela FEBRABAN para identificação do desconto. + # Domínio: + # 0 = Isento + # 1 = Valor Fixo + linhas_pagamentos["cod_desconto"] = "0" + + # Tamanho do campo não pode se maior do que 10 + doc_number = str(self.document_number) + if len(doc_number) > 10: + start_point = len(self.document_number) - 10 + doc_number = doc_number[start_point : len(self.document_number)] + + linhas_pagamentos["numero"] = doc_number + + if self.discount_value: + linhas_pagamentos["cod_desconto"] = "1" + + def _prepare_bank_line_banco_brasil(self, payment_mode_id, linhas_pagamentos): + if ( + self.mov_instruction_code_id.code + == payment_mode_id.cnab_sending_code_id.code + ): + linhas_pagamentos["cod_primeira_instrucao"] = ( + payment_mode_id.boleto_protest_code or "00" + ) + + # Caso Santander 400 precisa enviar o Nosso Numero com DV isso não acontece no + # 240, por enquanto é o único caso mapeado. + # Houve um PR https://github.com/kivanio/brcobranca/pull/236 na lib buscando + # resolver isso e foi apontando a contradição em ter para esse mesmo banco no + # caso do 400 a necessidade de informar o DV mas não precisar no 240, + # mas o mantedor da biblioteca não aceito a alteração. + # A melhor solução talvez seja ver a possibilidade de incluir ou fazer algo + # semelhante ao git-aggregator https://github.com/acsone/git-aggregator + # na API e com isso incluir um commit de outro repositorio que faça essa + # simples alteração porém mantendo a API ligada diretamente ao repo pricipal + # do BRcobranca, já que não existe o interesse em manter um Fork e um simples + # commit resolve o problema, por enquanto o calculo esta sendo feito aqui, se + # necessário ou isso for útil para outros casos pode ser visto de migrar esse + # calculo do modulo11 para um lugar genereico e facilitar seu uso exemplo + # l10n_br_account_payment_order/tools.py + def modulo11(self, num, base=9, r=0): + soma = 0 + fator = 2 + for c in reversed(num): + soma += int(c) * fator + if fator == base: + fator = 1 + fator += 1 + if r == 0: + soma = soma * 10 + digito = soma % 11 + if digito == 10: + digito = 0 + return digito + if r == 1: + resto = soma % 11 + return resto + + def _prepare_bank_line_santander(self, payment_mode_id, linhas_pagamentos): + if payment_mode_id.payment_method_code == "400": + nosso_numero = linhas_pagamentos["nosso_numero"] + # O campo deve ter tamanho 7 caso a Sequencia não esteja configurada + # corretamente é tratado aqui, talvez deva ser feito na validação + if len(nosso_numero) > 7: + start_point = len(nosso_numero) - 7 + nosso_numero = nosso_numero[start_point : len(nosso_numero)] + + dv = self.modulo11(nosso_numero, 9, 0) + linhas_pagamentos["nosso_numero"] = str(nosso_numero) + str(dv) + + def prepare_bank_payment_line(self, bank_name_brcobranca): + payment_mode_id = self.order_id.payment_mode_id + linhas_pagamentos = self._prepare_boleto_line_vals() + try: + bank_method = getattr( + self, f"_prepare_bank_line_{bank_name_brcobranca.name}" + ) + if bank_method: + bank_method(payment_mode_id, linhas_pagamentos) + except Exception: + _logger.warning( + f"Error executing method _prepare_bank_line_{bank_name_brcobranca.name}." + "Check the bank name and provided parameters.", + exc_info=True, + ) + + # Cada Banco pode possuir seus Codigos de Instrução + if ( + self.mov_instruction_code_id.code + == payment_mode_id.cnab_sending_code_id.code + ): + if payment_mode_id.boleto_fee_perc: + linhas_pagamentos["codigo_multa"] = payment_mode_id.boleto_fee_code + linhas_pagamentos["percentual_multa"] = payment_mode_id.boleto_fee_perc + + if payment_mode_id.boleto_interest_perc: + linhas_pagamentos["tipo_mora"] = payment_mode_id.boleto_interest_code + # TODO - É padrão em todos os bancos ? + # Código adotado pela FEBRABAN para identificação do tipo de + # pagamento de mora de juros. + # Domínio: + # ‘1’ = Valor Diário (R$) + # ‘2’ = Taxa Mensal (%) + # ‘3’= Valor Mensal (R$) * + # ‘4’ = Taxa diária (%) + # ‘5’ = Isento + # *OBSERVAÇÃO: + # ‘3’ - Valor Mensal (R$): a CIP não acata valor mensal, + # segundo manual. Cógido mantido + # para Correspondentes que ainda utilizam. + # Isento de Mora caso não exista percentual + if payment_mode_id.boleto_interest_code == "1": + linhas_pagamentos["valor_mora"] = self.company_currency_id.round( + self.amount_currency + * ((payment_mode_id.boleto_interest_perc / 100) / 30), + ) + if payment_mode_id.boleto_interest_code == "2": + linhas_pagamentos[ + "valor_mora" + ] = payment_mode_id.boleto_interest_perc + + if self.discount_value: + linhas_pagamentos["data_desconto"] = self.date.strftime("%Y/%m/%d") + linhas_pagamentos["valor_desconto"] = self.discount_value + + # Protesto + if payment_mode_id.boleto_protest_code: + linhas_pagamentos[ + "codigo_protesto" + ] = payment_mode_id.boleto_protest_code + if payment_mode_id.boleto_days_protest: + linhas_pagamentos[ + "dias_protesto" + ] = payment_mode_id.boleto_days_protest + + return linhas_pagamentos diff --git a/l10n_br_account_payment_brcobranca/models/account_payment_mode.py b/l10n_br_account_payment_brcobranca/models/account_payment_mode.py new file mode 100644 index 000000000000..e37f3b18463e --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_payment_mode.py @@ -0,0 +1,22 @@ +# Copyright (C) 2012-Today - KMEE (). +# @author Luis Felipe Miléo - mileo@kmee.com.br +# @author Renato Lima - renato.lima@akretion.com.br +# Copyright (C) 2021-Today - Akretion (). +# @author Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class AccountPaymentMode(models.Model): + """ + Override Account Payment Mode + """ + + _inherit = "account.payment.mode" + + @api.model + def _selection_cnab_processor(self): + selection = super()._selection_cnab_processor() + selection.append(("brcobranca", "BRCobrança")) + return selection diff --git a/l10n_br_account_payment_brcobranca/models/account_payment_order.py b/l10n_br_account_payment_brcobranca/models/account_payment_order.py new file mode 100644 index 000000000000..3d9f66de8e80 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/models/account_payment_order.py @@ -0,0 +1,215 @@ +# Copyright 2020 Akretion +# @author Magno Costa +# Copyright 2020 KMEE +# @author Luis Felipe Mileo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import json +import logging +import tempfile + +import requests +from erpbrasil.base import misc + +from odoo import _, models +from odoo.exceptions import Warning as ValidationError + +from ..constants.br_cobranca import ( + DICT_BRCOBRANCA_CNAB_TYPE, + get_brcobranca_api_url, + get_brcobranca_bank, +) + +_logger = logging.getLogger(__name__) + + +class PaymentOrder(models.Model): + _inherit = "account.payment.order" + + def _prepare_remessa_banco_brasil(self, remessa_values, cnab_type): + remessa_values.update( + { + "convenio": int(self.payment_mode_id.cnab_company_bank_code), + "variacao_carteira": self.payment_mode_id.boleto_variation.zfill(3), + "convenio_lider": self.payment_mode_id.convention_code.zfill(7), + "carteira": str(self.payment_mode_id.boleto_wallet).zfill(2), + } + ) + + def _prepare_remessa_santander(self, remessa_values, cnab_type): + remessa_values.update( + { + "codigo_carteira": self.payment_mode_id.boleto_wallet_code_id.code, + "codigo_transmissao": self.payment_mode_id.cnab_company_bank_code, + "conta_corrente": misc.punctuation_rm( + self.journal_id.bank_account_id.acc_number + ), + } + ) + + def _prepare_remessa_caixa(self, remessa_values, cnab_type): + remessa_values.update( + { + "convenio": int(self.payment_mode_id.cnab_company_bank_code), + "digito_agencia": self.journal_id.bank_account_id.bra_number_dig, + } + ) + + def _prepare_remessa_ailos(self, remessa_values, cnab_type): + remessa_values.update( + { + "convenio": int(self.payment_mode_id.cnab_company_bank_code), + "digito_agencia": self.journal_id.bank_account_id.bra_number_dig, + } + ) + + def _prepare_remessa_unicred(self, remessa_values, cnab_type): + remessa_values["codigo_beneficiario"] = int( + self.payment_mode_id.cnab_company_bank_code + ) + + def _prepare_remessa_sicredi(self, remessa_values, cnab_type): + bank_account_id = self.journal_id.bank_account_id + remessa_values.update( + { + # Aparentemente a validação do BRCobranca nesse caso gera erro + # quando é feito o int(misc.punctuation_rm(bank_account_id.acc_number)) + "conta_corrente": misc.punctuation_rm(bank_account_id.acc_number), + "posto": self.payment_mode_id.boleto_post, + "byte_idt": self.payment_mode_id.boleto_byte_idt, + } + ) + + def _prepare_remessa_bradesco(self, remessa_values, cnab_type): + remessa_values["codigo_empresa"] = int( + self.payment_mode_id.cnab_company_bank_code + ) + + def generate_payment_file(self): + """Returns (payment file as string, filename)""" + self.ensure_one() + self.file_number = self.payment_mode_id.cnab_sequence_id.next_by_id() + + # see remessa fields here: + # https://github.com/kivanio/brcobranca/blob/master/lib/brcobranca/remessa/base.rb + # https://github.com/kivanio/brcobranca/tree/master/lib/brcobranca/remessa/cnab240 + # https://github.com/kivanio/brcobranca/tree/master/lib/brcobranca/remessa/cnab400 + # and a test here: + # https://github.com/kivanio/brcobranca/blob/master/spec/ + # brcobranca/remessa/cnab400/itau_spec.rb + + cnab_type = self.payment_mode_id.payment_method_code + + # Se não for um caso CNAB deve chamar o super + if ( + cnab_type not in ("240", "400", "500") + or self.payment_mode_id.cnab_processor != "brcobranca" + ): + return super().generate_payment_file() + + bank_account_id = self.journal_id.bank_account_id + bank_brcobranca = get_brcobranca_bank( + bank_account_id, self.payment_mode_id.payment_method_code + ) + + # Verificar campos que não podem ser usados no CNAB, já é + # feito ao criar um Modo de Pagamento, porém para evitar + # erros devido alterações e re-validado aqui + self.payment_mode_id._check_cnab_restriction() + + if cnab_type not in bank_brcobranca.remessa: + # Informa se o CNAB especifico de um Banco não está implementado + # no BRCobranca, evitando a mensagem de erro mais extensa da lib + raise ValidationError( + _( + "The CNAB %(cnab_type)s for Bank %(bank_name)s are not implemented " + "in BRCobranca.", + cnab_type=cnab_type, + bank_name=bank_account_id.bank_id.name, + ) + ) + + pagamentos = [] + for line in self.payment_line_ids: + pagamentos.append(line.prepare_bank_payment_line(bank_brcobranca)) + + remessa_values = { + "carteira": str(self.payment_mode_id.boleto_wallet), + "agencia": bank_account_id.bra_number, + "conta_corrente": int(misc.punctuation_rm(bank_account_id.acc_number)), + "digito_conta": bank_account_id.acc_number_dig[0], + "empresa_mae": bank_account_id.partner_id.legal_name[:30], + "documento_cedente": misc.punctuation_rm( + bank_account_id.partner_id.cnpj_cpf + ), + "pagamentos": pagamentos, + "sequencial_remessa": self.file_number, + } + + try: + bank_method = getattr(self, f"_prepare_remessa_{bank_brcobranca.name}") + if bank_method: + bank_method(remessa_values, cnab_type) + except Exception: + _logger.warning( + f"Error executing method _prepare_remessa_{bank_brcobranca.name}." + "Check the bank name and provided parameters.", + exc_info=True, + ) + + remessa = self._get_brcobranca_remessa( + bank_brcobranca, remessa_values, cnab_type + ) + + return remessa, self.get_file_name(cnab_type) + + def _get_brcobranca_remessa(self, bank_brcobranca, remessa_values, cnab_type): + content = json.dumps(remessa_values) + f = open(tempfile.mktemp(), "w") + f.write(content) + f.close() + files = {"data": open(f.name, "rb")} + + brcobranca_api_url = get_brcobranca_api_url(self.env) + # EX.: "http://boleto_cnab_api:9292/api/remessa" + brcobranca_service_url = brcobranca_api_url + "/api/remessa" + _logger.info( + "Connecting to %s to generate CNAB-REMESSA file for Payment Order %s", + brcobranca_service_url, + self.name, + ) + res = requests.post( + brcobranca_service_url, + data={ + "type": DICT_BRCOBRANCA_CNAB_TYPE[cnab_type], + "bank": bank_brcobranca.name, + }, + files=files, + timeout=60, + ) + + if cnab_type == "240" and "R01" in res.text[242:254]: + # Todos os header de lote cnab 240 tem conteúdo: R01, + # verificar observações G025 e G028 do manual cnab 240 febraban. + remessa = res.content + elif cnab_type == "400" and res.text[:3] in ("01R", "DCB"): + # A remessa 400 não tem um layout padronizado, + # entretanto a maiorias dos arquivos começa com 01REMESSA, + # o banco de brasilia começa com DCB... + # Dúvidas verificar exemplos: + # https://github.com/kivanio/brcobranca/tree/master/spec/fixtures/remessa + remessa = res.content + else: + raise ValidationError(res.text) + + return remessa + + def generated2uploaded(self): + result = super().generated2uploaded() + for payment_line in self.payment_line_ids: + # No caso de Cancelamento da Invoice a AML é apagada + if payment_line.move_line_id: + # Importante para saber a situação do CNAB no caso + # de um pagto feito por fora ( dinheiro, deposito, etc) + payment_line.move_line_id.cnab_state = "exported" + return result diff --git a/l10n_br_account_payment_brcobranca/parser/__init__.py b/l10n_br_account_payment_brcobranca/parser/__init__.py new file mode 100644 index 000000000000..303e466df86f --- /dev/null +++ b/l10n_br_account_payment_brcobranca/parser/__init__.py @@ -0,0 +1 @@ +from . import cnab_file_parser diff --git a/l10n_br_account_payment_brcobranca/parser/cnab_file_parser.py b/l10n_br_account_payment_brcobranca/parser/cnab_file_parser.py new file mode 100644 index 000000000000..7e7d5bc7cb8b --- /dev/null +++ b/l10n_br_account_payment_brcobranca/parser/cnab_file_parser.py @@ -0,0 +1,677 @@ +# @ 2020 Akretion - www.akretion.com.br - +# Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +import base64 +import datetime +import json +import logging + +import requests + +from odoo.exceptions import UserError + +from odoo.addons.account_move_base_import.parser.file_parser import FileParser + +from ..constants.br_cobranca import get_brcobranca_api_url + +logger = logging.getLogger(__name__) + +dict_brcobranca_bank = { + "001": "banco_brasil", + "041": "banrisul", + "085": "ailos", + "237": "bradesco", + "104": "caixa", + "399": "hsbc", + "341": "itau", + "033": "santander", + "748": "sicred", + "004": "banco_nordeste", + "021": "banestes", + "756": "sicoob", + "136": "unicred", +} + + +class CNABFileParser(FileParser): + """CNAB parser that use a define format in CNAB to import + bank statement. + """ + + def __init__(self, journal, *args, **kwargs): + # The name of the parser as it will be called + self.parser_name = journal.import_type + # The result as a list of row. One row per line of data in the file, + # but not the commission one! + self.result_row_list = None + # The file buffer on which to work on + self.filebuffer = None + # The profile record to access its parameters in any parser method + self.journal = journal + self.move_date = None + self.move_name = None + self.move_ref = None + self.support_multi_moves = None + self.commission_field = None + self.env = journal.env + self.bank = self.journal.bank_account_id.bank_id + self.cnab_return_events = [] + + @classmethod + def parser_for(cls, parser_name): + if parser_name == "cnab400": + return parser_name == "cnab400" + elif parser_name == "cnab240": + return parser_name == "cnab240" + + def parse(self, filebuffer): + files = {"data": base64.b64decode(filebuffer)} + + data = self._get_brcobranca_retorno(files) + + self.result_row_list = self.process_return_file(data) + + yield self.result_row_list + + def _get_brcobranca_retorno(self, files): + bank_name_brcobranca = dict_brcobranca_bank[self.bank.code_bc] + brcobranca_api_url = get_brcobranca_api_url(self.env) + # Ex.: "http://boleto_cnab_api:9292/api/retorno" + brcobranca_service_url = brcobranca_api_url + "/api/retorno" + logger.info( + "Connecting to %s to get CNAB-RETORNO of file name %s", + brcobranca_service_url, + self.env.context.get("file_name"), + ) + res = requests.post( + brcobranca_service_url, + data={ + "type": self.journal.import_type, + "bank": bank_name_brcobranca, + }, + files=files, + timeout=60, + ) + + if res.status_code != 201: + raise UserError(res.text) + + string_result = res.json() + data = json.loads(string_result) + + return data + + def _get_date_format(self, bank_name_brcobranca): + # TODO: Idealmente o JSON de Retorno do BRCobranca deveria vir + # padronizado para não ser necessário ser feito esse tratamento aqui + if bank_name_brcobranca == "ailos": + # No Banco AILOS o formato da Data é completo com os 4 digitos. + zeros_date = "00000000" + date_format = "%d%m%Y" + else: + # Outros Bancos mapeados é apenas 2 digitos. + zeros_date = "000000" + date_format = "%d%m%y" + + return zeros_date, date_format + + def process_return_file(self, data): + # Forma de Lançamento do Retorno + # Em caso de Pagamento/Liquidação é feita a criação de uma Entrada de + # Diário para cada linha do arquivo CNAB com os valores de desconto, + # juros/mora, tarifa bancaria, abatimento, valor total + # + # Quando marcada a opção de Reconciliação Automatica no Diário + # a Fatura será Reconciliada e a Entrada de Diário será movida + # para o status Lançado + + # Valor Recebido diferente do Valor no Odoo + # Para que a Fatura/Nota Fiscal no Odoo seja completamente reconciliada + # e o seu status seja alterado de Aberto para Pago é preciso que + # a soma dos lançamentos(account.move.line) criados sejam iguais ao + # valor da account_move_line em aberto. + # + # Valor Menor + # Os valores de Desconto e Abatimento estão sendo adicionados no + # lançamento referente ao pagamento para que o valor total fique + # igual, exemplo: + # Odoo Valores arquivo CNAB + # Valor Odoo | Valor Recebido | Valor Abatimento |Valor Desconto + # 100 | 80 | 10 | 10 + # + # O Valor Recebido a ser lançado será 100. + # + # Caso o valor ainda seja menor nada pode ser feito aqui, pois + # significa que o cliente pagou um valor menor sem relação com o + # Abatimento e ou Desconto e que ainda está em Aberto junto ao banco. + # TODO: Existe a possibilidade de Pagar um valor menor junto ao banco ? + # Se for preciso Baixar esse valor o processo deverá ser utilizar o + # wizard de atualizações do CNAB, na account.move.line referente, + # pedindo a Baixa do Título o que irá gerar um nova Linha/Instrução + # CNAB a ser enviada ao Banco. + # + # Valor Maior + # Caso comum onde o devido o valor de Juros Mora/Multa faz com que + # os valores fiquem diferentes, exemplo: + # Odoo Valores arquivo CNAB + # Valor Odoo | Valor Recebido | Juros Mora + Multa* + # 100 | 110 | 10 + # + # O Valor Recebido a ser lançado será 100. + # *valores vem somados no CNAB Unicred 400, seria um padrão ? + # + # Não é possível relacionar esse lançamento contabil diretamente isso + # causa erro, seria preciso "Cancelar o Lançamento" da account.move( + # referente a invoice que gerou o CNAB) é criar uma nova linha + # assim aumentando o valor original da Fatura, na primeira linha que + # fosse recebida esse processo até poderia funcionar mas no caso de uma + # segunda, terceira, etc acredito que o programa já não permitiria mais + # Cancelar o Lançamento existindo reconciliações parciais. + # Por isso Nesse caso é preciso alterar o Valor Recebido + # ( Valor Recebido - Valor Juros Mora/Multa ) + # TODO: Deveria existir uma forma de mostrar o Valor de Juros/Multa na + # tela da Fatura/Invoice, e assim o usuário poder visualizar isso ? + # Porque não vai existir um relacionamento direto de conciliação, + # apenas a referencia no bank_payment_line_id da account.move.line, + # e caso se queira saber os detalhes será preciso olhar a Entrada de + # Diário referente. + + # Lista com os dados q poderão ser usados + # na criação das account move line + result_row_list = [] + + bank_name_brcobranca = dict_brcobranca_bank[self.bank.code_bc] + + if bank_name_brcobranca == "ailos": + # No AILOS o código de registro onde ficam as linhas CNAB é o 3. + registration_code_allowed = 3 + elif bank_name_brcobranca == "banco_brasil": + # No Banco do Brasil o código do registro principal é o 7. + # existem registros opcionais porém como não estão mapeados no BRCobrança + # e serão ignorados aqui. Teoricamente a verificação do código do registro + # nem deveria se feita aqui, cada dict retornado da lib era pra representar + # um registro completo do boleto. Esse tratamento deveria estar lá. + registration_code_allowed = 7 + else: + registration_code_allowed = 1 + + for linha_cnab in data: + if int(linha_cnab["codigo_registro"]) != registration_code_allowed: + # Bradesco + # Existe o codigo de registro 9 que eh um totalizador + # porem os campos estao colocados em outras posicoes + # que nao estao mapeadas no BRCobranca + # Itau + # 9 - Registro Trailer do Arquivo + # 4 e 5 - Registro de Detalhe (Opcional) + # continue + continue + + valor_titulo = self.cnab_str_to_float(linha_cnab["valor_titulo"]) + + zeros_date, date_format = self._get_date_format(bank_name_brcobranca) + + # Idealmente o campo data_ocorrencia deve vir mapeado no JSON + if ( + linha_cnab.get("data_ocorrencia") + and linha_cnab.get("data_ocorrencia") != zeros_date + ): + data_ocorrencia = datetime.datetime.strptime( + str(linha_cnab.get("data_ocorrencia")), date_format + ).date() + elif ( + linha_cnab.get("data_credito") + and linha_cnab.get("data_credito") != zeros_date + ): + # Tenta usar a data de credito como refererencia, + # se isso ocorre em uma caso especifico é algo a ser verificado + # no BRCobranca se é possível mapear o campo data_ocorrencia + data_ocorrencia = datetime.datetime.strptime( + str(linha_cnab.get("data_credito")), date_format + ).date() + else: + # Nada encontrado usa Hoje, teria mais algum campo que poderia + # ser usado? + data_ocorrencia = datetime.date.today() + + cod_ocorrencia = str(linha_cnab["codigo_ocorrencia"]) + # Cada Banco pode possuir um Codigo de Ocorrencia distinto, + # mesmo no caso do 240, ver Unicred na pasta de dados do + # l10n_br_account_payment_order + payment_method_cnab = self.env["account.payment.method"].search( + [("payment_type", "=", "inbound"), ("code", "=", self.parser_name[4:7])] + ) + + descricao_ocorrencia = self._get_description_occurrence( + payment_method_cnab, cod_ocorrencia + ) + + # Nosso numero vem com o Digito Verificador + # ex.: 00000000000002010 + + # Com exceção no itaú(341) que já vem sem o dígito verificador. + if self.bank.code_bc == "341": + nosso_numero_sem_dig = linha_cnab["nosso_numero"] + elif bank_name_brcobranca == "ailos": + # no AILOS o nosso número vem concatenado com o número da conta + # porém o que importa aqui é apenas os últimos 9 digitos que é + # de fato a sequência númerica. + nosso_numero_sem_dig = linha_cnab["nosso_numero"][-9:] + elif bank_name_brcobranca == "banco_brasil": + # no banco do brasil o nosso numero vem concatenado com o código de + # convênio, sendo apenas os últimos 10 dígitos a sequencia do nosso + # número usado para procurar o move line. + nosso_numero_sem_dig = linha_cnab["nosso_numero"][-10:] + else: + nosso_numero_sem_dig = linha_cnab["nosso_numero"][:-1] + + # No arquivo de retorno do CNAB o campo pode ter um tamanho + # diferente, o tamanho do campo é preenchido na totalidade + # com zeros a esquerda, e no odoo o tamanho do sequencial pode + # estar diferente + # ex.: retorno cnab 0000000000000201 own_number 0000000201 + # + # O campo own_number_without_zfill foi a forma que encontrei + # para poder fazer um search o nosso_numero_cnab_retorno.lstrip("0") e + # ter algo: + # ex.: + # arquivo retorno cnab 201 own_number_without_zfill 201 + # + # É usado o lstrip() para manter os zeros a direita, exemplo: + # VALOR '0000000090' + # | strip | rstrip | lstrip | 9 000000009 90 + # Valor '00000000201' + # | strip | rstrip | lstrip | 201 00000000201 201 + + nosso_numero_sem_zeros = nosso_numero_sem_dig.lstrip("0") + + # Podem existir sequencias do nosso numero/own_number iguais entre + # bancos diferentes, porém os Diario/account.journal + # não pode ser o mesmo. + + account_move_line = self.env["account.move.line"].search( + [ + ("own_number_without_zfill", "=", nosso_numero_sem_zeros), + ("journal_payment_mode_id", "=", self.journal.id), + ] + ) + + # Linha não encontrada + if not account_move_line: + self.cnab_return_events.append( + { + "occurrences": descricao_ocorrencia, + "occurrence_date": data_ocorrencia, + "str_motiv_a": " * - BOLETO NÃO ENCONTRADO.", + "own_number": linha_cnab["nosso_numero"], + "your_number": linha_cnab["documento_numero"], + "title_value": valor_titulo, + } + ) + continue + + payment_lines = self.env["account.payment.line"].search( + [ + ("move_line_id", "=", account_move_line.id), + ("state", "not in", ["cancel", "draft"]), + ], + ) + + # Codigos de Movimento de Retorno - Liquidação + cnab_liq_move_code = [] + for ( + move_code + ) in account_move_line.payment_mode_id.cnab_liq_return_move_code_ids: + cnab_liq_move_code.append(move_code.code) + + favored_bank_account = ( + account_move_line.payment_mode_id.fixed_journal_id.bank_account_id + ) + + due_date = False + # as vezes o vencimento pode ser branco + if ( + linha_cnab.get("data_vencimento") + and linha_cnab.get("data_vencimento") != zeros_date + ): + due_date = datetime.datetime.strptime( + str(linha_cnab.get("data_vencimento")), date_format + ).date() + + cnab_return_log_event = { + "occurrences": descricao_ocorrencia, + "occurrence_date": data_ocorrencia, + "own_number": account_move_line.own_number, + "your_number": account_move_line.document_number, + "title_value": valor_titulo, + "payment_line_ids": payment_lines.ids, + "invoice_id": account_move_line.move_id.id, + "due_date": due_date, + "move_line_id": account_move_line.id, + "company_title_identification": linha_cnab["documento_numero"] + or account_move_line.document_number, + "favored_bank_account_id": favored_bank_account.id, + # TODO: Campo Segmento é referente ao CNAB 240, o + # BRCobranca parece não informar esse campo no retorno, + # é preciso validar isso nesse caso. + # 'segmento': evento.servico_segmento, + # 'favorecido_nome': + # obj_account_move_line.company_id.partner_id.name, + # 'tipo_moeda': evento.credito_moeda_tipo, + } + + # Caso de Pagamento deve criar os Lançamentos de Diário + if cod_ocorrencia in cnab_liq_move_code: + row_list, log_event_payment = self._get_accounting_entries( + linha_cnab, account_move_line, payment_lines + ) + result_row_list.append(row_list) + cnab_return_log_event.update(log_event_payment) + else: + # Nos codigos de retorno cadastrados no Data do modulo + # l10n_br_account_payment_order o 02 se refere a + # Entrada Confirmada e 03 Entrada Rejeitada. + # TODO: Estou considerando que seja um padrão, existem + # exceções ? + # Caso exista será preciso criar o campo no payment.mode + # para informa-lo como nos outros casos. + if cod_ocorrencia == "02": + account_move_line.cnab_state = "accepted" + elif cod_ocorrencia == "03": + # TODO - algo a mais a ser feito ? + account_move_line.cnab_state = "not_accepted" + + # Inclui o LOG do Evento CNAB + self.cnab_return_events.append(cnab_return_log_event) + + return result_row_list + + def _get_description_occurrence(self, payment_method_cnab, cod_ocorrencia): + cnab_return_move_code = self.env["l10n_br_cnab.return.move.code"].search( + [ + ("bank_ids", "in", self.bank.id), + ("payment_method_ids", "in", payment_method_cnab.id), + ("code", "=", cod_ocorrencia), + ] + ) + if cnab_return_move_code: + descricao_ocorrencia = cod_ocorrencia + "-" + cnab_return_move_code.name + else: + descricao_ocorrencia = ( + cod_ocorrencia + "-" + "CÓDIGO DA DESCRIÇÃO NÃO ENCONTRADO" + ) + + return descricao_ocorrencia + + def _get_accounting_entries(self, linha_cnab, account_move_line, payment_lines): + row_list = [] + bank_name_brcobranca = dict_brcobranca_bank[self.bank.code_bc] + valor_recebido = ( + valor_desconto + ) = valor_juros_mora = valor_abatimento = valor_tarifa = 0.0 + + if linha_cnab["valor_recebido"]: + # Campo Valor Recebido vem com o Valor da Tarifa: + # valor recebido = valor pago + valor da tarifa + valor_recebido = self.cnab_str_to_float(linha_cnab["valor_recebido"]) + + zeros_date, date_format = self._get_date_format(bank_name_brcobranca) + + if linha_cnab["data_credito"] == zeros_date or not linha_cnab["data_credito"]: + data_credito = linha_cnab["data_credito"] + else: + data_credito = datetime.datetime.strptime( + str(linha_cnab["data_credito"]), date_format + ).date() + + # Na própria lib o desconto é tratado com duas keys diferentes + # dependendo do banco e do formato. Também há um erro de escrita que foi tratado + # aqui porque uma alteração da lib poderia quebrar outras implementações. + desconto_linha = linha_cnab.get("desconto") or linha_cnab.get( + "desconto_concedito" + ) + if desconto_linha: + valor_desconto = self.cnab_str_to_float(desconto_linha) + if valor_desconto > 0.0: + row_list.append( + { + "name": "Desconto (boleto) " + + account_move_line.document_number, + "debit": valor_desconto, + "credit": 0.0, + "account_id": ( + account_move_line.payment_mode_id.discount_account_id.id + ), + "type": "desconto", + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + row_list.append( + { + "name": "Desconto (boleto) " + + account_move_line.document_number, + "debit": 0.0, + "credit": valor_desconto, + "type": "desconto", + "account_id": self.journal.default_account_id.id, + "partner_id": account_move_line.partner_id.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + # Valor Juros Mora - valor de mora e multa pagos pelo sacado + if linha_cnab.get("juros_mora"): + valor_juros_mora = self.cnab_str_to_float(linha_cnab["juros_mora"]) + + if valor_juros_mora > 0.0: + row_list.append( + { + "name": "Valor Juros Mora (boleto) " + + account_move_line.document_number, + "debit": 0.0, + "credit": valor_juros_mora, + "type": "juros_mora", + "account_id": ( + account_move_line.payment_mode_id.interest_fee_account_id.id + ), + "partner_id": account_move_line.partner_id.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + row_list.append( + { + "name": "Valor Juros Mora (boleto) " + + account_move_line.document_number, + "debit": valor_juros_mora, + "credit": 0.0, + "account_id": self.journal.default_account_id.id, + "journal_id": account_move_line.journal_id.id, + "type": "juros_mora", + "partner_id": account_move_line.partner_id.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + # Valor Tarifa + if linha_cnab.get("valor_tarifa"): + valor_tarifa = self.cnab_str_to_float(linha_cnab["valor_tarifa"]) + + if valor_tarifa > 0.0: + # Usado para Conciliar a Fatura + row_list.append( + { + "name": "Tarifas bancárias (boleto) " + + account_move_line.document_number, + "debit": 0.0, + "credit": valor_tarifa, + "account_id": self.journal.default_account_id.id, + "type": "tarifa", + "partner_id": account_move_line.company_id.partner_id.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + # Avoid error in pre commit + tariff_charge_account = ( + account_move_line.payment_mode_id.tariff_charge_account_id + ) + row_list.append( + { + "name": "Tarifas bancárias (boleto) " + + account_move_line.document_number, + "debit": valor_tarifa, + "credit": 0.0, + "type": "tarifa", + "account_id": tariff_charge_account.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + # Valor Abatimento + if linha_cnab.get("valor_abatimento"): + valor_abatimento = self.cnab_str_to_float(linha_cnab["valor_abatimento"]) + + if valor_abatimento: + row_list.append( + { + "name": "Abatimento (boleto) " + + account_move_line.document_number, + "debit": valor_abatimento, + "credit": 0.0, + "account_id": ( + account_move_line.payment_mode_id.rebate_account_id.id + ), + "type": "abatimento", + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + row_list.append( + { + "name": "Abatimento (boleto) " + + account_move_line.document_number, + "debit": 0.0, + "credit": valor_abatimento, + "type": "abatimento", + "account_id": self.journal.default_account_id.id, + "partner_id": account_move_line.partner_id.id, + "payment_line_ids": payment_lines.ids, + "cnab_returned_ref": account_move_line.document_number, + } + ) + + # Linha da Fatura a ser reconciliada com o Pagamento em Aberto, + # necessário atualizar o Valor Recebido pois o Odoo não + # aceita a conciliação nem com um Valor Menor ou Maior. + valor_recebido_calculado = ( + valor_recebido + valor_desconto + valor_abatimento + ) - valor_juros_mora + + # No itaú(341) o valor recebido (valor principal) já vem com a tarifa descontada + # precisamos atualizar o valor recebido para que a reconcialiação feche. + if self.bank.code_bc == "341": + valor_recebido_calculado += valor_tarifa + + row_list.append( + { + "name": account_move_line.move_id.name, + "debit": 0.0, + "credit": valor_recebido_calculado, + "move_line": account_move_line, + "type": "liquidado", + "payment_line_ids": payment_lines.ids, + "account_id": account_move_line.account_id.id, + "partner_id": account_move_line.partner_id.id, + "date": data_credito, + "cnab_returned_ref": account_move_line.own_number, + } + ) + + # CNAB LOG + log_event_payment = { + "real_payment_date": data_credito.strftime("%Y-%m-%d"), + "payment_value": valor_recebido, + "discount_value": valor_desconto, + "interest_fee_value": valor_juros_mora, + "rebate_value": valor_abatimento, + "tariff_charge": valor_tarifa, + } + + return row_list, log_event_payment + + def cnab_str_to_float(self, value): + # Até onde vi independente do tamanho do campo os + # 2 ultimos caracteres se referem ao decimal + decimal_point = len(value) - 2 + value_float = float(str(value[0:decimal_point] + "." + value[decimal_point:])) + return value_float + + def get_move_vals(self): + """This method return a dict of vals that ca be passed to create method + of statement. + :return: dict of vals that represent additional infos for the statement + """ + return { + # O campo name precisa ser como abaixo ou não ser enviado + # se não gera erro no metodo _check_unique_sequence_number, + # na v12 estava indo nesse campo a informação que agora está + # no campo ref + # "name": self.move_name or "/", + # TODO: Precisa de migração? + "ref": "Retorno CNAB - Banco " + + self.bank.short_name + + " - Conta " + + self.journal.bank_account_id.acc_number, + "is_cnab": True, + } + + def get_move_line_vals(self, line, *args, **kwargs): + """This method must return a dict of vals that can be passed to create + method of statement line in order to record it. It is the + responsibility of every parser to give this dict of vals, so each one + can implement his own way of recording the lines. + :param: line: a dict of vals that represent a line of + result_row_list + :return: dict of values to give to the create method of statement + line, it MUST contain at least: + { + 'name':value, + 'date':value, + 'amount':value, + 'ref':value, + 'label':value, + 'commission_amount':value, + } + """ + vals = { + "name": line["name"] or line.get("source"), + "credit": line["credit"], + "debit": line["debit"], + "partner_id": None, + "account_id": line["account_id"], + "already_completed": True, + "payment_line_ids": line["payment_line_ids"], + "cnab_returned_ref": line["cnab_returned_ref"], + } + if ( + line["type"] + in ("liquidado", "tarifa", "juros_mora", "desconto", "abatimento") + and line["credit"] > 0.0 + ): + vals.update( + { + "partner_id": line["partner_id"], + } + ) + + return vals diff --git a/l10n_br_account_payment_brcobranca/readme/CONFIGURE.rst b/l10n_br_account_payment_brcobranca/readme/CONFIGURE.rst new file mode 100644 index 000000000000..f175ca936fb5 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/CONFIGURE.rst @@ -0,0 +1,26 @@ +**Português** +Para configurar esse modulo é preciso: + +* Rodar a biblioteca BRCobranca como um micro-serviço https://github.com/akretion/boleto_cnab_api . +* Informar a variável de ambiente **BRCOBRANCA_API_URL** no arquivo de configuração do Odoo ou se estiver usando o docky na seção enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , exemplo: + **BRCOBRANCA_API_URL=http://boleto_cnab_api:9292** +* Verifique se os Códigos de Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Instrução do Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml . +* Verifique se os Códigos de Retorno do Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Retorno de Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml . +* Criar a Conta Bancária referente ao CNAB em Faturamento > Configurações > Contabilidade > Contas Bancárias . +* Automaticamente será criado um Diário Contábil referente a conta bancária em Faturamento > Configurações > Contabilidade > Diários na aba **Informações Referentes a Importação** informe as configurações de Retorno do CNAB nos campos "Tipo de Importação", "Conta de Recebimento/Pagamento", "Criação de Contra-Partida" e se deve ser feita a reconciliação automática ao importar o arquivo em "Reconciliar Automaticamente o Retorno de Pagamento". +* Em Faturamento > Configurações > Administração > Modos de Pagamento criar um Modo de Pagamento com as informações do CNAB, no campo "Diário de Banco Fixo" informar o Diário Contábil da conta bancária e se for o caso, e é recomendado, marcar a opção "Adicionar automaticamente ao validar a fatura" para não ser preciso fazer manualmente. +* Caso o CNAB e Banco escolhidos possua um campo especifico que seja preciso implementar considere fazer um PR no modulo l10n_br_account_payment_order aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/models/l10n_br_cnab_boleto_fields.py#L307 . +* Configure as permissões de acesso dos usuários, as opções são CNAB "Usuário" e "Gerente". + +**English** +To configure this module, you need to: + +* Run BRCobranca as micro-service https://github.com/akretion/boleto_cnab_api. +* Inform the envoriment variable BRCOBRANCA_API_URL in the config odoo file or if are use docky in the section enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , example: + **BRCOBRANCA_API_URL=http://boleto_cnab_api:9292** +* Check if the CNAB Instruction Movement Code to be use exist in Invoicing > Configuration > Management > CNAB Movement Instruction Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml . +* Check if the CNAB Return Move Code to be use exist in Invoicing > Configuration > Management > CNAB Return Move Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml . +* Create an Bank Account referent of CNAB in Invoicing > Configuration > Accounting > Bank Accounts . +* Automatic will be create an Account Journal refer to bank account in Invoicing > Configuration > Accounting > Journals in tab **Import related infos** inform parameters of CNAB Return in fields "Type of Import", "Receivable/Payable Account", "Create Counterpart", and if should make automatic reconciliation when import the file in "Automatic Reconcile payment returns". +* In Invoicing > Configuration > Management > Payment Modes create an Payment Mode with CNAB information, in the field "Fixed Bank Journal" inform the Account Journal of bank account and mark if "Automatically add when validating the invoice" so that you don't have to do it manually. +* Configure user access permissions, CNAB options are "User" and "Manager". diff --git a/l10n_br_account_payment_brcobranca/readme/CONTRIBUTORS.rst b/l10n_br_account_payment_brcobranca/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..bb083725a3ab --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/CONTRIBUTORS.rst @@ -0,0 +1,6 @@ +* `Akretion `_: + * Raphaël Valyi + * Magno Costa + +* `Engenere `_: + * Antônio S. Pereira Neto diff --git a/l10n_br_account_payment_brcobranca/readme/CREDITS.rst b/l10n_br_account_payment_brcobranca/readme/CREDITS.rst new file mode 100644 index 000000000000..0883adf37cc5 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/CREDITS.rst @@ -0,0 +1,3 @@ +The development of this module has been financially supported by: + +* AKRETION LTDA - https://akretion.com/pt-BR diff --git a/l10n_br_account_payment_brcobranca/readme/DESCRIPTION.rst b/l10n_br_account_payment_brcobranca/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..51481e7a5e5f --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +**Português** +Esse modulo implementa o CNAB usando a biblioteca BRCobranca +https://github.com/kivanio/brcobranca . + +**English** +This module implement brazilian bank splips('Boletos Bancarios') by using +BRCobranca(https://github.com/kivanio/brcobranca). diff --git a/l10n_br_account_payment_brcobranca/readme/HISTORY.rst b/l10n_br_account_payment_brcobranca/readme/HISTORY.rst new file mode 100644 index 000000000000..75d8458d8c94 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/HISTORY.rst @@ -0,0 +1,31 @@ +14.0.1.0.0 (2022-05-26) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration + +12.0.1.0.0 (2021-05-07) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Finish migration +* [IMP] Integrate with module account_move_base_import used to import CNAB file +* [IMP] Make possible automatic reconciliation and register the values of Fees, Tariff Bank, Rebate in configured accounts. + +12.0.1.0.0 (2020-06-12) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Start Migration + +10.0.1.0.0 (2019-05-30) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration + +8.0.1.0.0 (2018-01-29) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [REF] Maked functional to print Boleto, create CNAB file and import CNAB as Extrat Bank the user should be resolved manully the divergences between the values( Fee, Tariff Bank, Rebate, etc). + +8.0.1.0.0 (2017-07-01) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [NEW] First version diff --git a/l10n_br_account_payment_brcobranca/readme/INSTALL.rst b/l10n_br_account_payment_brcobranca/readme/INSTALL.rst new file mode 100644 index 000000000000..93ba92f18ba0 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/INSTALL.rst @@ -0,0 +1,11 @@ +**Português** +O modulo depende do: + +* l10n_br_account_payment_order +* account_move_base_import + +**English** +This module depends on: + +* l10n_br_account_payment_order +* account_move_base_import diff --git a/l10n_br_account_payment_brcobranca/readme/ROADMAP.rst b/l10n_br_account_payment_brcobranca/readme/ROADMAP.rst new file mode 100644 index 000000000000..f30d73c0b9f8 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/ROADMAP.rst @@ -0,0 +1 @@ +* Incluir a posssibilidade de imprimir o boleto no menu Imprimir da Fatura, na v12 aparentemente não é possível chamar um metodo apenas um QWeb, verificar na migração para outras versões. diff --git a/l10n_br_account_payment_brcobranca/readme/USAGE.rst b/l10n_br_account_payment_brcobranca/readme/USAGE.rst new file mode 100644 index 000000000000..a0947639aebd --- /dev/null +++ b/l10n_br_account_payment_brcobranca/readme/USAGE.rst @@ -0,0 +1,23 @@ +**Português** + +* Ao criar e Confirmar uma Fatura que tem um Modo de Pagamento que seja CNAB deverá aparecer o botão de "Imprimir Boleto". +* Caso esteja marcado no Modo de Pagamento a opção de "Adicionar automaticamente ao validar a fatura" será criada ou adicionada em uma Ordem de Pagamento as linhas de pagamentos do CNAB, se a opção não estiver marcada será preciso fazer isso manualmente podendo ser feito tanto na Fatura quanto na Ordem de Pagamento. +* Ao Confirmar essa Ordem de Pagamento será possível gerar o arquivo de Remessa CNAB a ser enviado ao Banco, é importante confirmar o envio do arquivo alterando o status da ordem para "Arquivo Enviado", essa informação é usada para validar se existe uma instrução CNAB pendente antes de se poder criar outra. +* Alterações de CNAB como Alteração da Data de Vencimento, Protesto, Conceder Abatimento e etc podem ser feitas na própria Fatura em Faturamento > Clientes > Faturas na aba Recebimentos na última coluna existe o botão "Atualizar Informação CNAB" ao clicar em uma linha essa opção também aparece, ao fazer uma alteração é criada ou adicionada em uma Ordem de Pagamento a Instrução de Movimento CNAB selecionada. +* A importação do arquivo CNAB de Retorno pode ser feita em Pagamentos > Importar arquivo Batch ou no próprio Diário em Faturamento > Configurações > Contabilidade > Diários na aba **Informações Referentes a Importação** o botão Importar arquivo Batch. +* Toda importação de arquivo de retorno cria uma LOG que pode ser consultado em Pagamentos > LOG de Retorno CNAB. +* Caso o Código de Retorno CNAB recebido seja um dos "Códigos de Liquidação do Retorno do Movimento" do Modo de Pagamento será criado uma Entrada de Diário com os valores quando existirem de desconto, juros/mora, tarifa bancaria, abatimento e valor a ser reconciliado com a linha da Fatura referente, os lançamentos são separados de acordo com as Contas Contabéis definidas no Modo de Pagamento, a linha para reconciliar a linha da Fatura precisam ser iguais por isso o valor é: + valor_recebido_calculado = (valor_recebido + valor_desconto + valor_abatimento) - valor_juros_mora +* Quando marcada a opção de "Reconciliação Automatica" /a Entrada de Diário será movida para o status Lançado automaticamente ao importar o arquivo, se não estiver marcada isso deverá ser feito manualmente. + +**English** + +* When creating and confirming an Invoice that has a Payment Mode that is CNAB, the button should appear "Print Boleto". +* If the option to "Add automatically when validating the invoice" is marked in the Payment Mode CNAB payment lines will be created or added to a Payment Order, if the option is not marked, you will need to do this manually, which can be done both in the Invoice and in the Payment Order. +* By confirming this Payment Order it will be possible to generate the CNAB Remessa file to be sent to the Bank, it is important to confirm the upload of the file by changing the order status to "File Uploaded", this information is used to validate if there is a pending CNAB instruction before another one can be created. +* CNAB changes such as Change Due Date, Protest, Grant Rebate, etc. can be made in the Invoice itself in Invoicing > Customers > Invoices in the Receivable tab in the last column there is the button "Update CNAB Information" when clicking on a line this option also appears, when making a change it is created or added to a Payment Order the selected CNAB Movement Instruction. +* The import of the Return CNAB file can be done in Payments > Import Batch file or in the same Journal in Invoicing > Configuration > Accounting > Journals in the tab **Import related infos** the Import Batch File button. +* Every return file import creates a LOG that can be consulted in Payments > CNAB Return LOG. +* If the CNAB Return Code received is one of the "CNAB Liquidity Return Move Code" of the Payment Mode, a Journal Entry will be created with the values when there are discount, interest, tariff charge, rebate and amount to be reconciled with the referring Invoice line, entries are separated according to the Accounts defined in the Payment Mode, the line to reconcile the Invoice line need be equal so the value is: + calculated_value_receive = (receive_amount + discount_amount + rebate_amount) - interest_amount +* When the "Automatic Reconciliation" option is checked, the Entry of Journal will be moved to the status Posted automatically when importing the file, if not checked it should be done manually. diff --git a/l10n_br_account_payment_brcobranca/security/ir.model.access.csv b/l10n_br_account_payment_brcobranca/security/ir.model.access.csv new file mode 100644 index 000000000000..4ac741816e45 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/security/ir.model.access.csv @@ -0,0 +1,4 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +access_account_reconcile_cnab_user,access_account_reconcile_cnab_user,account.model_account_reconcile_model,l10n_br_account_payment_order.group_cnab_user,1,1,1,0 +access_account_reconcile_cnab_manager,access_account_reconcile_cnab_manager,account.model_account_reconcile_model,l10n_br_account_payment_order.group_cnab_manager,1,1,1,1 +access_account_journal_cnab_user,account.journal,model_account_journal,l10n_br_account_payment_order.group_cnab_user,1,1,1,0 diff --git a/l10n_br_account_payment_brcobranca/static/description/icon.png b/l10n_br_account_payment_brcobranca/static/description/icon.png new file mode 100644 index 000000000000..902f656602f8 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/static/description/icon.png differ diff --git a/l10n_br_account_payment_brcobranca/static/description/index.html b/l10n_br_account_payment_brcobranca/static/description/index.html new file mode 100644 index 000000000000..ca6b117c608b --- /dev/null +++ b/l10n_br_account_payment_brcobranca/static/description/index.html @@ -0,0 +1,574 @@ + + + + + +L10n Br Account Payment BRCobranca + + + +
+

L10n Br Account Payment BRCobranca

+ + +

Beta License: AGPL-3 OCA/l10n-brazil Translate me on Weblate Try me on Runboat

+

Português +Esse modulo implementa o CNAB usando a biblioteca BRCobranca +https://github.com/kivanio/brcobranca .

+

English +This module implement brazilian bank splips(‘Boletos Bancarios’) by using +BRCobranca(https://github.com/kivanio/brcobranca).

+

Table of contents

+ +
+

Installation

+

Português +O modulo depende do:

+
    +
  • l10n_br_account_payment_order
  • +
  • account_move_base_import
  • +
+

English +This module depends on:

+
    +
  • l10n_br_account_payment_order
  • +
  • account_move_base_import
  • +
+
+
+

Configuration

+

Português +Para configurar esse modulo é preciso:

+
    +
  • Rodar a biblioteca BRCobranca como um micro-serviço https://github.com/akretion/boleto_cnab_api .
  • +
  • Informar a variável de ambiente BRCOBRANCA_API_URL no arquivo de configuração do Odoo ou se estiver usando o docky na seção enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , exemplo: +BRCOBRANCA_API_URL=http://boleto_cnab_api:9292
  • +
  • Verifique se os Códigos de Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Instrução do Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml .
  • +
  • Verifique se os Códigos de Retorno do Movimento do CNAB a ser usado existem em Faturamento > Configurações > Administração > Códigos de Retorno de Movimento CNAB, se for necessário criar considere fazer um PR para adicionar como dados aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml .
  • +
  • Criar a Conta Bancária referente ao CNAB em Faturamento > Configurações > Contabilidade > Contas Bancárias .
  • +
  • Automaticamente será criado um Diário Contábil referente a conta bancária em Faturamento > Configurações > Contabilidade > Diários na aba Informações Referentes a Importação informe as configurações de Retorno do CNAB nos campos “Tipo de Importação”, “Conta de Recebimento/Pagamento”, “Criação de Contra-Partida” e se deve ser feita a reconciliação automática ao importar o arquivo em “Reconciliar Automaticamente o Retorno de Pagamento”.
  • +
  • Em Faturamento > Configurações > Administração > Modos de Pagamento criar um Modo de Pagamento com as informações do CNAB, no campo “Diário de Banco Fixo” informar o Diário Contábil da conta bancária e se for o caso, e é recomendado, marcar a opção “Adicionar automaticamente ao validar a fatura” para não ser preciso fazer manualmente.
  • +
  • Caso o CNAB e Banco escolhidos possua um campo especifico que seja preciso implementar considere fazer um PR no modulo l10n_br_account_payment_order aqui https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/models/l10n_br_cnab_boleto_fields.py#L307 .
  • +
  • Configure as permissões de acesso dos usuários, as opções são CNAB “Usuário” e “Gerente”.
  • +
+

English +To configure this module, you need to:

+
    +
  • Run BRCobranca as micro-service https://github.com/akretion/boleto_cnab_api.
  • +
  • Inform the envoriment variable BRCOBRANCA_API_URL in the config odoo file or if are use docky in the section enviroment https://github.com/akretion/docky-odoo-brasil/blob/12.0/docker-compose.yml#L3 , example: +BRCOBRANCA_API_URL=http://boleto_cnab_api:9292
  • +
  • Check if the CNAB Instruction Movement Code to be use exist in Invoicing > Configuration > Management > CNAB Movement Instruction Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_mov_instruction_code_data.xml .
  • +
  • Check if the CNAB Return Move Code to be use exist in Invoicing > Configuration > Management > CNAB Return Move Code if necessary create please consider make PR to add as data in https://github.com/OCA/l10n-brazil/blob/12.0/l10n_br_account_payment_order/data/l10n_br_cnab_return_move_code_data.xml .
  • +
  • Create an Bank Account referent of CNAB in Invoicing > Configuration > Accounting > Bank Accounts .
  • +
  • Automatic will be create an Account Journal refer to bank account in Invoicing > Configuration > Accounting > Journals in tab Import related infos inform parameters of CNAB Return in fields “Type of Import”, “Receivable/Payable Account”, “Create Counterpart”, and if should make automatic reconciliation when import the file in “Automatic Reconcile payment returns”.
  • +
  • In Invoicing > Configuration > Management > Payment Modes create an Payment Mode with CNAB information, in the field “Fixed Bank Journal” inform the Account Journal of bank account and mark if “Automatically add when validating the invoice” so that you don’t have to do it manually.
  • +
  • Configure user access permissions, CNAB options are “User” and “Manager”.
  • +
+
+
+

Usage

+

Português

+
    +
  • Ao criar e Confirmar uma Fatura que tem um Modo de Pagamento que seja CNAB deverá aparecer o botão de “Imprimir Boleto”.
  • +
  • Caso esteja marcado no Modo de Pagamento a opção de “Adicionar automaticamente ao validar a fatura” será criada ou adicionada em uma Ordem de Pagamento as linhas de pagamentos do CNAB, se a opção não estiver marcada será preciso fazer isso manualmente podendo ser feito tanto na Fatura quanto na Ordem de Pagamento.
  • +
  • Ao Confirmar essa Ordem de Pagamento será possível gerar o arquivo de Remessa CNAB a ser enviado ao Banco, é importante confirmar o envio do arquivo alterando o status da ordem para “Arquivo Enviado”, essa informação é usada para validar se existe uma instrução CNAB pendente antes de se poder criar outra.
  • +
  • Alterações de CNAB como Alteração da Data de Vencimento, Protesto, Conceder Abatimento e etc podem ser feitas na própria Fatura em Faturamento > Clientes > Faturas na aba Recebimentos na última coluna existe o botão “Atualizar Informação CNAB” ao clicar em uma linha essa opção também aparece, ao fazer uma alteração é criada ou adicionada em uma Ordem de Pagamento a Instrução de Movimento CNAB selecionada.
  • +
  • A importação do arquivo CNAB de Retorno pode ser feita em Pagamentos > Importar arquivo Batch ou no próprio Diário em Faturamento > Configurações > Contabilidade > Diários na aba Informações Referentes a Importação o botão Importar arquivo Batch.
  • +
  • Toda importação de arquivo de retorno cria uma LOG que pode ser consultado em Pagamentos > LOG de Retorno CNAB.
  • +
  • Caso o Código de Retorno CNAB recebido seja um dos “Códigos de Liquidação do Retorno do Movimento” do Modo de Pagamento será criado uma Entrada de Diário com os valores quando existirem de desconto, juros/mora, tarifa bancaria, abatimento e valor a ser reconciliado com a linha da Fatura referente, os lançamentos são separados de acordo com as Contas Contabéis definidas no Modo de Pagamento, a linha para reconciliar a linha da Fatura precisam ser iguais por isso o valor é: +valor_recebido_calculado = (valor_recebido + valor_desconto + valor_abatimento) - valor_juros_mora
  • +
  • Quando marcada a opção de “Reconciliação Automatica” /a Entrada de Diário será movida para o status Lançado automaticamente ao importar o arquivo, se não estiver marcada isso deverá ser feito manualmente.
  • +
+

English

+
    +
  • When creating and confirming an Invoice that has a Payment Mode that is CNAB, the button should appear “Print Boleto”.
  • +
  • If the option to “Add automatically when validating the invoice” is marked in the Payment Mode CNAB payment lines will be created or added to a Payment Order, if the option is not marked, you will need to do this manually, which can be done both in the Invoice and in the Payment Order.
  • +
  • By confirming this Payment Order it will be possible to generate the CNAB Remessa file to be sent to the Bank, it is important to confirm the upload of the file by changing the order status to “File Uploaded”, this information is used to validate if there is a pending CNAB instruction before another one can be created.
  • +
  • CNAB changes such as Change Due Date, Protest, Grant Rebate, etc. can be made in the Invoice itself in Invoicing > Customers > Invoices in the Receivable tab in the last column there is the button “Update CNAB Information” when clicking on a line this option also appears, when making a change it is created or added to a Payment Order the selected CNAB Movement Instruction.
  • +
  • The import of the Return CNAB file can be done in Payments > Import Batch file or in the same Journal in Invoicing > Configuration > Accounting > Journals in the tab Import related infos the Import Batch File button.
  • +
  • Every return file import creates a LOG that can be consulted in Payments > CNAB Return LOG.
  • +
  • If the CNAB Return Code received is one of the “CNAB Liquidity Return Move Code” of the Payment Mode, a Journal Entry will be created with the values when there are discount, interest, tariff charge, rebate and amount to be reconciled with the referring Invoice line, entries are separated according to the Accounts defined in the Payment Mode, the line to reconcile the Invoice line need be equal so the value is: +calculated_value_receive = (receive_amount + discount_amount + rebate_amount) - interest_amount
  • +
  • When the “Automatic Reconciliation” option is checked, the Entry of Journal will be moved to the status Posted automatically when importing the file, if not checked it should be done manually.
  • +
+
+
+

Known issues / Roadmap

+
    +
  • Incluir a posssibilidade de imprimir o boleto no menu Imprimir da Fatura, na v12 aparentemente não é possível chamar um metodo apenas um QWeb, verificar na migração para outras versões.
  • +
+
+
+

Changelog

+
+

14.0.1.0.0 (2022-05-26)

+
    +
  • [MIG] Migration
  • +
+
+
+

12.0.1.0.0 (2021-05-07)

+
    +
  • [MIG] Finish migration
  • +
  • [IMP] Integrate with module account_move_base_import used to import CNAB file
  • +
  • [IMP] Make possible automatic reconciliation and register the values of Fees, Tariff Bank, Rebate in configured accounts.
  • +
+
+
+

12.0.1.0.0 (2020-06-12)

+
    +
  • [MIG] Start Migration
  • +
+
+
+

10.0.1.0.0 (2019-05-30)

+
    +
  • [MIG] Migration
  • +
+
+
+

8.0.1.0.0 (2018-01-29)

+
    +
  • [REF] Maked functional to print Boleto, create CNAB file and import CNAB as Extrat Bank the user should be resolved manully the divergences between the values( Fee, Tariff Bank, Rebate, etc).
  • +
+
+
+

8.0.1.0.0 (2017-07-01)

+
    +
  • [NEW] First version
  • +
+
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The development of this module has been financially supported by:

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

rvalyi mbcosta

+

This module is part of the OCA/l10n-brazil project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_br_account_payment_brcobranca/tests/__init__.py b/l10n_br_account_payment_brcobranca/tests/__init__.py new file mode 100644 index 000000000000..3af55fb9d2bb --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_payment_order +from . import test_return_import diff --git a/l10n_br_account_payment_brcobranca/tests/data/CNAB240AILOS.RET b/l10n_br_account_payment_brcobranca/tests/data/CNAB240AILOS.RET new file mode 100644 index 000000000000..782c487598a0 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/CNAB240AILOS.RET @@ -0,0 +1,8 @@ +08500000 2972316080001691010040040000 0010150123600000000003735 SUA EMPRESA LTDA COOPERATIVA DE CREDITO DO VALE 10912202103080600000608700000 +08500001T01 043 20972316080001691010040040000 0123600000000003735 SUA EMPRESA LTDA 000000060912202100000000 +0850000300011T 060010150000011711043011711043000000001 100000000004540103022022000000000000100085001015454/01 902002582975000109EMPRESA DE TESTE 000000000000000000000010033 +0850000300012U 060000000000000000000000000000000000000000000000000000000000000000000000300000000000000000010000000000000000000000000000000612202107122021 000000000000000 00000000000000000000000 +0850000300011T 060010150000011711043011711043000000002 100000000004540103022022000000000000200085001015454/01 902002582975000109EMPRESA DE TESTE 000000000000000000000010033 +0850000300012U 06000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000010000000000000000000000000000612202107122021 000000000000000 00000000000000000000000 +08500005 00001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +08599999 000001000016000000 diff --git a/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_3.RET b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_3.RET new file mode 100644 index 000000000000..44a560030e86 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_3.RET @@ -0,0 +1,4 @@ +02RETORNO01COBRANCA 42056000156620925442CENTRAL DAS COOPERATIVAS DE CR001BANCO DO BRASIL0708131314759 000001 +10211034414000158123430000037190000007223405000000000000000030 01 01900000000000000000001802060720 060720000000003000013612343 0907200000180 00000000000000000000000000000000003100000000000010000000005/01 000000003082000000000001 000002 +10211034414000158123430000037190000007223405000000000000000049 01 01900000000000000000001802060720 060720000000007000013612343 0907200000180 000000000000000000000000000000000071000000000000100000000005/02 00000007082000000000001 000003 +9201001 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000016 diff --git a/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_4.RET b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_4.RET new file mode 100644 index 000000000000..f8393d8323a7 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_maior_4.RET @@ -0,0 +1,4 @@ +02RETORNO01COBRANCA 42056000156620925442CENTRAL DAS COOPERATIVAS DE CR001BANCO DO BRASIL0708131314759 000001 +10211034414000158123430000037190000007223405000000000000000030 01 01900000000000000000001806060720 060720000000003000013612343 0907200000180 00000000000000000000000000000000003100000000000010000000005/01 000000003082000000000001 000002 +10211034414000158123430000037190000007223405000000000000000049 01 01900000000000000000001806060720 060720000000007000013612343 0907200000180 000000000000000000000000000000000071000000000000100000000005/02 00000007082000000000001 000003 +9201001 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000016 diff --git a/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_1.RET b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_1.RET new file mode 100644 index 000000000000..13dddad03def --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_1.RET @@ -0,0 +1,4 @@ +02RETORNO01COBRANCA 42056000156620925442CENTRAL DAS COOPERATIVAS DE CR001BANCO DO BRASIL0708131314759 000001 +10211034414000158123430000037190000007223405000000000000000010 01 01900000000000000000001802060720 060720000000003000013612343 0907200000180 00000000002000000000000300000000002965000000000000000000005/01 000000002932000000000001 000002 +10211034414000158123430000037190000007223405000000000000000029 01 01900000000000000000001802060720 060720000000007000013612343 0907200000180 00000000002000000000000300000000006965000000000000000000005/02 000000006932000000000001 000003 +9201001 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000016 diff --git a/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_2.RET b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_2.RET new file mode 100644 index 000000000000..5a17b5cd1177 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/CNAB400UNICRED_valor_menor_2.RET @@ -0,0 +1,4 @@ +02RETORNO01COBRANCA 42056000156620925442CENTRAL DAS COOPERATIVAS DE CR001BANCO DO BRASIL0708131314759 000001 +10211034414000158123430000037190000007223405000000000000000010 01 01900000000000000000001806060720 060720000000003000013612343 0907200000180 00000000002000000000000300000000002950000000000000000000005/01 000000002932000000000001 000002 +10211034414000158123430000037190000007223405000000000000000029 01 01900000000000000000001806060720 060720000000007000013612343 0907200000180 00000000002000000000000300000000006950000000000000000000005/02 000000006932000000000001 000003 +9201001 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000000000000000000000000000000 000016 diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_ailos_cnab240.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_ailos_cnab240.pdf new file mode 100644 index 000000000000..7888b558434e Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_ailos_cnab240.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bb400.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bb400.pdf new file mode 100644 index 000000000000..0ef6221a37ea Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bb400.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bradesco400.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bradesco400.pdf new file mode 100644 index 000000000000..d764b263e174 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_bradesco400.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_itau400.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_itau400.pdf new file mode 100644 index 000000000000..959cb57a1b02 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_itau400.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander240.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander240.pdf new file mode 100644 index 000000000000..090d74ae1b16 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander240.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander400.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander400.pdf new file mode 100644 index 000000000000..ee54c524c142 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_santander400.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_sicredi_cnab240.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_sicredi_cnab240.pdf new file mode 100644 index 000000000000..084dfe967a69 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_sicredi_cnab240.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_unicred400.pdf b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_unicred400.pdf new file mode 100644 index 000000000000..e3ac99d53948 Binary files /dev/null and b/l10n_br_account_payment_brcobranca/tests/data/boleto_teste_unicred400.pdf differ diff --git a/l10n_br_account_payment_brcobranca/tests/data/test_remessa.REM b/l10n_br_account_payment_brcobranca/tests/data/test_remessa.REM new file mode 100644 index 000000000000..98e34ca146f4 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/test_remessa.REM @@ -0,0 +1,6 @@ +23100000 281583054000129 01611000000000039500Sua Empresa BANCO BRADESCO S.A. 11303201712000000000108400000 +23100011R01 042 2081583054000129 01611000000000039500Sua Empresa 000001011303201700000000 +2310001300001P 01016110000000000395000000000000000000000030 0 001 0503201700000000010000000000 01A130320170050320170000000000000000000000000000000000000000000000000000000000000000000001 00020 000000000000 +2310001300002Q 012081493979000189Cliente 1 SP Rua Samuel Morse 135 Brooklin 04576060Sao Paulo SP0000000000000000 000 +23100015 00000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000 +23199999 000001000006000000 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-1.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-1.REM new file mode 100644 index 000000000000..55345938fcd6 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-1.REM @@ -0,0 +1,10 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119082000000105000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000011606202100000000 +1040001300001P 0101565100012200000000000140000000000000011122000000000040 1606202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 0002000090000000000 +1040001300002Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 01000000000000000000000000000000000000000000000000000000000000000000000000 +1040001300004P 0101565100012200000000000140000000000000021122000000000040 3107202100000000007000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 0002000090000000000 +1040001300005Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300006R 01000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000008000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000010 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-10-alt_valor_titulo.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-10-alt_valor_titulo.REM new file mode 100644 index 000000000000..9e51710ab23d --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-10-alt_valor_titulo.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119422900001005000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000101606202100000000 +1040001300001P 4701565100012200000000000140000000000000011122000000000040 0707202100000000001500000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 472011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 47000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-2-data_venc.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-2-data_venc.REM new file mode 100644 index 000000000000..ae843760efec --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-2-data_venc.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119175000000205000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000021606202100000000 +1040001300001P 0601565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 062011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 06000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-3-protesto.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-3-protesto.REM new file mode 100644 index 000000000000..969337ee93d4 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-3-protesto.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119205800000305000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000031606202100000000 +1040001300001P 0901565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 092011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 09000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-4-sust_prot_mant_carteira.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-4-sust_prot_mant_carteira.REM new file mode 100644 index 000000000000..8f9471b21933 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-4-sust_prot_mant_carteira.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119241200000405000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000041606202100000000 +1040001300001P 1101565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 112011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 11000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-5-conceder_abatimento.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-5-conceder_abatimento.REM new file mode 100644 index 000000000000..30ff8e52d5d2 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-5-conceder_abatimento.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119264500000505000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000051606202100000000 +1040001300001P 0401565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 042011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 04000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-6-cancelar_abatimento.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-6-cancelar_abatimento.REM new file mode 100644 index 000000000000..968e8fbaa7ea --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-6-cancelar_abatimento.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119310100000605000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000061606202100000000 +1040001300001P 0501565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 052011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 05000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-7-conceder_desconto.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-7-conceder_desconto.REM new file mode 100644 index 000000000000..72c6a2deb267 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-7-conceder_desconto.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119323900000705000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000071606202100000000 +1040001300001P 0701565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 072011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 07000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-8-cancelar_desconto.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-8-cancelar_desconto.REM new file mode 100644 index 000000000000..0696bc50f637 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-8-cancelar_desconto.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119344500000805000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000081606202100000000 +1040001300001P 0801565100012200000000000140000000000000011122000000000040 0707202100000000003000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 082011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 08000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-9-alt_valor_titulo.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-9-alt_valor_titulo.REM new file mode 100644 index 000000000000..bf4ca4521785 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-cef_240-9-alt_valor_titulo.REM @@ -0,0 +1,7 @@ +10400000 2972316080001690000000000000000000001565100012200000000SUA EMPRESA LTDA CAIXA ECONOMICA FEDERAL 11606202119391600000905000000 REMESSA-PRODUCAO +10400011R0100030 20972316080001690001220000000000000001565100012200000000SUA EMPRESA LTDA 000000091606202100000000 +1040001300001P 4701565100012200000000000140000000000000011122000000000040 0707202100000000002000000000099N1606202130000000000000000000000000000000000000000000000000000000000000000000000000000000000000040 3001120090000000000 +1040001300002Q 472011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +1040001300003R 47000000000000000000000000000000000000000000000000000000000000000000000000 +10400015 000005000000000000000000000000000000000000000000000000000000000000000000000 +10499999 000001000007 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-unicred_400-1.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-unicred_400-1.REM new file mode 100644 index 000000000000..e5cc00d54e1f --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa-unicred_400-1.REM @@ -0,0 +1,4 @@ +01REMESSA01COBRANCA 00000000000092035760SUA EMPRESA LTDA 136UNICRED 160621 0000000001 CODIGO_BENEFICIARIO000001 +1012343000000000371900210000000000000 13600 0200000002002N 010000003/01160621000000003000000000000000160621020500000000002000000000000000000000000000000190000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 000002 +1012343000000000371900210000000000000 13600 0200000002002N 010000003/02310721000000007000000000000000160621020500000000002000000000000000000000000000000270000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 000003 +9 000004 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_ailos240.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_ailos240.REM new file mode 100644 index 000000000000..42a78af7bdf0 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_ailos240.REM @@ -0,0 +1,8 @@ +08500000 297231608000169101004 0123600000000003735 SUA EMPRESA LTDA AILOS 10912202103080600000608700000 +08500011R01 045 2097231608000169101004 0123600000000003735 SUA EMPRESA LTDA 000000060912202100000000 +0850001300001P 010123600000000003735 00003735000000011 101220000000000000010912202100000000003000000000002N091220213000000000000000000000000000000000000000000000000000000000000000000000000000000/01 3052 090000000000 +0850001300002Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +0850001300003P 010123600000000003735 00003735000000012 101220000000000000023101202200000000007000000000002N091220213000000000000000000000000000000000000000000000000000000000000000000000000000000/02 3052 090000000000 +0850001300004Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +08500015 00000600000200000000000100000000000000000000000000000000000000000000000000000000000000000000000000 +08599999 000001000008 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bb400.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bb400.REM new file mode 100644 index 000000000000..e45d0c25d769 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bb400.REM @@ -0,0 +1,4 @@ +01REMESSA01COBRANCA 70300000053848000000SUA EMPRESA LTDA 001BANCODOBRASIL 0608210000001 7654321 000001 +70297231608000169703000000538480001234 000123400000000010000 019000000004DSC1801000000000106082100000000300000010000 01N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00 000002 +70297231608000169703000000538480001234 000123400000000020000 019000000004DSC1801000000000230092100000000700000010000 01N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00 000003 +9 000004 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bradesco400.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bradesco400.REM new file mode 100644 index 000000000000..3e98e3c018cd --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_bradesco400.REM @@ -0,0 +1,4 @@ +01REMESSA01COBRANCA 00000000001222130126SUA EMPRESA LTDA 237BRADESCO 060821 MX0000001 000001 +100000000000000000000003016110000395000000005/0 0000000000000000001P00000000002N 2 0100000005/006082100000000300000000000001N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA, 807, SAO PAULO/SP 01311915 000002 +100000000000000000000003016110000395000000005/0 0000000000000000002800000000002N 2 0100000005/030092100000000700000000000001N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA, 807, SAO PAULO/SP 01311915 000003 +9 000004 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_itau400.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_itau400.REM new file mode 100644 index 000000000000..41d849c1b0d5 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_itau400.REM @@ -0,0 +1,4 @@ +01REMESSA01COBRANCA 851500150160 SUA EMPRESA LTDA 341BANCO ITAU SA 060821 000001 +10297231608000169851500150160 000000000003/0 00000000010000000000000175 I0100000003/006082100000000300003410000099N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00000003 000002 +10297231608000169851500150160 000000000003/0 00000000020000000000000175 I0100000003/030092100000000700003410000099N060821000000000000000000000000000000000000000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00000003 000003 +9 000004 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander240.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander240.REM new file mode 100644 index 000000000000..da2bf62e66ab --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander240.REM @@ -0,0 +1,10 @@ +03300000 2097231608000169123456789012345 SUA EMPRESA LTDA BANCO SANTANDER 126022024 000001040 +03300011R01 030 2097231608000169 123456789012345 SUA EMPRESA LTDA 000000012602202400000000 +0330001300001P 010707200000133310000013331 0000000000019512 TESTE SANTANDER2602202400000000003000000000 02N26022024300000000000000000000000026022024000000000000300000000000000000000000000000000TESTE SANTANDER CNAB24001000300000 +0330001300002Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000000000000 +0330001300003R 01000000000000000000000000000000000000000000000000000000000000000000000000 +0330001300004P 010707200000133310000013331 0000000000027512 TESTE SANTANDER3103202400000000007000000000 02N26022024300000000000000000000000031032024000000000000700000000000000000000000000000000TESTE SANTANDER CNAB24002000300000 +0330001300005Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000000000000 +0330001300006R 01000000000000000000000000000000000000000000000000000000000000000000000000 +03300015 000008 +03399999 000001000010 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander400.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander400.REM new file mode 100644 index 000000000000..eadb2241d21b --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_santander400.REM @@ -0,0 +1,4 @@ +01REMESSA01COBRANCA 12345678901234567890SUA EMPRESA LTDA 033SANTANDER 2602240000000000000000 058000001 +1029723160800016912345678901234567890TESTE SANTANDER CNAB400/0100000019000000 00000000000000000000 000000501TESTE SANTANDER CNAB400/0126022400000000300000330000001N260224000000000000000002602240000000000300000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00 000002 +1029723160800016912345678901234567890TESTE SANTANDER CNAB400/0200000027000000 00000000000000000000 000000501TESTE SANTANDER CNAB400/0231032400000000700000330000001N260224000000000000000003103240000000000700000000000000000000000000000211034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP 00 000003 +9000004000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004 diff --git a/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_sicredi240.REM b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_sicredi240.REM new file mode 100644 index 000000000000..b4cb7802a2ed --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/data/teste_remessa_sicredi240.REM @@ -0,0 +1,10 @@ +74800000 297231608000169 01234 0000000003310 SUA EMPRESA LTDA SICREDI 11108202122301800000108101600 +74800011R01 040 2097231608000169 01234 0000000003310 SUA EMPRESA LTDA 000000011108202100000000 +7480001300001P 0101234 0000000003310 0000000001 111220000000000000301208202100000000003000000000 03N11082021300000000000000000000000100000000000000000000000000000000000000000000000000000 0000000300001060090000000000 +7480001300002Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +7480001300003R 01000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000 000000000000 0 +7480001300004P 0101234 0000000003310 0000000002 111220000000000000303009202100000000007000000000 03N11082021300000000000000000000000100000000000000000000000000000000000000000000000000000 0000000300001060090000000000 +7480001300005Q 012011034414000158AKRETION LTDA AVENIDA PAULISTA 807 CENTRO 01311915SAO PAULO SP0000000000000000 000 +7480001300006R 01000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000 000000000000 0 +74800015 00000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +74899999 000001000010000000 diff --git a/l10n_br_account_payment_brcobranca/tests/test_payment_order.py b/l10n_br_account_payment_brcobranca/tests/test_payment_order.py new file mode 100644 index 000000000000..78d9423d55f3 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/test_payment_order.py @@ -0,0 +1,954 @@ +# @ 2021 Akretion - www.akretion.com.br - +# Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +import os +from datetime import date, timedelta +from unittest import mock + +from odoo.exceptions import UserError +from odoo.modules import get_resource_path +from odoo.tests import Form, TransactionCase, tagged + +_module_ns = "odoo.addons.l10n_br_account_payment_brcobranca" +_provider_class_pay_order = ( + _module_ns + ".models.account_payment_order" + ".PaymentOrder" +) +_provider_class_acc_invoice = _module_ns + ".models.account_move" + ".AccountMove" + + +@tagged("post_install", "-at_install") +class TestPaymentOrder(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.register_payments_model = cls.env["account.payment.register"].with_context( + active_model="account.move" + ) + cls.payment_model = cls.env["account.payment"] + cls.aml_cnab_change_model = cls.env["account.move.line.cnab.change"] + + # Get Invoice for test + cls.invoice_unicred = cls.env.ref( + "l10n_br_account_payment_order." + "demo_invoice_payment_order_unicred_cnab400" + ) + cls.invoice_cef = cls.env.ref( + "l10n_br_account_payment_order." "demo_invoice_payment_order_cef_cnab240" + ) + cls.partner_akretion = cls.env.ref("l10n_br_base.res_partner_akretion") + # I validate invoice by creating on + cls.invoice_cef.action_post() + + payment_order = cls.env["account.payment.order"].search( + [("payment_mode_id", "=", cls.invoice_cef.payment_mode_id.id)] + ) + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-1.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + + # Journal + cls.journal_cash = cls.env["account.journal"].search( + [("type", "=", "cash"), ("company_id", "=", cls.invoice_cef.company_id.id)], + limit=1, + ) + cls.payment_method_manual_in = cls.env.ref( + "account.account_payment_method_manual_in" + ) + + cls.aml_to_change = cls.invoice_cef.financial_move_line_ids[0] + cls.ctx_change_cnab = { + "active_model": "account.move.line", + "active_ids": [cls.aml_to_change.id], + } + + def _run_boleto_remessa(self, invoice, boleto_file, remessa_file): + # I validate invoice + invoice.action_post() + + # I check that the invoice state is "Posted" + self.assertEqual(invoice.state, "posted") + + # Imprimir Boleto + if os.environ.get("CI"): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + boleto_file, + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_acc_invoice + "._get_brcobranca_boleto", + return_value=mocked_response, + ): + invoice.view_boleto_pdf() + else: + invoice.view_boleto_pdf() + + payment_order = self.env["account.payment.order"].search( + [("payment_mode_id", "=", invoice.payment_mode_id.id)] + ) + + self.assertEqual(len(payment_order.payment_line_ids), 2) + + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + remessa_file, + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_banco_brasil_cnab_400(self): + """Teste Boleto e Remessa Banco do Brasil - CNAB 400""" + invoice_bb_cnab_400 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_bb_cnab400" + ) + self._run_boleto_remessa( + invoice_bb_cnab_400, "boleto_teste_bb400.pdf", "teste_remessa_bb400.REM" + ) + + def test_banco_itau_cnab_400(self): + """Teste Boleto e Remessa Banco Itau - CNAB 400""" + invoice_itau_cnab_400 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_itau_cnab400" + ) + self._run_boleto_remessa( + invoice_itau_cnab_400, + "boleto_teste_itau400.pdf", + "teste_remessa_itau400.REM", + ) + + def test_banco_bradesco_cnab_400(self): + """Teste Boleto e Remessa Banco Bradesco - CNAB 400""" + invoice_bradesco_cnab_400 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order" + ) + self._run_boleto_remessa( + invoice_bradesco_cnab_400, + "boleto_teste_bradesco400.pdf", + "teste_remessa_bradesco400.REM", + ) + + def test_banco_unicred_cnab_400(self): + """Teste Boleto e Remessa Banco Unicred - CNAB 400""" + invoice_unicred_cnab_400 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_unicred_cnab400" + ) + self._run_boleto_remessa( + invoice_unicred_cnab_400, + "boleto_teste_unicred400.pdf", + "teste_remessa-unicred_400-1.REM", + ) + + def test_banco_sicred_cnab_240(self): + """Teste Boleto e Remessa Banco SICREDI - CNAB 240""" + invoice_sicred_cnab_240 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_sicredi_cnab240" + ) + + self._run_boleto_remessa( + invoice_sicred_cnab_240, + "boleto_teste_sicredi_cnab240.pdf", + "teste_remessa_sicredi240.REM", + ) + + def test_banco_ailos_cnab_240(self): + """Teste Boleto e Remessa Banco AILOS - CNAB 240""" + invoice_ailos_cnab_240 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_ailos_cnab240" + ) + self._run_boleto_remessa( + invoice_ailos_cnab_240, + "boleto_teste_ailos_cnab240.pdf", + "teste_remessa_ailos240.REM", + ) + + def test_banco_santander_cnab_400(self): + """Teste Boleto e Remessa Banco Santander - CNAB 400""" + invoice_santander_cnab_400 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_santander_cnab400" + ) + self._run_boleto_remessa( + invoice_santander_cnab_400, + "boleto_teste_santander400.pdf", + "teste_remessa_santander400.REM", + ) + + def test_banco_santander_cnab_240(self): + """Teste Boleto e Remessa Banco Santander - CNAB 240""" + invoice_santander_cnab_240 = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_santander_cnab240" + ) + self._run_boleto_remessa( + invoice_santander_cnab_240, + "boleto_teste_santander240.pdf", + "teste_remessa_santander240.REM", + ) + + def test_bank_cnab_not_implement_brcobranca(self): + """Test Bank CNAB not implemented in BRCobranca.""" + invoice = self.env.ref( + "l10n_br_account_payment_order.demo_invoice_payment_order_itau_cnab240" + ) + # I validate invoice + invoice.action_post() + + # I check that the invoice state is "Posted" + self.assertEqual(invoice.state, "posted") + # O Banco Itau CNAB 240 não está implementado no BRCobranca + # por isso deve gerar erro. + with self.assertRaises(UserError): + invoice.view_boleto_pdf() + + def test_payment_order_invoice_cancel_process(self): + """Test Payment Order and Invoice Cancel process.""" + + payment_order = self.env["account.payment.order"].search( + [("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id)] + ) + + # Ordem de Pagto CNAB não pode ser apagada + with self.assertRaises(UserError): + payment_order.unlink() + + # Ordem de Pagto CNAB não pode ser Cancelada + with self.assertRaises(UserError): + payment_order.action_done_cancel() + + # Testar Cancelamento + self.invoice_cef.button_cancel() + + # Caso de Ordem de Pagamento já confirmado a Linha + # e a account.move não pode ser apagadas + self.assertEqual(len(payment_order.payment_line_ids), 2) + # A partir da v13 as account.move.line relacionadas + # continuam exisitindo + self.assertEqual(len(self.invoice_cef.line_ids), 3) + self.assertEqual(len(self.invoice_cef.invoice_line_ids), 1) + + # Criação do Pedido de Baixa + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + + for line in payment_order.payment_line_ids: + # Caso de Baixa do Titulo + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_write_off_code_id.name, + ) + + def test_payment_outside_cnab_writeoff_and_change_tittle_value(self): + """ + Caso de Pagamento com CNAB já iniciado sendo necessário fazer a Baixa + de uma Parcela e a Alteração de Valor de Titulo por pagto parcial. + """ + + payment = ( + self.env["account.payment"] + .with_context( + active_model="account.move", + active_ids=self.invoice_cef.ids, + ) + .create( + { + "payment_type": "inbound", + "payment_method_line_id": ( + self.journal_cash._get_available_payment_method_lines("inbound") + .filtered(lambda x: x.code == "manual") + .id + ), + "partner_type": "customer", + "partner_id": self.partner_akretion.id, + "amount": 600, + "journal_id": self.journal_cash.id, + } + ) + ) + payment.action_post() + + # Ordem de PAgto com alterações + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + if line.amount_currency == 300: + # Caso de Baixa do Titulo + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_write_off_code_id.name, + ) + else: + # Caso de alteração do valor do titulo por pagamento parcial + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_change_title_value_id.name, + ) + self.assertEqual( + line.move_line_id.amount_residual, line.amount_currency + ) + + def test_cnab_change_due_date(self): + """ + Test CNAB Change Due Date + """ + + dict_change_due_date = { + "change_type": "change_date_maturity", + } + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create(dict_change_due_date) + # Teste alteração com a mesma data não permitido + # with self.assertRaises(UserError): + # aml_cnab_change.doit() + # TODO ao rodar 2 vezes o metodo doit por algum motivo, ainda desconhecido, + # no teste o campo company_id na Order de Debito vem False, o que causa o + # erro abaixo: + # ### + # odoo.exceptions.UserError: Incompatible companies on records: + # - 'P00228' belongs to company False and 'Journal Item' (move_line_id: + # 'Teste Caixa Economica Federal CNAB240 Teste Caixa Economica Federal CNAB240' + # ) belongs to another company. + # ### + # Porém esse campo é um related do payment_mode_id + # https://github.com/OCA/bank-payment/blob/14.0/ + # account_payment_order/models/account_payment_order.py#L42 + # e ao verificar no metodo que busca ou cria uma nova Ordem de Debito + # https://github.com/OCA/l10n-brazil/blob/14.0/ + # l10n_br_account_payment_order/models/l10n_br_cnab_change_methods.py#L67 + # é possível validar que o payment_mode_id está preechido: + # print('PAYMENT ORDER =====', payorder, payorder.name, + # payorder.payment_mode_id.name, payorder.payment_mode_id.company_id.name, + # payorder.company_id.name) + # PAYMENT ORDER ===== account.payment.order(139,) PAY0139 + # Cobrança Caixa Economica Federal 240 Sua Empresa + # False + + new_date = date.today() + timedelta(days=30) + + dict_change_due_date.update({"date_maturity": new_date}) + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create(dict_change_due_date) + + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_change_maturity_date_id.name, + ) + + # Open payment order + payment_order.draft2open() + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-2-data_venc.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_protest(self): + """ + Test CNAB Protesto + """ + # Protesto + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create({"change_type": "protest_tittle"}) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_protest_title_id.name, + ) + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-3-protesto.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_suspend_protest_and_keep_wallet(self): + """ + Test CNAB Suspend Protest and Keep Wallet + """ + # Suspender Protesto e manter em carteira + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create({"change_type": "suspend_protest_keep_wallet"}) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + + cnab_code_suspend_protest_keep_wallet = ( + self.aml_to_change.payment_mode_id.cnab_code_suspend_protest_keep_wallet_id + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + cnab_code_suspend_protest_keep_wallet.name, + ) + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-4-sust_prot_mant_carteira.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_grant_rebate(self): + """ + Test CNAB Grant Rebate + """ + # Caso Conceder Abatimento + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create( + { + "change_type": "grant_rebate", + "rebate_value": 10.0, + } + ) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_grant_rebate_id.name, + ) + self.assertEqual(line.rebate_value, 10.0) + + # Open payment order + payment_order.draft2open() + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_grant_rebate_id.name, + ) + self.assertEqual(line.rebate_value, 10.0) + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-5-conceder_abatimento.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_cancel_rebate(self): + """ + Test CNAB Cancel Rebate + """ + # Caso Cancelar Abatimento + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create({"change_type": "cancel_rebate"}) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_cancel_rebate_id.name, + ) + + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-6-cancelar_abatimento.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_grant_discount(self): + """ + Test CNAB Grant Discount + """ + # Caso Conceder Desconto + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create( + { + "change_type": "grant_discount", + "discount_value": 10.0, + } + ) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_grant_discount_id.name, + ) + self.assertEqual(line.discount_value, 10.0) + + # Open payment order + payment_order.draft2open() + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_grant_discount_id.name, + ) + self.assertEqual(line.discount_value, 10.0) + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-7-conceder_desconto.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + def test_cnab_cancel_discount(self): + """ + Test CNAB Cancel Discount + """ + # Caso Cancelar discount + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create({"change_type": "cancel_discount"}) + aml_cnab_change.doit() + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_cancel_discount_id.name, + ) + + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-8-cancelar_desconto.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + # Suspender Protesto e dar Baixa + # TODO: Especificar melhor esse caso + + def test_cnab_change_method_not_payment(self): + """ + Test CNAB Change Method Not Payment + """ + aml_cnab_change = self.aml_cnab_change_model.with_context( + **self.ctx_change_cnab + ).create({"change_type": "not_payment"}) + aml_cnab_change.doit() + self.assertEqual(self.aml_to_change.payment_situation, "nao_pagamento") + self.assertEqual(self.aml_to_change.cnab_state, "done") + self.assertEqual(self.aml_to_change.reconciled, True) + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + # Baixa do Titulo + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_write_off_code_id.name, + ) + + def test_payment(self): + """ + Caso de Pagamento com CNAB + """ + self.partner_akretion = self.env.ref("l10n_br_base.res_partner_akretion") + + payment_order = self.env["account.payment.order"].search( + [("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id)] + ) + + # Open payment order + payment_order.action_cancel() + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-1.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + payment_register = Form( + self.env["account.payment.register"].with_context( + active_model="account.move", + active_ids=self.invoice_cef.ids, + ) + ) + payment_register.journal_id = self.journal_cash + payment_register.payment_method_line_id = ( + self.journal_cash._get_available_payment_method_lines("inbound").filtered( + lambda x: x.code == "manual" + ) + ) + + # Perform the partial payment by setting the amount at 300 instead of 500 + payment_register.amount = 100 + payment_register.save()._create_payments() + + # Ordem de PAgto com alterações + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + + for line in payment_order.payment_line_ids: + # Caso de alteração do valor do titulo por pagamento parcial + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_change_title_value_id.name, + ) + self.assertEqual(line.move_line_id.amount_residual, line.amount_currency) + + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-9-alt_valor_titulo.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + payment_register = Form( + self.env["account.payment.register"].with_context( + active_model="account.move", + active_ids=self.invoice_cef.ids, + ) + ) + payment_register.journal_id = self.journal_cash + payment_register.payment_method_line_id = ( + self.journal_cash._get_available_payment_method_lines("inbound").filtered( + lambda x: x.code == "manual" + ) + ) + + # Perform the partial payment by setting the amount at 300 instead of 500 + payment_register.amount = 50 + payment_register.save()._create_payments() + + # Ordem de PAgto com alterações + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + # Caso de alteração do valor do titulo por pagamento parcial + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_code_change_title_value_id.name, + ) + self.assertEqual(line.move_line_id.amount_residual, line.amount_currency) + + # Open payment order + payment_order.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-cef_240-10-alt_valor_titulo.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order.open2generated() + else: + payment_order.open2generated() + + # Confirm Upload + payment_order.generated2uploaded() + self.assertEqual(payment_order.state, "uploaded") + + payment = ( + self.env["account.payment"] + .with_context( + active_model="account.move", + active_ids=self.invoice_cef.ids, + ) + .create( + { + "payment_type": "inbound", + "payment_method_line_id": ( + self.journal_cash._get_available_payment_method_lines("inbound") + .filtered(lambda x: x.code == "manual") + .id + ), + "partner_type": "customer", + "partner_id": self.partner_akretion.id, + "amount": 150, + "journal_id": self.journal_cash.id, + } + ) + ) + payment.action_post() + + # Ordem de PAgto com alterações + payment_order = self.env["account.payment.order"].search( + [ + ("payment_mode_id", "=", self.invoice_cef.payment_mode_id.id), + ("state", "=", "draft"), + ] + ) + for line in payment_order.payment_line_ids: + # Baixa do Titulo + self.assertEqual( + line.mov_instruction_code_id.name, + line.order_id.payment_mode_id.cnab_write_off_code_id.name, + ) + # TODO: Pedido de Baixa está indo com o valor inicial deveria ser + # o ultimo valor enviado ? Já que é um Pedido de Baixa o Banco + # validaria essas atualizações ? + # l.move_line_id.amount_residual = 0.0 + # l.amount_currency = 300 + # self.assertEqual( + # l.move_line_id.amount_residual, + # l.amount_currency) diff --git a/l10n_br_account_payment_brcobranca/tests/test_return_import.py b/l10n_br_account_payment_brcobranca/tests/test_return_import.py new file mode 100644 index 000000000000..f9894291983d --- /dev/null +++ b/l10n_br_account_payment_brcobranca/tests/test_return_import.py @@ -0,0 +1,892 @@ +# Copyright 2021 Akretion - Raphaël Valyi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) +# Copyright (C) 2021-Today - Akretion (). +# @author Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import os +from unittest import mock + +from odoo.modules import get_resource_path +from odoo.tests import TransactionCase, tagged + +_module_ns = "odoo.addons.l10n_br_account_payment_brcobranca" +_provider_class_pay_order = ( + _module_ns + ".models.account_payment_order" + ".PaymentOrder" +) +_provider_class = _module_ns + ".parser.cnab_file_parser" + ".CNABFileParser" + + +@tagged("post_install", "-at_install") +class TestReturnImport(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.company_a = cls.env.ref("base.main_company") + cls.account_move_obj = cls.env["account.move"] + cls.account_move_line_obj = cls.env["account.move.line"] + cls.cnab_log_obj = cls.env["l10n_br_cnab.return.log"] + + cls.account_id = cls.env.ref( + "l10n_br_account_payment_order.1_account_template_3010101010200_avoid_travis_error" + ) + cls.bank_account = cls.env["account.account"].create( + { + "code": "X1014", + "name": "Bank Current Account - (test)", + "account_type": "asset_cash", + } + ) + cls.import_wizard_obj = cls.env["credit.statement.import"] + + # Get Invoice for test + cls.invoice_unicred_1 = cls.env.ref( + "l10n_br_account_payment_order." + "demo_invoice_payment_order_unicred_cnab400" + ) + cls.invoice_unicred_2 = cls.env.ref( + "l10n_br_account_payment_brcobranca." + "demo_invoice_brcobranca_unicred_cnab400" + ) + + cls.invoice_ailos_1 = cls.env.ref( + "l10n_br_account_payment_order." "demo_invoice_payment_order_ailos_cnab240" + ) + + cls.journal = cls.env.ref("l10n_br_account_payment_order.unicred_journal") + + # I validate invoice by creating on + cls.invoice_unicred_1.action_post() + cls.invoice_unicred_2.action_post() + cls.invoice_ailos_1.action_post() + + # Para evitar erros nos testes de variação da Sequencia do + # Nosso Numero/own_number quando se roda mais de uma vez ou + # devido a diferença entre os comandos feitos pelo Travis + cls.invoice_unicred_1_own_numbers = [] + for line in cls.invoice_unicred_1.financial_move_line_ids: + # No arquivo de retorno vem o NOSSO NUMERO + Digito Verificador + cls.invoice_unicred_1_own_numbers.append(line.own_number + "0") + + cls.invoice_unicred_2_own_numbers = [] + for line in cls.invoice_unicred_2.financial_move_line_ids: + # No arquivo de retorno vem o NOSSO NUMERO + Digito Verificador + cls.invoice_unicred_2_own_numbers.append(line.own_number + "0") + + cls.invoice_ailos_1_own_numbers = [] + for line in cls.invoice_ailos_1.financial_move_line_ids: + cls.invoice_ailos_1_own_numbers.append(line.own_number) + + payment_order_unicred = cls.env["account.payment.order"].search( + [("payment_mode_id", "=", cls.invoice_unicred_1.payment_mode_id.id)] + ) + + # Open payment order + payment_order_unicred.draft2open() + + # Verifica se deve testar com o mock + if os.environ.get("CI"): + # Generate + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "teste_remessa-unicred_400-1.REM", + ) + with open(file_name, "rb") as f: + mocked_response = f.read() + with mock.patch( + _provider_class_pay_order + "._get_brcobranca_remessa", + return_value=mocked_response, + ): + payment_order_unicred.open2generated() + else: + payment_order_unicred.open2generated() + + # Confirm Upload + payment_order_unicred.generated2uploaded() + + def _import_file(self, file_name): + """import a file using the wizard + return the create account.bank.statement object + """ + + with open(file_name, "rb") as f: + content = f.read() + self.wizard = self.import_wizard_obj.create( + { + "journal_id": self.journal.id, + "input_statement": base64.b64encode(content), + "file_name": os.path.basename(file_name), + } + ) + action = self.wizard.import_statement() + log_view_ref = self.ref( + "l10n_br_account_payment_order.l10n_br_cnab_return_log_form_view" + ) + if action["views"] == [(log_view_ref, "form")]: + return self.cnab_log_obj.browse(action["res_id"]) + else: + return self.account_move_obj.browse(action["res_id"]) + + def test_valor_menor_1(self): + mocked_response = [ + { + "codigo_registro": "1", + "codigo_ocorrencia": "02", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000010", + "nosso_numero": self.invoice_unicred_1_own_numbers[0], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000300", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000030000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000200", + "desconto_concedito": None, + "valor_recebido": "0000000029650", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "1", + "codigo_ocorrencia": "02", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000029", + "nosso_numero": self.invoice_unicred_1_own_numbers[1], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000300", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000070000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000200", + "desconto_concedito": None, + "valor_recebido": "0000000069650", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "9", + "codigo_ocorrencia": "00", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "0000", + "cedente_com_dv": "000000000", + "convenio": None, + "nosso_numero": "00 00000", + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "000000", + "valor_titulo": "0000000000000", + "banco_recebedor": "00", + "agencia_recebedora_com_dv": "", + "especie_documento": None, + "data_credito": "000000", + "valor_tarifa": "", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "", + "juros_mora": "", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "000016", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + ] + + with mock.patch( + _provider_class + "._get_brcobranca_retorno", + return_value=mocked_response, + ): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "CNAB400UNICRED_valor_menor_1.RET", + ) + # Se não for um codigo cnab de liquidação retorna apenas o LOG criado. + log = self._import_file(file_name) + + self.assertEqual("Banco UNICRED - Conta 371", log.name) + + def test_valor_menor_2(self): + mocked_response = [ + { + "codigo_registro": "1", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000090", + "nosso_numero": self.invoice_unicred_1_own_numbers[0], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000300", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000030000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000200", + "desconto_concedito": None, + "valor_recebido": "0000000029500", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "1", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000109", + "nosso_numero": self.invoice_unicred_1_own_numbers[1], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000300", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000070000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000200", + "desconto_concedito": None, + "valor_recebido": "0000000069500", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "9", + "codigo_ocorrencia": "00", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "0000", + "cedente_com_dv": "000000000", + "convenio": None, + "nosso_numero": "00 00000", + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "000000", + "valor_titulo": "0000000000000", + "banco_recebedor": "00", + "agencia_recebedora_com_dv": "", + "especie_documento": None, + "data_credito": "000000", + "valor_tarifa": "", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "", + "juros_mora": "", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "000016", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + ] + + with mock.patch( + _provider_class + "._get_brcobranca_retorno", + return_value=mocked_response, + ): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "CNAB400UNICRED_valor_menor_2.RET", + ) + # Se for um codigo cnab de liquidação retorna as account.move criadas. + moves = self._import_file(file_name) + + self.assertEqual("Retorno CNAB - Banco UNICRED - Conta 371", moves.ref) + # I check that the invoice state is "Paid" + self.assertEqual(self.invoice_unicred_1.payment_state, "paid") + + def test_valor_maior_3(self): + mocked_response = [ + { + "codigo_registro": "1", + "codigo_ocorrencia": "02", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000030", + "nosso_numero": self.invoice_unicred_2_own_numbers[0], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000030000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000031000", + "juros_mora": "0000000001000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "1", + "codigo_ocorrencia": "02", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000049", + "nosso_numero": self.invoice_unicred_2_own_numbers[1], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000070000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000071000", + "juros_mora": "0000000001000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "9", + "codigo_ocorrencia": "00", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "0000", + "cedente_com_dv": "000000000", + "convenio": None, + "nosso_numero": "00 00000", + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "000000", + "valor_titulo": "0000000000000", + "banco_recebedor": "00", + "agencia_recebedora_com_dv": "", + "especie_documento": None, + "data_credito": "000000", + "valor_tarifa": "", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "", + "juros_mora": "", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "000016", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + ] + + with mock.patch( + _provider_class + "._get_brcobranca_retorno", + return_value=mocked_response, + ): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "CNAB400UNICRED_valor_maior_3.RET", + ) + # Se não for um codigo cnab de liquidação retorna apenas o LOG criado. + log = self._import_file(file_name) + + self.assertEqual("Banco UNICRED - Conta 371", log.name) + + def test_valor_maior_4(self): + mocked_response = [ + { + "codigo_registro": "1", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000110", + "nosso_numero": self.invoice_unicred_2_own_numbers[0], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000030000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000031000", + "juros_mora": "0000000001000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "1", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + # "nosso_numero": "00000000000000129", + "nosso_numero": self.invoice_unicred_2_own_numbers[1], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "060720", + "valor_titulo": "0000000070000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "060720", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000071000", + "juros_mora": "0000000001000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "9", + "codigo_ocorrencia": "00", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "0000", + "cedente_com_dv": "000000000", + "convenio": None, + "nosso_numero": "00 00000", + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "000000", + "valor_titulo": "0000000000000", + "banco_recebedor": "00", + "agencia_recebedora_com_dv": "", + "especie_documento": None, + "data_credito": "000000", + "valor_tarifa": "", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "", + "juros_mora": "", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "000016", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + ] + + with mock.patch( + _provider_class + "._get_brcobranca_retorno", + return_value=mocked_response, + ): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "CNAB400UNICRED_valor_maior_4.RET", + ) + # Se for um codigo cnab de liquidação retorna as account.move criadas + moves = self._import_file(file_name) + + self.assertEqual("Retorno CNAB - Banco UNICRED - Conta 371", moves.ref) + # I check that the invoice state is "Paid" + self.assertEqual(self.invoice_unicred_2.payment_state, "paid") + + def test_ailos_return(self): + mocked_response = [ + { + "codigo_registro": "03", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + "nosso_numero": "00000000000" + self.invoice_ailos_1_own_numbers[0], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "06072021", + "valor_titulo": "0000000030000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "06072021", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000030000", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "03", + "codigo_ocorrencia": "06", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "1234", + "cedente_com_dv": "000003719", + "convenio": None, + "nosso_numero": "00000000000" + self.invoice_ailos_1_own_numbers[1], + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "06072021", + "valor_titulo": "0000000070000", + "banco_recebedor": "136", + "agencia_recebedora_com_dv": "12343", + "especie_documento": None, + "data_credito": "06072021", + "valor_tarifa": "0000180", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "0000000070000", + "juros_mora": "0000000000000", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "00000", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + { + "codigo_registro": "9", + "codigo_ocorrencia": "00", + "data_ocorrencia": None, + "agencia_com_dv": None, + "agencia_sem_dv": "0000", + "cedente_com_dv": "000000000", + "convenio": None, + "nosso_numero": "00 00000", + "tipo_cobranca": None, + "tipo_cobranca_anterior": None, + "natureza_recebimento": None, + "carteira_variacao": None, + "desconto": "0000000", + "iof": None, + "carteira": None, + "comando": None, + "data_liquidacao": None, + "data_vencimento": "00000000", + "valor_titulo": "0000000000000", + "banco_recebedor": "00", + "agencia_recebedora_com_dv": "", + "especie_documento": None, + "data_credito": "00000000", + "valor_tarifa": "", + "outras_despesas": None, + "juros_desconto": None, + "iof_desconto": None, + "valor_abatimento": "0000000000000", + "desconto_concedito": None, + "valor_recebido": "", + "juros_mora": "", + "outros_recebimento": None, + "abatimento_nao_aproveitado": None, + "valor_lancamento": None, + "indicativo_lancamento": None, + "indicador_valor": None, + "valor_ajuste": None, + "sequencial": "000016", + "arquivo": None, + "motivo_ocorrencia": [], + "documento_numero": None, + }, + ] + # Verifica se a fatura está aberta, antes de fazer o retorno. + self.assertEqual(self.invoice_ailos_1.state, "posted") + + self.journal = self.env.ref("l10n_br_account_payment_order.ailos_journal") + + with mock.patch( + _provider_class + "._get_brcobranca_retorno", + return_value=mocked_response, + ): + file_name = get_resource_path( + "l10n_br_account_payment_brcobranca", + "tests", + "data", + "CNAB240AILOS.RET", + ) + + # Se for um codigo cnab de liquidação retorna as account.move criadas + moves = self._import_file(file_name) + + self.assertEqual( + "Retorno CNAB - Banco COOP CENTRAL AILOS - Conta 373", moves.ref + ) + # I check that the invoice state is "Paid" + self.assertEqual(self.invoice_ailos_1.payment_state, "paid") diff --git a/l10n_br_account_payment_brcobranca/views/account_journal_view.xml b/l10n_br_account_payment_brcobranca/views/account_journal_view.xml new file mode 100644 index 000000000000..5bf7833e32d4 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/views/account_journal_view.xml @@ -0,0 +1,18 @@ + + + + + account.journal.form + account.journal + + + + + + + + + diff --git a/l10n_br_account_payment_brcobranca/wizard/__init__.py b/l10n_br_account_payment_brcobranca/wizard/__init__.py new file mode 100644 index 000000000000..9c87e3439709 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/wizard/__init__.py @@ -0,0 +1 @@ +from . import import_statement diff --git a/l10n_br_account_payment_brcobranca/wizard/import_statement.py b/l10n_br_account_payment_brcobranca/wizard/import_statement.py new file mode 100644 index 000000000000..40f50594f9f7 --- /dev/null +++ b/l10n_br_account_payment_brcobranca/wizard/import_statement.py @@ -0,0 +1,54 @@ +# Copyright 2020 Akretion +# @author Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class CreditPartnerStatementImporter(models.TransientModel): + _inherit = "credit.statement.import" + + def import_statement(self): + """This Function import credit card agency statement""" + moves = self.env["account.move"] + cnab_logs = self.env["l10n_br_cnab.return.log"] + for importer in self: + journal = importer.journal_id + ftype = importer._check_extension() + result = journal.with_context( + file_name=importer.file_name + ).multi_move_import(importer.input_statement, ftype.replace(".", "")) + if len(result) > 1 or result._name == "account.move": + moves |= result + if result._name == "l10n_br_cnab.return.log": + cnab_logs |= result + + if moves: + action = self.env["ir.actions.act_window"]._for_xml_id( + "account.action_move_journal_line" + ) + if len(moves) > 1: + action["domain"] = [("id", "in", moves.ids)] + ref = self.env.ref("account.view_move_tree") + action["views"] = [(ref.id, "tree")] + action["res_id"] = moves.ids[0] if moves else False + # Removendo Filtros da Visão, valor padrão vem + # {'search_default_misc_filter':1, 'view_no_maturity': True} + action["context"] = {"view_no_maturity": True} + else: + ref = self.env.ref("account.view_move_form") + action["views"] = [(ref.id, "form")] + action["res_id"] = moves.id if moves else False + return action + else: + action = self.env["ir.actions.act_window"]._for_xml_id( + "l10n_br_account_payment_order.l10n_br_cnab_return_log_action" + ) + if len(cnab_logs) > 1: + action["domain"] = [("id", "in", cnab_logs.id)] + ref = self.env.ref( + "l10n_br_account_payment_order.l10n_br_cnab_return_log_form_view" + ) + action["views"] = [(ref.id, "form")] + action["res_id"] = cnab_logs.id if cnab_logs else False + return action diff --git a/l10n_br_account_payment_brcobranca/wizard/import_statement_view.xml b/l10n_br_account_payment_brcobranca/wizard/import_statement_view.xml new file mode 100644 index 000000000000..1b0c256b94be --- /dev/null +++ b/l10n_br_account_payment_brcobranca/wizard/import_statement_view.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/setup/l10n_br_account_payment_brcobranca/odoo/addons/l10n_br_account_payment_brcobranca b/setup/l10n_br_account_payment_brcobranca/odoo/addons/l10n_br_account_payment_brcobranca new file mode 120000 index 000000000000..51964d0c64d1 --- /dev/null +++ b/setup/l10n_br_account_payment_brcobranca/odoo/addons/l10n_br_account_payment_brcobranca @@ -0,0 +1 @@ +../../../../l10n_br_account_payment_brcobranca \ No newline at end of file diff --git a/setup/l10n_br_account_payment_brcobranca/setup.py b/setup/l10n_br_account_payment_brcobranca/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/l10n_br_account_payment_brcobranca/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)