Trust-Code/odoo-brasil

View on GitHub
br_cnab/febraban/cnab_240/cnab_240.py

Summary

Maintainability
A
3 hrs
Test Coverage
# -*- coding: utf-8 -*-
# © 2015 Luis Felipe Mileo
#        Fernando Marcato Rodrigues
#        Daniel Sadamo Hirayama
#        KMEE - www.kmee.com.br
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from ..cnab import Cnab
from decimal import Decimal
import datetime
import re
import string
import time
import logging

_logger = logging.getLogger(__name__)

try:
    from cnab240.tipos import Arquivo
except ImportError:
    _logger.debug('Cannot import cnab240')


class Cnab240(Cnab):

    def __init__(self):
        super(Cnab, self).__init__()

    @staticmethod
    def get_bank(bank):
        if bank == '237':
            from .bancos.bradesco import Bradesco240
            return Bradesco240
        elif bank == '756':
            from .bancos.sicoob import Sicoob240
            return Sicoob240
        elif bank == '001':
            from .bancos.banco_brasil import BancoBrasil240
            return BancoBrasil240
        elif bank == '0851':
            from .bancos.cecred import Cecred240
            return Cecred240
        elif bank == '341':
            from .bancos.itau import Itau240
            return Itau240
        elif bank == '033':
            from .bancos.santander import Santander240
            return Santander240
        elif bank == '104':
            from .bancos.cef import Cef240
            return Cef240
        elif bank == '748':
            from .bancos.sicredi import Sicredi240
            return Sicredi240
        else:
            return Cnab240

    @property
    def inscricao_tipo(self):
        if self.order.payment_mode_id.bank_account_id.partner_id.is_company:
            return 2
        else:
            return 1

    def _prepare_header(self):
        cnpj_cpf = re.sub('[^0-9]', '',
                          self.order.payment_mode_id.company_id.cnpj_cpf)
        cedente_conta_dv = self.order.payment_mode_id.bank_account_id.\
            acc_number_dig
        cedente_conta_dv = str(cedente_conta_dv)
        return {
            'controle_banco': int(self.order.payment_mode_id.
                                  bank_account_id.bank_bic),
            'arquivo_data_de_geracao': self.data_hoje(),
            'arquivo_hora_de_geracao': self.hora_agora(),
            'arquivo_sequencia': self.order.file_number,
            'cedente_inscricao_tipo': self.inscricao_tipo,
            'cedente_inscricao_numero': int(cnpj_cpf),
            'cedente_agencia': int(
                self.order.payment_mode_id.bank_account_id.bra_number),
            'cedente_conta': int(self.order.payment_mode_id.bank_account_id.
                                 acc_number),
            'cedente_conta_dv': cedente_conta_dv,
            'cedente_convenio': self.order.payment_mode_id.bank_account_id.
            codigo_convenio,
            'cedente_agencia_dv': self.order.payment_mode_id.
            bank_account_id.bra_number_dig,
            'cedente_nome': self.order.payment_mode_id.company_id.legal_name,
            # DV ag e conta
            'cedente_dv_ag_cc': (self.order.payment_mode_id.
                                 bank_account_id.bra_number_dig),
            'arquivo_codigo': 1,  # Remessa/Retorno
            'servico_operacao': u'R',
            'nome_banco': unicode(self.order.payment_mode_id.bank_account_id.
                                  bank_name)
        }

    def get_file_numeration(self):
        numero = False  # self.order.get_next_number()
        if not numero:
            numero = 1
        return numero

    def format_date(self, srt_date):
        return int(datetime.datetime.strptime(
            srt_date, '%Y-%m-%d').strftime('%d%m%Y'))

    def nosso_numero(self, format):
        pass

    def cep(self, format):
        cep = re.sub('[^0-9]', '', format or '')
        sulfixo = cep[-3:]
        prefixo = cep[:5]
        return prefixo, sulfixo

    def sacado_inscricao_tipo(self, partner_id):
        # TODO: Implementar codigo para PIS/PASEP
        if partner_id.is_company:
            return 2
        else:
            return 1

    def rmchar(self, format):
        return re.sub('[%s]' % re.escape(string.punctuation), '',
                      format or '')

    def _prepare_segmento(self, line):
        prefixo, sulfixo = self.cep(line.partner_id.zip)

        # if not self.order.payment_mode_id.boleto_aceite == 'S':
        #    aceite = u'A'

        # Código agencia do cedente
        # cedente_agencia = cedente_agencia

        # Dígito verificador da agência do cedente
        # cedente_agencia_conta_dv = cedente_agencia_dv

        # Código da conta corrente do cedente
        # cedente_conta = cedente_conta

        # Dígito verificador da conta corrente do cedente
        # cedente_conta_dv = cedente_conta_dv

        # Dígito verificador de agencia e conta
        # Era cedente_agencia_conta_dv agora é cedente_dv_ag_cc

        return {
            'controle_banco': int(self.order.payment_mode_id.bank_account_id.
                                  bank_bic),
            'cedente_agencia': int(self.order.payment_mode_id.bank_account_id.
                                   bra_number),
            'cedente_conta': int(self.order.payment_mode_id.bank_account_id.
                                 acc_number),
            'cedente_conta_dv': self.order.payment_mode_id.bank_account_id.
            acc_number_dig,
            'cedente_convenio': self.order.payment_mode_id.bank_account_id.
            codigo_convenio,
            'cedente_agencia_dv': self.order.payment_mode_id.bank_account_id.
            bra_number_dig,
            'cedente_nome':
            self.order.payment_mode_id.bank_account_id.partner_id.legal_name,
            # DV ag e cc
            'cedente_dv_ag_cc': (self.order.payment_mode_id.bank_account_id.
                                 bra_number_dig),
            'identificacao_titulo': u'0000000',  # TODO
            'identificacao_titulo_banco': u'0000000',  # TODO
            'identificacao_titulo_empresa': (' ' * 25),
            'numero_documento': "%s/%s" % (line.move_id.name, line.name),
            'vencimento_titulo': self.format_date(
                line.date_maturity),
            'valor_titulo': Decimal(str(line.debit)).quantize(
                Decimal('1.00')),
            # TODO: Código adotado para identificar o título de cobrança.
            # 8 é Nota de cŕedito comercial
            'especie_titulo': int(self.order.payment_mode_id.boleto_especie),
            'aceite_titulo': self.order.payment_mode_id.boleto_aceite,
            'data_emissao_titulo': self.format_date(
                line.date),
            # Taxa de juros do Odoo padrão mensal: 2. Campo 27.3P
            # CEF/FEBRABAN e Itaú não tem.
            'codigo_juros': 2,
            'juros_mora_data': self.format_date(
                line.date_maturity),
            'juros_mora_taxa':  Decimal(
                str(self.order.payment_mode_id.late_payment_interest)
                ).quantize(Decimal('1.00')),
            # Multa padrão em percentual no Odoo, valor '2'
            'codigo_multa': '2',
            'data_multa': self.format_date(
                line.date_maturity),
            'juros_multa': Decimal(
                str(self.order.payment_mode_id.late_payment_fee)).quantize(
                    Decimal('1.00')),
            # TODO Remover taxa dia - deixar apenas taxa normal
            'juros_mora_taxa_dia': Decimal('0.00'),
            'valor_abatimento': Decimal('0.00'),
            'sacado_inscricao_tipo': int(
                self.sacado_inscricao_tipo(line.partner_id)),
            'sacado_inscricao_numero': int(
                self.rmchar(line.partner_id.cnpj_cpf)),
            'sacado_nome': line.partner_id.legal_name or line.partner_id.name,
            'sacado_endereco': (
                line.partner_id.street + ' ' + line.partner_id.number),
            'sacado_bairro': line.partner_id.district,
            'sacado_cep': int(prefixo),
            'sacado_cep_sufixo': int(sulfixo),
            'sacado_cidade': line.partner_id.city_id.name,
            'sacado_uf': line.partner_id.state_id.code,
            'codigo_protesto': int(self.order.payment_mode_id.boleto_protesto),
            'prazo_protesto': int(
                self.order.payment_mode_id.boleto_protesto_prazo),
            'codigo_baixa': 2,
            'prazo_baixa': 0,  # De 5 a 120 dias.
            'controlecob_data_gravacao': self.data_hoje(),
            'cobranca_carteira': int(
                self.order.payment_mode_id.boleto_carteira[:2]),
        }

    def remessa(self, order):
        cobrancasimples_valor_titulos = 0

        self.order = order
        header = self._prepare_header()
        self.arquivo = Arquivo(self.bank, **header)
        for line in order.line_ids:
            seg = self._prepare_segmento(line.move_line_id)
            self.arquivo.incluir_cobranca(header, **seg)
            self.arquivo.lotes[0].header.servico_servico = 1
            # TODO: tratar soma de tipos de cobranca
            cobrancasimples_valor_titulos += line.move_line_id.amount_currency
            self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \
                Decimal(cobrancasimples_valor_titulos).quantize(
                    Decimal('1.00'))

        return unicode(self.arquivo)

    def data_hoje(self):
        return (int(time.strftime("%d%m%Y")))

    def hora_agora(self):
        return (int(time.strftime("%H%M%S")))