# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
##
## Copyright (C) 2017 Async Open Source
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., or visit: http://www.gnu.org/.
##
## Author(s): Stoq Team <stoq-devel@async.com.br>
##
from datetime import timedelta
from decimal import Decimal
from stoqlib.lib.cnab.base import Field, Record, Cnab
from stoqlib.lib.formatters import format_address
class Record400(Record):
size = 400
class ItauFileHeader(Record400):
fields = [
Field('registry_type', int, 1, 0),
Field('operation_type', int, 1, 1), # 1 = remessa
Field('operation_name', str, 7, 'REMESSA'),
Field('service_code', int, 2, 1), # 01 == Cobrança
Field('service_name', str, 15, 'COBRANCA'),
Field('agency', int, 4),
Field('_', int, 2, 0),
Field('account', int, 5),
Field('dv_agencia_conta', int, 1),
Field('_', str, 8, ''),
Field('company_name', str, 30),
Field('bank_number', int, 3),
Field('bank_name', str, 15),
Field('create_date', int, 6),
Field('_', str, 294, ''),
Field('registry_sequence', int, 6),
]
class ItauPaymentDetail(Record400):
fields = [
Field('registry_type', int, 1, 1),
Field('company_type', int, 2, 2), # CPF/CNPJ 2 = CNPJ
Field('company_document', int, 14),
Field('agency', int, 4),
Field('_', int, 2, 0),
Field('account', int, 5),
Field('dv_agencia_conta', int, 1),
Field('_', str, 4, ''),
# Instruçào a ser cancelada NOTA 27
# Deve ser preenchido somente quando codigo_ocorrencia == 38
Field('cancel_instruction', int, 4, 0),
Field('payment_description', str, 25),
Field('nosso_numero', int, 8),
# Este campo deverá ser preenchido com zeros caso a moeda seja o Real.
Field('variable_currency', Decimal, 8, 0, decimals=5),
Field('carteira', int, 3),
Field('bank_use', str, 21, ''),
Field('codigo_carteira', str, 1), # NOTA 5
Field('codigo_ocorrencia', int, 2, 1), # 01 == Remessa NOTA 6
Field('numero_documento', int, 10), # na verdade é str, mas eu quero alinhado a direita
Field('due_date', int, 6),
Field('value', Decimal, 11, decimals=2),
Field('bank_number', int, 3),
Field('charging_agency', int, 5, 0),
Field('especie_titulo', str, 2, '99'), # 01 - Duplicata Mercantil / 99 - Diversos
Field('aceite', str, 1),
Field('open_date', int, 6), # NOTA 31
Field('instrucao_1', int, 2), # NOTA 11
Field('instrucao_2', int, 2), # NOTA 11
Field('interest_value', Decimal, 11), # Juros de 1 dia
Field('discount_date', int, 6, 0),
Field('discount_value', Decimal, 11, 0),
Field('iof', Decimal, 11, 0),
Field('abatimento', Decimal, 11, 0),
Field('payer_type', int, 2), # CPF/CNPJ
Field('payer_document', int, 14),
Field('payer_name', str, 30),
Field('_', str, 10, ''),
Field('payer_address', str, 40),
Field('payer_district', str, 12),
Field('payer_postal_code', int, 8),
Field('payer_city', str, 15),
Field('payer_state', str, 2),
Field('sacador_avalista', str, 30, ''),
Field('_', str, 4, ''),
Field('penalty_date', int, 6, 0),
# Numero de dias para protestar/não receber/devolver/etc, dependendo do
# valor das instrucoes 1 e 2
Field('prazo', int, 2), # NOTA 11 (A)
Field('_', str, 1, ''),
Field('registry_sequence', int, 6),
]
# NOTA 5
cod_carteira = {
104: 'I',
108: 'I',
109: 'I',
112: 'I',
115: 'I',
121: 'I',
147: 'E',
150: 'U',
180: 'I',
188: 'I',
191: 'I',
}
def __init__(self, payment, bank_info, **kwargs):
person = payment.group.payer
if person.company:
payer_type = 2
doc = person.company.cnpj
else:
payer_type = 1
doc = person.individual.cpf
raw_doc = ''.join(i for i in doc if i.isdigit())
address = person.get_main_address()
postal_code = address.postal_code.replace('-', '')
address_str = format_address(address, include_district=False)
discount_value = bank_info.discount_percentage / 100 * payment.value
interest_value = bank_info.interest_percentage / 100 * payment.value
kwargs.update(
numero_documento=str(payment.identifier),
due_date=payment.due_date.strftime('%d%m%y'),
value=payment.value,
payment_description=payment.description,
open_date=payment.open_date.strftime('%d%m%y'),
aceite=bank_info.aceite,
nosso_numero=bank_info.nosso_numero,
# Payer data
payer_type=payer_type,
payer_document=raw_doc,
payer_name=person.name,
payer_address=address_str,
payer_district=address.district,
payer_postal_code=postal_code.split('-')[0],
payer_city=address.city_location.city,
payer_state=address.city_location.state,
# Juros diário (em reaiso)
interest_value=interest_value
)
if discount_value:
kwargs.update(
# Desconto até o pagamento
discount_date=payment.due_date.strftime('%d%m%y'),
discount_value=discount_value,
)
super(ItauPaymentDetail, self).__init__(**kwargs)
@property
def codigo_carteira(self):
carteira = self.get_value('carteira')
return self.cod_carteira[int(carteira)]
class ItauPenaltyDetail(Record400):
fields = [
Field('registry_type', int, 1, 2),
Field('penalty_code', str, 1, 2), # 2 = valor percentual
Field('penalty_date', int, 8),
Field('penalty_percentage', Decimal, 11), # FIXME
Field('_', str, 371, ''),
Field('registry_sequence', int, 6)
]
def __init__(self, payment, bank_info, **kwargs):
pdate = payment.due_date + timedelta(days=1)
kwargs.update(
penalty_date=pdate.strftime('%d%m%Y'),
)
super(ItauPenaltyDetail, self).__init__(**kwargs)
class ItauFileTrailer(Record400):
fields = [
Field('registry_type', int, 1, 9),
Field('_', str, 393, ''),
Field('registry_sequence', int, 6),
]
class ItauCnab400(Cnab):
def setup(self, payments):
i = 1
self.add_record(ItauFileHeader, registry_sequence=i)
info_class = self.bank_info.__class__
for payment in payments:
info = info_class(payment)
i += 1
self.add_record(ItauPaymentDetail, payment, info, registry_sequence=i)
if info.penalty_percentage > 0:
i += 1
self.add_record(ItauPenaltyDetail, payment, info, registry_sequence=i)
self.add_record(ItauFileTrailer, registry_sequence=i + 1)
@property
def create_date(self):
date = self.default_values['create_date']
# the format here is ddmmaa, while the other is ddmmaaaa
return date[:4] + date[-2:]