示例#1
0
 def test_load_return_file(self):
     file_ = codecs.open(self.path_to_file, encoding='ascii')
     loaded_cnab = File(santander)
     loaded_cnab.load_return_file(file_)
     file_.seek(0)
     self.assertEqual(file_.read().replace('\n', '\r\n'), str(loaded_cnab))
     file_.close()
示例#2
0
 def setUp(self):
     self.data = get_data_from_file()
     self.file = File(santander)
     self.file.add_header(self.data['HeaderArquivo'])
     self.file.add_segment('HeaderLote', self.data['HeaderLote'])
     self.file.add_segment('SegmentoJ', self.data['SegmentoJ'])
     self.path_to_file = os.path.join(ARQS_DIRPATH, 'santander.rem')
     self.comparison_file = open(self.path_to_file, 'r').read().split('\n')
示例#3
0
    def _get_account(self, cnab_file):
        if self.cnab_type != 'payable':
            return super(l10nBrPaymentCnabImport, self)._get_account(cnab_file)

        stream = StringIO(cnab_file.decode('ascii'))
        bank = get_bank(self.journal_id.bank_id.bic)
        cnab = File(bank)
        cnab.load_return_file(stream)
        return cnab.header.cedente_conta, cnab.header.cedente_agencia
示例#4
0
class TestPyCnab240(unittest.TestCase):
    def setUp(self):
        self.data = get_data_from_file()
        self.file = File(santander)
        self.file.add_header(self.data['HeaderArquivo'])
        self.file.add_segment('HeaderLote', self.data['HeaderLote'])
        self.file.add_segment('SegmentoJ', self.data['SegmentoJ'])
        self.path_to_file = os.path.join(ARQS_DIRPATH, 'santander.rem')
        self.comparison_file = open(self.path_to_file, 'r').read().split('\n')

    def test_add_header(self):
        self.assertEqual(self.comparison_file[0], str(self.file.header))

    def test_add_segment(self):
        self.assertEqual(self.comparison_file[1],
                         str(self.file.get_active_lot().header))
        self.assertEqual(
            self.comparison_file[2],
            str(self.file.get_active_lot().get_active_event(None).segments[0]))

    def test_close_file(self):
        self.file.close_file()
        self.assertEqual(3, self.file.lots[0].trailer.quantidade_registros)
        self.assertEqual(1, self.file.trailer.totais_quantidade_lotes)
        self.assertEqual(5, self.file.trailer.totais_quantidade_registros)

    def test_str(self):
        self.file.close_file()
        self.assertEqual(str(self.file), '\r\n'.join(self.comparison_file))

    def test_load_return_file(self):
        file_ = codecs.open(self.path_to_file, encoding='ascii')
        loaded_cnab = File(santander)
        loaded_cnab.load_return_file(file_)
        file_.seek(0)
        self.assertEqual(file_.read().replace('\n', '\r\n'), str(loaded_cnab))
        file_.close()
示例#5
0
    def do_import(self, cnab_file):
        if self.cnab_type != 'payable':
            return super(l10nBrPaymentCnabImport, self).do_import(cnab_file)

        stream = StringIO(cnab_file.decode('ascii'))
        bank = get_bank(self.journal_id.bank_id.bic)
        account, bra_number = self._get_account(cnab_file)
        loaded_cnab = File(bank)
        loaded_cnab.load_return_file(stream)

        statement = self.env['l10n_br.payment.statement'].sudo().create({
            'journal_id':
            self.journal_id.id,
            'date':
            date.today(),
            'company_id':
            self.journal_id.company_id.id,
            'name':
            self.journal_id.l10n_br_sequence_statements.next_by_id(),
            'type':
            'payable',
        })
        for lot in loaded_cnab.lots:
            for event in lot.events:
                payment_line = self.env['payment.order.line'].search([
                    ('nosso_numero', '=', event.numero_documento_cliente),
                    ('journal_id', '=', self.journal_id.id),
                    ('type', '=', 'payable')
                ])

                cnab_code = event.ocorrencias_retorno[:2]
                message = self._get_message(self.journal_id.bank_id.bic,
                                            event.ocorrencias_retorno.strip())
                if not payment_line:
                    nome = ''
                    if hasattr(event, 'favorecido_nome'):
                        nome = event.favorecido_nome
                    elif hasattr(event, 'nome_concessionaria'):
                        nome = event.nome_concessionaria
                    elif hasattr(event, 'contribuinte_nome'):
                        nome = event.contribuinte_nome

                    self.env['l10n_br.payment.statement.line'].sudo().create({
                        'date':
                        datetime.strptime("{:08}".format(event.data_pagamento),
                                          "%d%m%Y"),
                        'nosso_numero':
                        event.numero_documento_cliente,
                        'name':
                        nome,
                        'amount':
                        event.valor_pagamento,
                        'cnab_code':
                        cnab_code,
                        'cnab_message':
                        message,
                        'statement_id':
                        statement.id,
                        'ignored':
                        True,
                    })
                    continue
                protocol = autentication = None
                if hasattr(event, 'protocolo_pagamento'):
                    protocol = event.protocolo_pagamento
                if hasattr(event, 'autenticacao_pagamento'):
                    autentication = event.autenticacao_pagamento
                self.select_routing(payment_line,
                                    cnab_code,
                                    bank,
                                    message,
                                    statement,
                                    protocolo=protocol,
                                    autenticacao=autentication)

        action = self.env.ref(
            'br_account_payment.action_payment_statement_tree')
        return action.read()[0]
