class TestCnab240(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestCnab240, self).__init__(*args, **kwargs) self.maxDiff = None def setUp(self): self.itau_data = get_itau_data_from_dict() self.arquivo = Arquivo(itau, **self.itau_data['arquivo']) def test_unicode(self): self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) self.assertEqual(str(self.arquivo), get_itau_file_remessa()) def test_empty_data(self): arquivo = Arquivo(itau) self.assertRaises(errors.ArquivoVazioError, str, arquivo) def test_leitura(self): return_file_path = os.path.join(ARQS_DIRPATH, 'cobranca.itau.ret') ret_file = codecs.open(return_file_path, encoding='ascii') arquivo = Arquivo(itau, arquivo=ret_file) ret_file.seek(0) self.assertEqual(ret_file.read(), str(arquivo)) ret_file.close()
def remessa(self, order): """ :param order: :return: """ cobrancasimples_valor_titulos = 0 self.order = order header = self._prepare_header() self.arquivo = Arquivo(self.bank, **header) for line in order.line_ids: if line.payment_mode_id.bank_account_id.bank_id.bic == '755': self.nosso_numero_with_dv = line.nosso_numero + line.nosso_numero_dv else: self.nosso_numero_with_dv = line.nosso_numero print self.nosso_numero print self.nosso_numero_with_dv seg = self._prepare_segmento(line.move_line_id) print seg 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 montarArquivoNC_IDS(self, cr, uid, ids, context=None): # str = unicode(arquivo) # f = open('/tmp/arquivo_remessa.rem','w') # f.write(str) # python will convert \n to os.linesep # f.close() res = {} cnab_data = dict() # Header values dict_arquivo = self.get_header_data(cr, uid, ids, context) dict_salvar = dict_arquivo cnab_data['arquivo'] = dict_arquivo arquivo = Arquivo(cef, **cnab_data['arquivo']) # Segmentos nossa_classe_pool = self.pool.get('l10n_br_account.payment_receivable') segmento_pool = self.pool.get('cnab240export.segmentos') nossa_classe_ids = [] arquivo.lotes[0].header.servico_servico = 1 for nc_ids in nossa_classe_ids: # Para os dados de cada "nossa_classe_line" e correspondente # "move_line", inclua os segmentos P e Q. id_segmento = segmento_pool.create(cr, uid, context=None) segmento_cobranca = segmento_pool.write_segmentos(cr, uid, id_segmento, nc_ids, context) cnab_data['cobranca'] = segmento_cobranca arquivo.incluir_cobranca(**cnab_data['cobranca']) self.salva_dados(cr, uid, ids, dict_salvar, context) return res
class TestCnab240(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestCnab240, self).__init__(*args, **kwargs) self.maxDiff = None def setUp(self): self.itau_data = get_itau_data_from_dict() self.arquivo = Arquivo(itau, **self.itau_data['arquivo']) def test_unicode(self): self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) self.assertEqual(str(self.arquivo), get_itau_file_remessa()) def test_empty_data(self): arquivo = Arquivo(itau) self.assertRaises(errors.ArquivoVazioError, str, arquivo) def test_leitura_itau(self): return_file_path = os.path.join(ARQS_DIRPATH, 'cobranca.itau.ret') ret_file = codecs.open(return_file_path, encoding='ascii') arquivo = Arquivo(itau, arquivo=ret_file) ret_file.seek(0) self.assertEqual(ret_file.read(), str(arquivo)) ret_file.close()
def remessa(self, order): """ :param order: :return: """ cobrancasimples_valor_titulos = 0 self.order = order header = self._prepare_header() self.arquivo = Arquivo(self.bank, **header) # for line in order.line_ids: if line.validate_line_to_export(): 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.value self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) year = str(datetime.datetime.now().year)[2:] # add year in nosso_numero because we pass it to bank # and this is used to loacate payment order line while # importing bank return if line.nosso_numero[:2] != year: line.nosso_numero = year + str(line.nosso_numero) line.state = 'ag' return unicode(self.arquivo)
def montarArquivoNC_IDS(self, cr, uid, ids, context=None): # str = unicode(arquivo) # f = open('/tmp/arquivo_remessa.rem','w') # f.write(str) # python will convert \n to os.linesep # f.close() res = {} cnab_data = dict() # Header values dict_arquivo = self.get_header_data(cr, uid, ids, context) dict_salvar = dict_arquivo cnab_data['arquivo'] = dict_arquivo arquivo = Arquivo(cef, **cnab_data['arquivo']) # Segmentos nossa_classe_pool = self.pool.get('l10n_br_account.payment_receivable') segmento_pool = self.pool.get('cnab240export.segmentos') nossa_classe_ids = [] arquivo.lotes[0].header.servico_servico = 1 for nc_ids in nossa_classe_ids: # Para os dados de cada "nossa_classe_line" e correspondente # "move_line", inclua os segmentos P e Q. id_segmento = segmento_pool.create(cr, uid, context=None) segmento_cobranca = segmento_pool.write_segmentos( cr, uid, id_segmento, nc_ids, context) cnab_data['cobranca'] = segmento_cobranca arquivo.incluir_cobranca(**cnab_data['cobranca']) self.salva_dados(cr, uid, ids, dict_salvar, context) return res
def processa_pagamentos(data): arquivo = Arquivo(banco_brasil, **data) pagamentos = data.get('pagamentos') valor_total = Decimal(0.0) # "arquivo_data_de_geracao": "01041990", # "arquivo_hora_de_geracao": "235959", for pagamento in pagamentos: arquivo.incluir_pagamentos_diversos(**data, **pagamento) valor_total += Decimal(pagamento.get('valor', 0.0)) arquivo.lotes[0].trailer.somatorio_valor = valor_total return str(arquivo)
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 str(self.arquivo)
def test_leitura(self): return_file_path = os.path.join(ARQS_DIRPATH, 'cobranca.itau.ret') ret_file = codecs.open(return_file_path, encoding='ascii') arquivo = Arquivo(itau, arquivo=ret_file) ret_file.seek(0) self.assertEqual(ret_file.read(), str(arquivo)) ret_file.close()
def _parse(self, *args, **kwargs): """Launch the parsing itself.""" cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.seek(0) cnab240_file.write(self.filebuffer) cnab240_file.flush() ret_file = codecs.open(cnab240_file.name, encoding='ascii') arquivo = Arquivo(cef, arquivo=ret_file) cnab240_file.close() res = [] for lote in arquivo.lotes: for evento in lote.eventos: res.append({ 'name': evento.sacado_nome, 'date': datetime.datetime.strptime( str(evento.vencimento_titulo), '%d%m%Y'), 'amount': evento.valor_titulo, 'ref': evento.numero_documento, 'label': evento.sacado_inscricao_numero, # cnpj 'transaction_id': evento.nosso_numero_identificacao, # nosso numero 'commission_amount': evento.valor_tarifas, }) self.result_row_list = res return True
def _get_account(self, cnab_file): if self.cnab_type != 'receivable': return super(L10nBrPaymentCnabImport, self)._get_account(cnab_file) stream = StringIO(cnab_file.decode('ascii')) bank = get_bank(self.journal_id.bank_id.bic) cnab = Arquivo(bank, arquivo=stream) return cnab.header.cedente_conta, cnab.header.cedente_agencia
def _check_cnab(self, data_file, raise_error=False): try: cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() Arquivo(sicoob, arquivo=open(cnab240_file.name, 'r')) return True except Exception as e: if raise_error: raise UserError(u"Arquivo formato inválido:\n%s" % str(e)) return False
def remessa(self, order): """ :param order: :return: """ cobrancasimples_valor_titulos = 0 self.order = order self.arquivo = Arquivo(self.bank, **self._prepare_header()) for line in order.line_ids: self.arquivo.incluir_cobranca(**self._prepare_segmento(line)) self.arquivo.lotes[0].header.servico_servico = 1 # TODO: tratar soma de tipos de cobranca cobrancasimples_valor_titulos += line.amount_currency # fixed 'quantidade_registros' in trailer to 000001 self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore')
def remessa(self, header, lista_boletos): """ :param order: :return: """ cobrancasimples_valor_titulos = Decimal(0.00) self.arquivo = Arquivo(self.bank, **self._prepare_header(**header)) for line in lista_boletos: self.arquivo.incluir_cobranca(**self._prepare_segmento(line)) self.arquivo.lotes[0].header.servico_servico = 1 # TODO: tratar soma de tipos de cobranca # TODO: Verificar se é o valor do documento ou o valor cobrancasimples_valor_titulos += Decimal(line.valor_documento) self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore')
def _parse_cnab(self, data_file, raise_error=False): cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() arquivo = Arquivo(sicoob, arquivo=open(cnab240_file.name, 'r')) transacoes = [] for lote in arquivo.lotes: for evento in lote.eventos: valor = evento.valor_lancamento if evento.tipo_lancamento == 'D': valor *= -1 transacoes.append({ 'name': evento.descricao_historico, 'date': datetime.strptime(str(evento.data_lancamento), '%d%m%Y'), 'amount': valor, 'partner_name': evento.cedente_nome, 'ref': evento.numero_documento, 'unique_import_id': str(evento.servico_numero_registro), }) header = arquivo.lotes[0].header trailer = arquivo.lotes[0].trailer inicio = datetime.strptime(str(header.data_saldo_inicial), '%d%m%Y') final = datetime.strptime(str(trailer.data_saldo_final), '%d%m%Y') vals_bank_statement = { 'name': u"%s - %s até %s" % (arquivo.header.nome_do_banco, inicio.strftime('%d/%m/%Y'), final.strftime('%d/%m/%Y')), 'date': inicio, 'balance_start': arquivo.lotes[0].header.valor_saldo_inicial, 'balance_end_real': arquivo.lotes[0].trailer.valor_saldo_final, 'transactions': transacoes } account_number = str(arquivo.header.cedente_conta) if self.force_journal_account: account_number = self.journal_id.bank_acc_number return (arquivo.lotes[0].header.moeda, account_number, [vals_bank_statement])
def remessa(self, order): """ :param order: :return: """ pag_valor_titulos = 0 self.order = order self.arquivo = Arquivo(self.bank, **self._prepare_header()) cont_lote = 0 for line in order.line_ids: self.arquivo.incluir_pagamento(**self.incluir_pagamento_for(line)) pag_valor_titulos += line.amount_currency self.arquivo.trailer.total_valor_arq = Decimal( pag_valor_titulos).quantize(Decimal('1.00')) self.arquivo.trailer.sequencial_transacao = self.controle_linha cont_lote += 1 remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore')
def parse(self, data, banco_impt): """Launch the parsing itself.""" cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.seek(0) cnab240_file.write(data) cnab240_file.flush() ret_file = codecs.open(cnab240_file.name, encoding='ascii') # Nome_modo_impt é o nome da pasta do json. Código do banco é inválido # nessa situação arquivo = Arquivo((self.determine_bank(banco_impt)), arquivo=ret_file) cnab240_file.close() transacoes = [] total_amt = Decimal(0.00) for lote in arquivo.lotes: for evento in lote.eventos: vals = { 'name': evento.sacado_nome, 'amount': evento.valor_titulo, 'ref': evento.numero_documento, 'label': evento.sacado_inscricao_numero, # cnpj 'transaction_id': evento.numero_documento, # nosso numero, Alfanumérico 'unique_import_id': evento.nosso_numero, } if evento.vencimento_titulo: vals['date'] = datetime.datetime.strptime( str(evento.vencimento_titulo), '%d%m%Y') transacoes.append(vals) total_amt += evento.valor_titulo vals_bank_statement = { 'name': '%s - %s' % (arquivo.header.nome_do_banco, arquivo.header.arquivo_data_de_geracao), 'date': datetime.datetime.strptime( str(arquivo.header.arquivo_data_de_geracao), '%d%m%Y'), 'balance_start': 0.00, 'balance_end_real': total_amt, 'currency_code': u'BRL', # Código da moeda 'account_number': arquivo.header.cedente_conta, 'transactions': transacoes } return [vals_bank_statement]
def _check_cnab(self, data_file, raise_error=False): try: cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() arquivo = open(cnab240_file.name, 'r') # read 1st 3 chars of 1st line from file bank_code = arquivo.readline()[0:3] bank = self.determine_bank(bank_code) Arquivo(bank, arquivo=open(cnab240_file.name, 'r')) return True except Exception as e: if raise_error: raise UserError(u"Arquivo formato inválido:\n%s" % str(e)) return False
def _check_cnab(self, data_file, raise_error=False): try: cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() journal_id = self.env.context['journal_id'] if self.force_journal_account: journal_id = self.journal_id.id bank = self.get_bank(journal_id) Arquivo(bank, arquivo=open(cnab240_file.name, 'r')) return True except Exception as e: if raise_error: raise UserError(u"Arquivo formato inválido:\n%s" % str(e)) return False
def setUp(self): self.itau_data = get_itau_data_from_dict() self.arquivo = Arquivo(itau, **self.itau_data['arquivo'])
class TestCnab240(unittest.TestCase): """ All tests related to file handling. """ def setUp(self): self.itau_data = get_itau_data_from_dict() self.arquivo = Arquivo(itau, **self.itau_data['arquivo']) def test_unicode(self): self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) self.arquivo.incluir_cobranca(**self.itau_data['cobranca2']) _file = unicode(self.arquivo).splitlines() _itau = get_itau_file_remessa().splitlines() for ix, l in enumerate(_file): assert l == _itau[ix], "Error on line {}\n{}\n{}".format( ix, l, _itau[ix] ) def test_to_file_is_unicode(self): """ We check that what we write is what we are testing. Just to avoid regressions or being blind with bugs. Also, UTF-8 sanitization happens on dumping to file, so we have a special test below """ self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) self.arquivo.incluir_cobranca(**self.itau_data['cobranca2']) strio = StringIO() self.arquivo.escrever(strio) _file = strio.getvalue().splitlines() _unicode = unicode(self.arquivo).splitlines() strio.close() for ix, l in enumerate(_file): assert l == _unicode[ix], u"Error on line {}\n{}\n{}".format( ix, l, _unicode[ix] ) def test_nonascii(self): """ Test if we can handle nonascii chars. """ nonascii = get_nonascii_data() self.arquivo.incluir_cobranca(**nonascii['cobranca']) self.arquivo.incluir_cobranca(**nonascii['cobranca2']) strio = StringIO() self.arquivo.escrever(strio) _file = strio.getvalue().splitlines() _itau = get_itau_file_remessa().splitlines() strio.close() for ix, l in enumerate(_file): assert l == _itau[ix], u"Error on line {}\n{}\n{}".format( ix, l, _itau[ix] ) # def test_record_limit(self): # """ Check that we limit the file to 178 records.""" # #self.assertEqual(len(self.arquivo), 0) # # import ipdb; ipdb.set_trace() # _add = self.arquivo.incluir_cobranca # data = self.itau_data['cobranca'] # # try: # i = 0 # for _ in xrange(88): # _add(**data) # i += 1 # except errors.ArquivoCheioError: # #assert False, 'Should fit, at {}'.format(i) # pass # else: # self.assertRaises(errors.ArquivoCheioError, _add, **data) # def test_assure_len(self): # """ Len of a record should be 2 and growth should be 2. """ # self.arquivo.c # self.assertEqual(len(self.arquivo), 0) # self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) # # header + seg_p + seg_q # self.assertEqual(len(self.arquivo), 3) # self.arquivo.incluir_cobranca(**self.itau_data['cobranca']) # self.assertEqual(len(self.arquivo), 5) def test_empty_data(self): arquivo = Arquivo(itau) self.assertRaises(errors.ArquivoVazioError, unicode, arquivo) def test_leitura(self): return_file_path = os.path.join(ARQS_DIRPATH, 'cobranca.itau.ret') with codecs.open(return_file_path, encoding='ascii') as ret_file: arquivo = Arquivo(itau, arquivo=ret_file) ret_file.seek(0) self.assertEqual(ret_file.read(), unicode(arquivo))
def test_empty_data(self): arquivo = Arquivo(bancodobrasil) self.assertRaises(errors.ArquivoVazioError, str, arquivo)
def setUp(self): self.bancodobrasil_data = get_bancodobrasil_data_from_dict() self.arquivo = Arquivo(bancodobrasil, **self.bancodobrasil_data['arquivo'])
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.company_id.partner_id.is_company: return 2 else: return 1 def _prepare_header(self): cnpj_cpf = re.sub('[^0-9]', '', self.order.company_id.cnpj_cpf) cedente_conta_dv = self.order.src_bank_account_id.acc_number_dig cedente_conta_dv = str(cedente_conta_dv) return { 'controle_banco': int(self.order.src_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.src_bank_account_id.bra_number), 'cedente_conta': int(self.order.src_bank_account_id.acc_number), 'cedente_conta_dv': cedente_conta_dv, 'cedente_convenio': self.order.src_bank_account_id.codigo_convenio, 'cedente_agencia_dv': self.order.src_bank_account_id.bra_number_dig, 'cedente_nome': self.order.company_id.legal_name, # DV ag e conta 'cedente_dv_ag_cc': self.order.src_bank_account_id.bra_number_dig, 'arquivo_codigo': 1, # Remessa/Retorno 'servico_operacao': u'R', 'nome_banco': self.order.src_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): sulfixo = format[-3:] prefixo = format[: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.src_bank_account_id.bank_bic), 'cedente_agencia': int(self.order.src_bank_account_id.bra_number), 'cedente_conta': int(self.order.src_bank_account_id.acc_number), 'cedente_conta_dv': self.order.src_bank_account_id.acc_number_dig, 'cedente_convenio': self.order.src_bank_account_id.codigo_convenio, 'cedente_agencia_dv': self.order.src_bank_account_id.bra_number_dig, 'cedente_nome': self.order.company_id.legal_name, # DV ag e cc 'cedente_dv_ag_cc': self.order.src_bank_account_id.bra_number_dig, 'identificacao_titulo': u'0000000', # TODO 'identificacao_titulo_banco': u'0000000', # TODO 'identificacao_titulo_empresa': (' ' * 25), 'numero_documento': line.identifier, 'vencimento_titulo': self.format_date(line.date_maturity), 'valor_titulo': Decimal(str(line.amount_total)).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.emission_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')), '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 self._hook_validation() header = self._prepare_header() self.arquivo = Arquivo(self.bank, **header) for line in order.line_ids: seg = self._prepare_segmento(line) 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.amount_total self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) return str(self.arquivo) def data_hoje(self): return (int(time.strftime("%d%m%Y"))) def hora_agora(self): return (int(time.strftime("%H%M%S"))) def _hook_validation(self): pass
def test_empty_data(self): arquivo = Arquivo(itau) self.assertRaises(errors.ArquivoVazioError, str, arquivo)
class Cnab240(Cnab): """ """ def __init__(self): super(Cnab, self).__init__() @staticmethod def get_bank(bank): if bank == '341': from .bancos.itau import Itau240 return Itau240 elif bank == '237': from .bancos.bradesco import Bradesco240 return Bradesco240 elif bank == '104': from .bancos.cef import Cef240 return Cef240 elif bank == '033': from .bancos.santander import Santander240 return Santander240 else: return Cnab240 def nosso_numero(self, format): return format def _prepare_header(self, arquivo_codigo, controle_banco, cedente_agencia, cedente_agencia_dv, cedente_conta, cedente_conta_dv, cedente_dv_ag_cc, cedente_inscricao_numero, cedente_inscricao_tipo, cedente_nome, nome_banco, servico_operacao, arquivo_sequencia, arquivo_data_de_geracao=False, arquivo_hora_de_geracao=False, **kwargs): """ :param: :return: """ return { 'controle_banco': controle_banco, 'arquivo_data_de_geracao': arquivo_data_de_geracao or self.data_hoje(), 'arquivo_hora_de_geracao': arquivo_hora_de_geracao or self.hora_agora(), # TODO: Número sequencial de arquivo 'arquivo_sequencia': int(arquivo_sequencia), 'cedente_inscricao_tipo': int(self.inscricao_tipo(cedente_inscricao_numero)), 'cedente_inscricao_numero': int(self.punctuation_rm(cedente_inscricao_numero)), 'cedente_agencia': int(cedente_agencia), 'cedente_conta': int(cedente_conta), 'cedente_conta_dv': cedente_conta_dv, 'cedente_agencia_dv': cedente_agencia_dv, 'cedente_nome': cedente_nome, # DV ag e conta 'cedente_dv_ag_cc': cedente_dv_ag_cc, 'arquivo_codigo': 1, # Remessa/Retorno 'servico_operacao': unicode(servico_operacao), 'nome_banco': unicode(nome_banco), } def _prepare_segmento(self, line): """ :param line: :return: """ prefixo, sulfixo = self.cep(line.sacado_cep) aceite = u'N' if not line.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 { # TODO: Esses dados podem ser de outras filiais e contas # provavelmente, então pode ser que teremos que refazer este # trecho. 'controle_banco': self.arquivo.header.controle_banco, 'cedente_agencia': self.arquivo.header.cedente_agencia, 'cedente_conta': self.arquivo.header.cedente_conta, 'cedente_conta_dv': self.arquivo.header.cedente_conta_dv, 'cedente_agencia_dv': self.arquivo.header.cedente_agencia_dv, 'cedente_dv_ag_cc': self.arquivo.header.cedente_dv_ag_cc, 'identificacao_titulo': u'0000000', # TODO 'identificacao_titulo_banco': u'0000000', # TODO 'identificacao_titulo_empresa': line.nosso_numero, 'numero_documento': line.numero_documento, 'vencimento_titulo': self.format_date(line.data_vencimento), 'valor_titulo': Decimal(line.valor_documento).quantize(Decimal('1.00')), # TODO: Código adotado para identificar o título de cobrança. # 8 é Nota de cŕedito comercial 'especie_titulo': 8, # FIXME #int(self.order.mode.boleto_especie), 'aceite_titulo': aceite, 'data_emissao_titulo': self.format_date(line.data_documento), # TODO: trazer taxa de juros do Odoo. Depende do valor do 27.3P # CEF/FEBRABAN e Itaú não tem. 'juros_mora_data': self.format_date(line.data_vencimento), # FIXME 'juros_mora_taxa_dia': Decimal('0.00'), # FIXME 'valor_abatimento': Decimal('0.00'), # FIXME 'sacado_inscricao_tipo': int(self.inscricao_tipo(line.sacado_documento)), 'sacado_inscricao_numero': int(self.punctuation_rm(line.sacado_documento)), 'sacado_nome': line.sacado_nome, 'sacado_endereco': line.sacado_endereco, 'sacado_bairro': line.sacado_bairro, 'sacado_cep': int(prefixo), 'sacado_cep_sufixo': int(sulfixo), 'sacado_cidade': line.sacado_cidade, 'sacado_uf': line.sacado_uf, 'codigo_protesto': 1, #int(self.order.mode.boleto_protesto), 'prazo_protesto': 1, #int(self.order.mode.boleto_protesto_prazo), 'codigo_baixa': 2, 'prazo_baixa': 0, # De 5 a 120 dias. 'controlecob_data_gravacao': self.data_hoje(), 'cobranca_carteira': int(line.carteira), } def remessa(self, header, lista_boletos): """ :param order: :return: """ cobrancasimples_valor_titulos = Decimal(0.00) self.arquivo = Arquivo(self.bank, **self._prepare_header(**header)) for line in lista_boletos: self.arquivo.incluir_cobranca(**self._prepare_segmento(line)) self.arquivo.lotes[0].header.servico_servico = 1 # TODO: tratar soma de tipos de cobranca # TODO: Verificar se é o valor do documento ou o valor cobrancasimples_valor_titulos += Decimal(line.valor_documento) self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore')
class Cnab240(Cnab): """ """ def __init__(self): super(Cnab, self).__init__() @staticmethod def get_bank(bank): if bank == '341': from .bancos.itau import Itau240 return Itau240 elif bank == '237': from .bancos.bradesco import Bradesco240 return Bradesco240 elif bank == '104': from .bancos.cef import Cef240 return Cef240 elif bank == '033': from .bancos.santander import Santander240 return Santander240 elif bank == '756': from .bancos.sicoob import Sicoob240 return Sicoob240 else: return Cnab240 @property def inscricao_tipo(self): # TODO: Implementar codigo para PIS/PASEP if self.order.company_id.partner_id.is_company: return 2 else: return 1 def _prepare_header(self): """ :param: :return: """ return { 'cedente_agencia_conta_dv': int(self.order.mode.bank_id.acc_number_dig), 'controle_banco': int(self.order.mode.bank_id.bank_bic), 'arquivo_data_de_geracao': self.data_hoje(), 'arquivo_hora_de_geracao': self.hora_agora(), # TODO: Número sequencial de arquivo 'arquivo_sequencia': int(self.get_file_numeration()), 'cedente_inscricao_tipo': self.inscricao_tipo, 'cedente_inscricao_numero': int(punctuation_rm(self.order.company_id.cnpj_cpf)), 'cedente_agencia': int(self.order.mode.bank_id.bra_number), 'cedente_conta': int(self.order.mode.bank_id.acc_number), 'cedente_conta_dv': (self.order.mode.bank_id.acc_number_dig), 'cedente_agencia_dv': self.order.mode.bank_id.bra_number_dig, 'cedente_nome': self.order.company_id.legal_name, # DV ag e conta 'cedente_dv_ag_cc': (self.order.mode.bank_id.bra_acc_dig), 'arquivo_codigo': 1, # Remessa/Retorno 'servico_operacao': u'R', 'nome_banco': unicode(self.order.mode.bank_id.bank_name), } def get_file_numeration(self): numero = 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): sulfixo = format[-3:] prefixo = format[: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): """ :param line: :return: """ prefixo, sulfixo = self.cep(line.partner_id.zip) aceite = u'N' if not self.order.mode.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 { 'cedente_agencia_conta_dv': int(self.order.mode.bank_id.acc_number_dig), 'controle_banco': int(self.order.mode.bank_id.bank_bic), 'cedente_agencia': int(self.order.mode.bank_id.bra_number), 'cedente_conta': int(self.order.mode.bank_id.acc_number), 'cedente_conta_dv': self.order.mode.bank_id.acc_number_dig, 'cedente_agencia_dv': self.order.mode.bank_id.bra_number_dig, 'cedente_nome': self.order.company_id.legal_name, # DV ag e cc 'cedente_dv_ag_cc': (self.order.mode.bank_id.acc_number_dig), 'identificacao_titulo': line.move_line_id.name, # 25 chars limit 'identificacao_titulo_banco': u'0000000', # TODO 'identificacao_titulo_empresa': line.move_line_id.move_id.name, 'numero_documento': line.move_line_id.transaction_ref, # 10 chars limit 'vencimento_titulo': self.format_date(line.ml_maturity_date), 'valor_titulo': Decimal(str(line.amount_currency)).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.mode.boleto_especie), 'aceite_titulo': aceite, 'data_emissao_titulo': self.format_date(line.ml_date_created), # 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.ml_maturity_date), 'juros_mora_taxa': Decimal(str(self.order.mode.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.ml_maturity_date), 'juros_multa': Decimal(str(self.order.mode.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, '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.l10n_br_city_id.name, 'sacado_uf': line.partner_id.state_id.code, 'codigo_protesto': int(self.order.mode.boleto_protesto), 'prazo_protesto': int(self.order.mode.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.mode.boleto_carteira), } def remessa(self, order): """ :param order: :return: """ cobrancasimples_valor_titulos = 0 self.order = order self.arquivo = Arquivo(self.bank, **self._prepare_header()) for line in order.line_ids: self.arquivo.incluir_cobranca(**self._prepare_segmento(line)) self.arquivo.lotes[0].header.servico_servico = 1 # TODO: tratar soma de tipos de cobranca cobrancasimples_valor_titulos += line.amount_currency # fixed 'quantidade_registros' in trailer to 000001 self.arquivo.lotes[0].trailer.cobrancasimples_valor_titulos = \ Decimal(cobrancasimples_valor_titulos).quantize( Decimal('1.00')) remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore') def data_hoje(self): return (int(time.strftime("%d%m%Y"))) def hora_agora(self): return (int(time.strftime("%H%M%S")))
def _parse_cnab(self, data_file, raise_error=False): """ LEIO os dados aqui mas o tipo 9 nao vem res = super(AccountBankStatementImport, self)._parse_cnab(data_file, raise_error) x,y,z = res tr = z[0]['transactions'] for ln in tr: print ln['name'] print ln['partner_name'] print ln['ref'] """ cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() #arquivo = Arquivo(sicoob, arquivo=open(cnab240_file.name, 'r')) arquivo = Arquivo(itau, arquivo=open(cnab240_file.name, 'r')) transacoes = [] inicio = datetime.strptime(str(arquivo.header.arquivo_data_de_geracao), '%d%m%Y') final = datetime.strptime(str(arquivo.header.arquivo_data_de_geracao), '%d%m%Y') #import pudb;pu.db cod_arquivo = str(arquivo.header.arquivo_sequencia + arquivo.header.cedente_conta) n_arq = '%s - %s - %s' % (arquivo.header.cedente_conta, inicio.strftime('%d/%m/%Y'), final.strftime('%d/%m/%Y')) company_id = 1 if self.force_journal_account: if not self.journal_id.company_id: raise UserError(u"Informe a Empresa na Conta Selecionada") company_id = str(self.journal_id.company_id.id) else: raise UserError(u"Informe a Conta") len_company = len(company_id) for lote in arquivo.lotes: for evento in lote.eventos: if evento.servico_codigo_movimento not in (6, 8, 9, 10): continue n_doc = '0' if evento.numero_documento: c_doc = len(evento.numero_documento) if c_doc > 7: try: pos_doc = evento.numero_documento.index('/') n_doc = evento.numero_documento[:pos_doc] # coloquei aqui pois os titulos velhos nao tem a empresa na frente if company_id != n_doc[:len_company]: continue except: n_doc = evento.numero_documento else: n_doc = evento.numero_documento prt = self.env['account.invoice'].search( [('number', 'ilike', evento.numero_documento)], limit=1) prt_id = 0 if prt: sacado = prt.partner_id.name prt_id = prt.partner_id.id else: sacado = evento.sacado_nome if evento.servico_codigo_movimento == 9: self._alterar_status_fatura(prt.id, n_arq) continue #valor = evento.valor_lancamento valor = evento.valor_titulo #if evento.tipo_lancamento == 'D': # valor *= -1 if evento.data_credito == 0: dta_credito = evento.data_ocorrencia else: dta_credito = evento.data_credito cod_arquivo += n_doc transacoes.append({ 'name': n_doc, 'date': datetime.strptime(str(dta_credito), '%d%m%Y'), 'amount': valor, 'partner_name': sacado, 'ref': n_doc, 'unique_import_id': str(cod_arquivo), }) header = arquivo.lotes[0].header trailer = arquivo.lotes[0].trailer vals_bank_statement = { 'name': u"%s - %s até %s" % (arquivo.header.nome_do_banco, inicio.strftime('%d/%m/%Y'), final.strftime('%d/%m/%Y')), 'date': inicio, 'balance_start': 0.0, # arquivo.lotes[0].header.valor_saldo_inicial, 'balance_end_real': 0.0, #arquivo.lotes[0].trailer.valor_saldo_final, 'transactions': transacoes } account_number = str(arquivo.header.cedente_conta) if self.force_journal_account: account_number = self.journal_id.bank_acc_number return ( 'BRL', #arquivo.lotes[0].header.moeda, account_number, [vals_bank_statement]) return res
class PagFor500(Cnab): """ """ def __init__(self): super(Cnab, self).__init__() @staticmethod def get_bank(bank): if bank == '237': from .bancos.bradesco import BradescoPagFor return BradescoPagFor else: return PagFor500 @property def inscricao_tipo(self): # TODO: Implementar codigo para PIS/PASEP if self.order.company_id.partner_id.is_company: return 2 else: return 1 def _prepare_header(self): """ :param: :return: """ return { 'arquivo_data_de_geracao': self.data_hoje_pag_for(), 'arquivo_hora_de_geracao': self.hora_agora(), # TODO: Número sequencial de arquivo 'numero_remessa': int(self.get_file_numeration()), 'cedente_inscricao_tipo': self.inscricao_tipo, 'cnpj_cpf_base': int(punctuation_rm(self.order.company_id.cnpj_cpf)[0:8]), 'cnpj_cpf_filial': int(punctuation_rm(self.order.company_id.cnpj_cpf)[9:12]), 'sufixo_cnpj': int(punctuation_rm(self.order.company_id.cnpj_cpf)[12:14]), 'cedente_agencia': int(self.order.mode.bank_id.bra_number), 'cedente_conta': int(self.order.mode.bank_id.acc_number), 'cedente_agencia_conta_dv': self.order.mode.bank_id.bra_number_dig, 'nome_empresa_pagadora': self.order.company_id.legal_name, 'cedente_codigo_agencia_digito': self.order.mode.bank_id.bra_number_dig, 'arquivo_codigo': 1, # Remessa/Retorno 'servico_operacao': u'R', 'reservado_empresa': u'BRADESCO PAG FOR', # Sequencial crescente e nunca pode ser repetido 'numero_lista_debito': int(self.get_file_numeration()), # TODO: Sequencial crescente de 1 a 1 no arquivo. O primeiro header # será sempre 000001 'sequencial': 1 } def get_file_numeration(self): numero = 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 format_date_ano_mes_dia(self, srt_date): return int( datetime.datetime.strptime(srt_date, '%Y-%m-%d').strftime('%Y%m%d')) def nosso_numero(self, format): pass def cep(self, format): sulfixo = format[-3:] prefixo = format[: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, vals): """ :param line: :return: """ segmento = {} vals.update(segmento) # TODO this zip code prefixo, sulfixo = self.cep(line.partner_id.zip) aceite = u'N' if not self.order.mode.boleto_aceite == 'S': aceite = u'A' segmento = { 'conta_complementar': int(self.order.mode.bank_id.acc_number), # 'especie_titulo': 8, 'tipo_inscricao': int(self.sacado_inscricao_tipo(line.partner_id)), 'cnpj_cpf_base_forn': int(self.rmchar(line.partner_id.cnpj_cpf)[0:8]), 'cnpj_cpf_filial_forn': int(self.rmchar(line.partner_id.cnpj_cpf)[9:12]), 'cnpj_cpf_forn_sufixo': int(self.rmchar(line.partner_id.cnpj_cpf)[12:14]), 'nome_forn': line.partner_id.legal_name, 'endereco_forn': (line.partner_id.street + ' ' + line.partner_id.number), 'cep_forn': int(prefixo), 'cep_complemento_forn': int(sulfixo), # 'nosso_numero': 11, # FIXME # TODO quando banco é 237, deve-se extrair da linha digitável. Do contrário, zeros. # 'numero_documento': line.name, # 'vencimento_titulo': self.format_date_ano_mes_dia( # line.ml_maturity_date), 'data_emissao_titulo': self.format_date_ano_mes_dia(line.ml_date_created), 'desconto1_data': 0, 'fator_vencimento': 0, # FIXME 'valor_titulo': Decimal(str(line.amount_currency)).quantize(Decimal('1.00')), 'valor_pagto': Decimal(str(line.amount_currency)).quantize(Decimal('1.00')), 'valor_desconto': Decimal('0.00'), 'valor_acrescimo': Decimal('0.00'), # FIXME 'tipo_documento': 2, # NF, Fatura, Duplicata... # NF_Fatura_01/Fatura_02/NF_03/Duplicata_04/Outros_05 'numero_nf': int(line.ml_inv_ref.internal_number), 'modalidade_pagamento': int(line.order_id.mode.type_purchase_payment), 'data_para_efetivacao_pag': 0, # Quando não informada o sistema assume a data constante do campo Vencimento 'tipo_movimento': 0, # TODO Tipo de Movimento. # 0 - Inclusão. # 5 - Alteração. # 9 - Exclusão. 'codigo_movimento': 0, # Autoriza agendamento # 'horario_consulta_saldo': u'5', # Quando não informado consulta em todos processamentos 'codigo_area_empresa': 0, 'codigo_lancamento': 0, # FIXME 'tipo_conta_fornecedor': 1, # FIXME # O Primeiro registro de transação sempre será o registro # “000002”, e assim sucessivamente. 'sequencial': 3, # FIXME # Trailer 'totais_quantidade_registros': 0, 'total_valor_arq': Decimal('0.00'), # FIXME: lib nao reconhece campo 'sequencial_trailer': int(self.get_file_numeration()), 'sequencial_transacao': self.controle_linha, 'codigo_protesto': int(self.order.mode.boleto_protesto), 'prazo_protesto': int(self.order.mode.boleto_protesto_prazo), 'codigo_baixa': 2, 'prazo_baixa': 0, # De 5 a 120 dias. 'controlecob_data_gravacao': self.data_hoje(), } segmento.update(vals) return segmento def remessa(self, order): """ :param order: :return: """ pag_valor_titulos = 0 self.order = order self.arquivo = Arquivo(self.bank, **self._prepare_header()) cont_lote = 0 for line in order.line_ids: self.arquivo.incluir_pagamento(**self.incluir_pagamento_for(line)) pag_valor_titulos += line.amount_currency self.arquivo.trailer.total_valor_arq = Decimal( pag_valor_titulos).quantize(Decimal('1.00')) self.arquivo.trailer.sequencial_transacao = self.controle_linha cont_lote += 1 remessa = unicode(self.arquivo) return unicodedata.normalize('NFKD', remessa).encode('ascii', 'ignore') def data_hoje(self): return (int(time.strftime("%d%m%Y"))) def data_hoje_pag_for(self): return (int(time.strftime("%Y%m%d"))) def hora_agora(self): return (int(time.strftime("%H%M%S"))) @staticmethod def modulo11(num, base, r): return BoletoData.modulo11(num, base=9, r=0) def incluir_pagamento_for(self, line): mode = line.order_id.mode.type_purchase_payment if mode in ('01'): return self.lancamento_credito_bradesco(line) elif mode in ('02'): raise UserError('Operação não suportada') elif mode in ('03'): return self.lancamento_doc(line) elif mode in ('05'): raise UserError('Operação não suportada') elif mode in ('08'): return self.lancamento_ted(line) elif mode in ('30'): raise UserError('Operação não suportada') elif mode in ('31'): # titulos de terceiros return self.lancamento_titulos_terceiros(line) raise UserError('Operação não suportada') def lancamento_credito_bradesco(self, line): # TODO: # modalidade 01. vals = { 'especie_titulo': line.order_id.mode.type_purchase_payment, 'codigo_banco_forn': 237, 'codigo_agencia_forn': int(line.bank_id.bra_number), 'digito_agencia_forn_transacao': line.bank_id.bra_number_dig, 'conta_corrente_forn': int(line.bank_id.acc_number), 'digito_conta_forn_transacao': line.bank_id.acc_number_dig, 'numero_pagamento': self.adiciona_digitos_num_pag(line.communication), 'carteira': int(self.order.mode.boleto_carteira), 'nosso_numero': 0, 'vencimento_titulo': self.format_date_ano_mes_dia(line.ml_maturity_date), 'informacoes_complementares': u'', } return self._prepare_segmento(line, vals) def lancamento_ted(self, line): # TODO: # modalidade 08. vals = { 'conta_complementar': int(self.order.mode.bank_id.acc_number), 'especie_titulo': line.order_id.mode.type_purchase_payment, # TODO: código do banco. Para a Modalidade de Pagamento valor # pode variar 'codigo_banco_forn': int(line.bank_id.bank.bic), 'codigo_agencia_forn': int(line.bank_id.bra_number), 'digito_agencia_forn_transacao': line.bank_id.bra_number_dig, 'conta_corrente_forn': int(line.bank_id.acc_number), 'digito_conta_forn_transacao': line.bank_id.acc_number_dig, # TODO Gerado pelo cliente pagador quando do agendamento de # pagamento por parte desse, exceto para a modalidade 30 - # Títulos em Cobrança Bradesco # communication 'numero_pagamento': self.adiciona_digitos_num_pag(line.communication), 'carteira': 0, 'nosso_numero': 0, 'vencimento_titulo': self.format_date_ano_mes_dia(line.ml_maturity_date), 'fator_vencimento': 0, # FIXME # 'modalidade_pagamento': int(self.order.mode.boleto_especie), 'tipo_movimento': 0, # TODO Tipo de Movimento. # 0 - Inclusão. # 5 - Alteração. # 9 - Exclusão. Wkf Odoo. 'codigo_movimento': 0, # FIXME # 'horario_consulta_saldo': u'5', # FIXME # 'informacoes_complementares': self.montar_info_comple_ted(), 'informacoes_complementares': u'', 'codigo_lancamento': 0, # FIXME 'tipo_conta_fornecedor': 1, # FIXME } return self._prepare_segmento(line, vals) def lancamento_doc(self): # TODO: vals = {} return self._prepare_segmento(vals) def lancamento_titulos_terceiros(self, line): # TODO: res_cods_ag_cc = \ self.ler_linha_digitavel_codigos_ag_cc(line.linha_digitavel) vals = { 'conta_complementar': int(self.order.mode.bank_id.acc_number), 'especie_titulo': line.order_id.mode.type_purchase_payment, # extrair do código de barras 'codigo_banco_forn': res_cods_ag_cc['codigo_banco_forn'], 'codigo_agencia_forn': res_cods_ag_cc['codigo_agencia_forn'], 'digito_agencia_forn_transacao': res_cods_ag_cc['digito_agencia_forn_transacao'], 'conta_corrente_forn': res_cods_ag_cc['conta_corrente_forn'], 'digito_conta_forn_transacao': res_cods_ag_cc['digito_conta_forn_transacao'], 'carteira': res_cods_ag_cc['carteira'] } return self._prepare_segmento(vals) def adiciona_digitos_num_pag(self, campo): num_digitos = 16 campo = str(campo) chars_faltantes = num_digitos - len(campo) return (u' ' * chars_faltantes) + campo def montar_info_comple_ted(self): tipo_doc_compe = TIPO_DOC[0][0] num_doc_ted = '000000' finalidade_doc_compe = FINALIDADE_DOC_TED[2][ 0] # pagamento duplicatas. Ou será 01? tipo_conta_doc_ted = '01' codigo_identif_transf = '0000000000000000000000000' fim_do_campo = ' ' info_comple = tipo_doc_compe + num_doc_ted + finalidade_doc_compe + \ tipo_conta_doc_ted + codigo_identif_transf + fim_do_campo return (info_comple.encode('utf-8')) def ler_linha_digitavel_codigos_ag_cc(self, linha_digitavel): linha_completa = linha_digitavel codigo_banco_fornecedor = linha_digitavel[:3] res = {} # para banco = 237, bradesco if (codigo_banco_fornecedor == '237'): res = { 'codigo_banco_forn': int(codigo_banco_fornecedor), 'codigo_agencia_forn': int(linha_digitavel[4:8]), 'digito_agencia_forn_transacao': u'', # Calcular usando modulo 11 base 7 'conta_corrente_forn': int(linha_digitavel[23:30]), 'digito_conta_forn_transacao': u'', # Calcular usando modulo 11 base 7 'carteira': int(linha_digitavel[8:10]), 'nosso_numero': int(linha_digitavel[11:21]) } # para outros bancos else: res = { 'codigo_banco_forn': int(codigo_banco_fornecedor), 'codigo_agencia_forn': 0, 'digito_agencia_forn_transacao': u'', 'conta_corrente_forn': 0, 'digito_conta_forn_transacao': u'', 'carteira': 0, 'nosso_numero': 0, } return res
def montarArquivo(self, cr, uid, ids, context=None): res = {} cnab_data = dict() for obj_id in self.browse(cr, uid, ids, context): # exportation_bank = obj_id.codigo_banco exportation_bank = u'341' segmento_pool = self.pool.get('cnab240export.segmentos') ids_segmentos = segmento_pool.search( cr, uid, [('arquivo_id', 'in', ids)]) #itau_data = dict() #itau_data['arquivo'] = dict_arquivo #itau_data['cobranca'] = dict_cobranca #arquivo = Arquivo(itau, **itau_data['arquivo']) #arquivo.incluir_cobranca(**itau_data['cobranca']) #arquivo.lotes[0].header.servico_servico = 1 # Header dict_arquivo = self.get_cnab_header_data(cr, uid, ids, context) cnab_data['arquivo'] = dict_arquivo if exportation_bank == u'104': arquivo = Arquivo(itau, **cnab_data['arquivo']) elif exportation_bank == u'341': arquivo = Arquivo(itau, **cnab_data['arquivo']) #cnab_data['cobranca'] = dict_cobranca #arquivo.incluir_cobranca(**cnab_data['cobranca']) for seg in ids_segmentos: #pdb.set_trace() segmento_cobranca = self.get_cnab_segmento_data(cr, uid, seg, context) #cedente_nome = obj_id.cedente_nome #cedente_inscricao_numero = obj_id.cedente_inscricao_numero #cedente_inscricao_tipo = obj_id.cedente_inscricao_tipo #cedente_agencia = obj_id.cedente_agencia #cedente_conta = obj_id.cedente_conta #cedente_agencia_conta_dv = obj_id.cedente_agencia_digito #cedente_codigo_codCedente = obj_id.cedente_codCedente #nome_do_banco = obj_id.nome_do_banco #arquivo_sequencia = int(obj_id.arquivo_sequencia) segmento_cobranca['cedente_nome'] = dict_arquivo.get('cedente_nome') segmento_cobranca['cedente_inscricao_numero'] = dict_arquivo.get('cedente_inscricao_numero') segmento_cobranca['cedente_inscricao_tipo'] = dict_arquivo.get('cedente_inscricao_tipo') segmento_cobranca['cedente_agencia'] = dict_arquivo.get('cedente_agencia') segmento_cobranca['cedente_conta'] = dict_arquivo.get('cedente_conta') segmento_cobranca['cedente_agencia_conta_dv'] = dict_arquivo.get('cedente_agencia_conta_dv') #segmento_cobranca['dente_codCedente'] = dict_arquivo.get('cedente_codCedente') #segmento_cobranca['nome_do_banco'] = dict_arquivo.get('nome_do_banco') #segmento_cobranca[''] = dict_arquivo.get('') cnab_data['cobranca'] = segmento_cobranca arquivo.incluir_cobranca(**cnab_data['cobranca']) arquivo.lotes[0].header.servico_servico = 1 str = unicode(arquivo) f = open('/tmp/arquivo_remessa.rem','w') f.write(str) # python will convert \n to os.linesep f.close() return True
def setUp(self): self.santander_data = get_santander_data_from_dict() self.arquivo = Arquivo(santander, **self.santander_data['arquivo'])
def setUp(self): self.bancoob_data = get_bancoob_data_from_dict() self.arquivo = Arquivo(bancoob, **self.bancoob_data['arquivo'])
def _parse_cnab(self, data_file, raise_error=False): cnab240_file = tempfile.NamedTemporaryFile() cnab240_file.write(data_file) cnab240_file.flush() journal_id = self.env.context['journal_id'] if self.force_journal_account: journal_id = self.journal_id.id bank = self.get_bank(journal_id) arquivo = Arquivo(bank, arquivo=open(cnab240_file.name, 'r')) transacoes = [] valor_total = Decimal('0.0') for lote in arquivo.lotes: for evento in lote.eventos: valor = evento.titulo_pago # Apenas liquidação (Sicoob:6) # Liquidação Banco do Brasil (6, 17) # Liquidação Bradesco (6, 177) # Liquidação Santander ('06', '17') if evento.servico_codigo_movimento in (6, 17, '06', '17',): valor_total += valor nosso_numero = self._get_nosso_numero( journal_id, evento.nosso_numero) move_line = self.env['account.move.line'].search( [('nosso_numero', '=', nosso_numero)]) transacoes.append({ 'name': "%s : %s" % ( move_line.partner_id.name or evento.sacado_nome, evento.numero_documento or "%s: %s" % ( move_line.move_id.name, move_line.name)), 'date': datetime.strptime( str(evento.data_ocorrencia), '%d%m%Y'), 'amount': valor, 'partner_name': move_line.partner_id.name or evento.sacado_nome, 'partner_id': move_line.partner_id.id, 'ref': evento.numero_documento, 'unique_import_id': str(evento.nosso_numero), 'nosso_numero': nosso_numero, }) inicio = final = datetime.now() if len(transacoes): primeira_transacao = min(transacoes, key=lambda x: x["date"]) ultima_transacao = max(transacoes, key=lambda x: x["date"]) inicio = primeira_transacao["date"] final = ultima_transacao["date"] last_bank_stmt = self.env['account.bank.statement'].search( [('journal_id', '=', journal_id)], order="date desc, id desc", limit=1) last_balance = last_bank_stmt and last_bank_stmt[0].balance_end or 0.0 vals_bank_statement = { 'name': u"%s - %s até %s" % ( arquivo.header.nome_do_banco, inicio.strftime('%d/%m/%Y'), final.strftime('%d/%m/%Y')), 'date': inicio, 'balance_start': last_balance, 'balance_end_real': Decimal(last_balance) + valor_total, 'transactions': transacoes } account_number = '' # str(arquivo.header.cedente_conta) if self.force_journal_account: account_number = self.journal_id.bank_acc_number return ( 'BRL', account_number, [vals_bank_statement] )
def do_import(self, cnab_file): if self.cnab_type != 'receivable': return super(L10nBrPaymentCnabImport, self).do_import(cnab_file) stream = StringIO(cnab_file.decode('ascii')) bank = get_bank(self.journal_id.bank_id.bic) arquivo = Arquivo(bank, arquivo=stream) sequence = self.journal_id.l10n_br_sequence_statements statement = None for lote in arquivo.lotes: for evento in lote.eventos: if not statement: statement = self.env['l10n_br.payment.statement'].create({ 'journal_id': self.journal_id.id, 'date': date.today(), 'company_id': self.journal_id.company_id.id, 'name': sequence.next_by_id(), 'type': 'receivable', }) code, message = parse_cnab_code( self.journal_id.bank_id.bic, evento.servico_codigo_movimento) payment_line = self.env['payment.order.line'].search([ ('nosso_numero', '=', int(evento.nosso_numero)), ('src_bank_account_id', '=', self.journal_id.bank_account_id.id) ]) due_date = date.today() effective_date = None if evento.vencimento_titulo: due_date = datetime.strptime( "{:08}".format(evento.vencimento_titulo), "%d%m%Y") if evento.data_ocorrencia: effective_date = datetime.strptime( "{:08}".format(evento.data_ocorrencia), "%d%m%Y") vals = { 'nosso_numero': evento.nosso_numero, 'numero_documento': evento.numero_documento, 'sacado_nome': evento.sacado_nome, 'valor_titulo': evento.valor_titulo, 'titulo_acrescimos': evento.titulo_acrescimos, 'titulo_desconto': evento.titulo_desconto, 'titulo_abatimento': evento.titulo_abatimento, 'titulo_pago': evento.titulo_pago, 'valor_tarifas': evento.valor_tarifas, 'titulo_liquido': evento.titulo_liquido, 'vencimento_titulo': due_date, 'data_ocorrencia': effective_date, 'cnab_code': code, 'cnab_message': message, } IMMUTABLE_STATES = ('paid', 'rejected', 'cancelled') if payment_line and payment_line.state in IMMUTABLE_STATES: vals['cnab_message'] = 'Importado previamente' self._create_ignored_line(statement, vals, payment_line) continue if not payment_line: self._create_ignored_line(statement, vals) continue # Process the line payment_line.process_receivable_line(statement, vals) if not statement: raise UserError(_('Nenhum registro localizado nesse extrato!')) action = self.env.ref( 'br_account_payment.action_payment_statement_tree') return action.read()[0]