示例#6
0
 def __init__(self):
     self._cnab_file = File(self._bank)
示例#7
0
class Cnab_240(object):
    def _hour_now(self):
        return (int(datetime.now().strftime("%H%M%S")[0:4]))

    def _string_to_monetary(self, numero, precision=2):
        frmt = '{:.%df}' % precision
        return Decimal(frmt.format(numero))

    def _float_to_monetary(self, number, precision=2):
        return Decimal(str(number)).quantize(Decimal('0.01'))

    def _just_numbers(self, value):
        return re.sub('[^0-9]', '', str(value or ''))

    def _string_to_num(self, toTransform, default=None):
        if not toTransform:
            return default or 0
        value = re.sub('[^0-9]', '', str(toTransform))
        if not value:
            return default or 0
        try:
            return int(value)
        except ValueError:
            if default is not None:
                return default
            else:
                raise

    def format_date(self, date_value):
        if not date_value:
            return ''
        if not isinstance(date_value, (date, datetime)):
            date_value = datetime.strptime(date_value[0:10], "%Y-%m-%d")
        return date_value.strftime("%d%m%Y")

    def is_doc_or_ted(self, op):
        if op == '01' or op == '02':
            return True
        return False

    def _get_header_arq(self):
        bank = self._order.src_bank_account_id
        headerArq = {
            'cedente_inscricao_tipo':
            2,  # 0 = Isento, 1 = CPF, 2 = CNPJ
            # número do registro da empresa
            'cedente_inscricao_numero':
            self._string_to_num(self._order.company_id.cnpj_cpf),
            # Usado pelo Banco para identificar o contrato - númerodo banco(4),
            # códigode agência(4 "sem DV"), número do convênio(12).
            'codigo_convenio':
            bank.l10n_br_convenio_pagamento,
            'cedente_agencia':
            self._string_to_num(bank.bra_number, 0),
            'cedente_agencia_dv':
            bank.bra_number_dig,
            'cedente_conta':
            self._string_to_num(bank.acc_number),
            'cedente_conta_dv':
            bank.acc_number_dig,
            'cedente_nome':
            self._order.company_id.legal_name[:30],
            'data_geracao_arquivo':
            int(self.format_date(date.today())),
            'hora_geracao_arquivo':
            self._hour_now(),
            'numero_sequencial_arquivo':
            self._order.file_number,
        }
        return headerArq

    def _get_segmento(self, line, lot_sequency, num_lot, nome_segmento):
        information_id = line.payment_information_id
        segmento = {
            'numero_parcela': str(information_id.numero_parcela_icms),
            'divida_ativa_etiqueta': str(information_id.divida_ativa_etiqueta),
            "cedente_inscricao_numero": self._string_to_num(
                self._order.company_id.cnpj_cpf),
            "identificador_fgts": information_id.identificacao_fgts,
            "lacre_conectividade_social": information_id.conec_social_fgts,
            "lacre_conectividade_social_dv":
                information_id.conec_social_dv_fgts,
            "controle_lote": num_lot,
            "sequencial_registro_lote": lot_sequency,
            "tipo_movimento": information_id.mov_type,
            "codigo_instrucao_movimento": information_id.mov_instruc,
            "codigo_camara_compensacao": information_id.operation_code,
            # adicionar campo para o banco do clinte com um valor default
            "favorecido_codigo_banco": line.bank_account_id.bank_id.name,
            "favorecido_banco": int(line.bank_account_id.bank_id.bic),
            "favorecido_agencia": line.bank_account_id.bra_number,
            "favorecido_agencia_dv": line.bank_account_id.bra_number_dig or '',
            "favorecido_conta": line.bank_account_id.acc_number,
            "favorecido_conta_dv": line.bank_account_id.acc_number_dig or '',
            "favorecido_agencia_conta_dv": '',
            "favorecido_nome":
            line.partner_id.legal_name or line.partner_id.name,
            "favorecido_doc_numero": line.partner_id.cnpj_cpf,
            "numero_documento_cliente": line.nosso_numero,
            "data_pagamento": int(self.format_date(line.date_maturity)),
            "valor_pagamento": self._float_to_monetary(line.amount_total),
            "data_real_pagamento": int(self.format_date(
                self._order.data_emissao_cnab)),
            "valor_real_pagamento": self._float_to_monetary(line.value_final),
            "mensagem2": information_id.message2 or '',
            "finalidade_doc_ted": information_id.mov_finality or '',
            "favorecido_emissao_aviso_alfa": information_id.warning_code,
            "favorecido_emissao_aviso": int(information_id.warning_code),
            "favorecido_inscricao_tipo":
            2 if line.partner_id.is_company else 1,
            "favorecido_inscricao_numero": self._string_to_num(
                line.partner_id.cnpj_cpf),
            "favorecido_endereco_rua": line.partner_id.street or '',
            "favorecido_endereco_numero": self._string_to_num(
                line.partner_id.number, default=0),
            "favorecido_endereco_complemento": line.partner_id.street2 or '',
            "favorecido_bairro": line.partner_id.district or '',
            "favorecido_cidade": line.partner_id.city_id.name or '',
            "favorecido_cep": self._string_to_num(line.partner_id.zip),
            "cep_complemento": self._just_numbers(line.partner_id.zip[5:]),
            "favorecido_uf": line.partner_id.state_id.code or '',
            "valor_documento": self._float_to_monetary(line.amount_total),
            "valor_abatimento": self._float_to_monetary(
                information_id.rebate_value),
            "valor_desconto": self._float_to_monetary(
                information_id.discount_value),
            "valor_mora": self._float_to_monetary(
                information_id.interest_value),
            "valor_multa": self._float_to_monetary(information_id.fine_value),
            "hora_envio_ted": self._hour_now(),
            "codigo_historico_credito": information_id.credit_hist_code,
            "cedente_nome": self._order.company_id.legal_name[:30],
            "valor_nominal_titulo":  self._float_to_monetary(
                line.amount_total),
            "valor_desconto_abatimento": self._float_to_monetary(
                information_id.rebate_value + information_id.discount_value),
            "valor_multa_juros": self._float_to_monetary(
                information_id.interest_value + information_id.fine_value),
            "codigo_moeda": int(information_id.currency_code),
            "codigo_de_barras": self._string_to_num(line.barcode),
            "codigo_de_barras_alfa": line.barcode or '',
            # TODO Esse campo deve ser obtido a partir do payment_mode_id
            "nome_concessionaria":
            (line.partner_id.legal_name or line.partner_id.name)[:30],
            "data_vencimento": int(self.format_date(line.date_maturity)),
            "valor_juros_encargos": self._string_to_monetary(
                information_id.interest_value),
            # GPS
            "contribuinte_nome": self._order.company_id.legal_name[:30],
            "codigo_receita_tributo": information_id.codigo_receita or '',
            "tipo_identificacao_contribuinte": 1,
            "identificacao_contribuinte": self._string_to_num(
                self._order.company_id.cnpj_cpf),
            "identificacao_contribuinte_alfa": self._just_numbers(
                self._order.company_id.cnpj_cpf),
            "codigo_identificacao_tributo": information_id.tax_identification\
                or '',
            "mes_ano_competencia": self.get_mes_ano_competencia(line),
            "valor_previsto_inss": self._string_to_monetary(line.amount_total),
            # DARF
            "periodo_apuracao": int(self.format_date(line.invoice_date) or 0),
            "valor_principal": self._string_to_monetary(line.amount_total),
            "valor_receita_bruta_acumulada": self._string_to_monetary(
                self._order.company_id.annual_revenue),
            "percentual_receita_bruta_acumulada": self._string_to_monetary(
                information_id.percentual_receita_bruta_acumulada),
            # GARE SP
            'inscricao_estadual': int(self._string_to_num(
                self._order.company_id.inscr_est)),
            'valor_receita': self._string_to_monetary(line.amount_total),
            'numero_referencia': self._string_to_num(
                information_id.numero_referencia),
        }
        return segmento

    def _get_trailer_arq(self):
        trailerArq = {}
        return trailerArq

    def _get_trailer_lot(self, totais, num_lot):
        trailer_lot = {
            "controle_lote": num_lot,
            "somatorio_valores": self._string_to_monetary(totais.get('total'))
        }
        return trailer_lot

    def _get_header_lot(self, line, num_lot, lot):
        information_id = line.payment_information_id
        bank = self._order.src_bank_account_id
        header_lot = {
            "forma_lancamento":
            lot,
            "controle_lote":
            num_lot,
            "tipo_servico":
            int(information_id.service_type),
            "cedente_inscricao_tipo":
            2,
            "cedente_inscricao_numero":
            self._string_to_num(self._order.company_id.cnpj_cpf),
            "codigo_convenio":
            str(bank.l10n_br_convenio_pagamento),
            "cedente_agencia":
            bank.bra_number,
            "cedente_agencia_dv":
            bank.bra_number_dig or '',
            "cedente_conta":
            bank.acc_number,
            "cedente_conta_dv":
            bank.acc_number_dig or '',
            "cedente_nome":
            self._order.company_id.legal_name[:30],
            "mensagem1":
            information_id.message1 or '',
            "cedente_endereco_rua":
            self._order.company_id.street,
            "cedente_endereco_numero":
            self._string_to_num(self._order.company_id.number),
            "cedente_endereco_complemento":
            str(self._order.company_id.street2)[0:15]
            if self._order.company_id.street2 else '',
            "cedente_cidade":
            str(self._order.company_id.city_id.name)[:20]
            if self._order.company_id.city_id.name else '',
            "cedente_cep":
            self._string_to_num(self._order.company_id.zip[:6]),
            "cedente_cep_complemento":
            self._string_to_num(self._order.company_id.zip[6:]),
            "cedente_uf":
            self._order.company_id.state_id.code,
        }
        return header_lot

    def get_operation(self, line):
        bank_origin = line.src_bank_account_id.bank_id.bic
        bank_dest = line.bank_account_id.bank_id.bic
        tit_origin = line.src_bank_account_id.partner_id
        tit_dest = line.bank_account_id.partner_id
        op = line.payment_information_id.payment_type
        return get_operation(bank_origin, bank_dest, tit_origin, tit_dest, op)

    def _ordenate_lines(self, listOfLines):
        operacoes = {}
        for line in listOfLines:
            op = self.get_operation(line)
            if op in operacoes:
                operacoes[op].append(line)
            else:
                operacoes[op] = [line]
        self._lot_qty = len(operacoes)
        return operacoes

    def __init__(self):
        self._cnab_file = File(self._bank)

    def create_cnab(self, listOfLines):
        self._cnab_file.add_header(self._get_header_arq())
        self.create_details(self._ordenate_lines(listOfLines))

    def create_details(self, operacoes):
        num_lot = 1
        for lote, events in operacoes.items():
            self._create_header_lote(events[0], num_lot, lote)
            lot_sequency = 1
            for event in events:
                lot_sequency = self.create_detail(lote, event, lot_sequency,
                                                  num_lot)
            totais_lote = self._sum_lot_values(events)
            self._create_trailer_lote(totais_lote, num_lot)
            num_lot = num_lot + 1

    def _create_header_lote(self, line, num_lot, lot):
        self._cnab_file.add_segment('HeaderLote',
                                    self._get_header_lot(line, num_lot, lot))

    def create_detail(self, operation, event, lot_sequency, num_lot):
        segments = self.segments_per_operation().get(operation, [])
        if not segments:
            raise Exception(
                'Pelo menos um segmento por tipo deve ser implementado!')
        for nome_segmento in segments:
            vals = self._get_segmento(event, lot_sequency, num_lot,
                                      nome_segmento)
            if vals is not None:
                self._cnab_file.add_segment(nome_segmento, vals)
            lot_sequency += 1
        self._cnab_file.get_active_lot().get_active_event(None).close_event()
        return lot_sequency

    def segments_per_operation(self):
        return {
            "01": ["SegmentoA", "SegmentoB"],
            "03": ["SegmentoA", "SegmentoB"],
        }

    def _get_trailer_lot_name(self):
        return 'TrailerLote'

    def _create_trailer_lote(self, totais, num_lot):
        seg_name = self._get_trailer_lot_name()
        self._cnab_file.add_segment(seg_name,
                                    self._get_trailer_lot(totais, num_lot))
        self._cnab_file.get_active_lot().close_lot()

    def _generate_file(self):
        arquivo = StringIO()
        self._cnab_file.write_to_file(arquivo)
        return arquivo.getvalue()

    def write_cnab(self):
        self._cnab_file.add_trailer(self._get_trailer_arq())
        self._cnab_file.close_file()
        return self._generate_file().encode()

    def _sum_lot_values(self, lot):
        total = 0
        for line in lot:
            total = total + line.value_final
        return {'total': total}

    def get_mes_ano_competencia(self, line):
        if not line.invoice_date:
            return 0
        return int(line.invoice_date.strftime('%m%y'))