diff --git a/febraban/cnab240/bradesco/__init__.py b/febraban/cnab240/bradesco/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/febraban/cnab240/bradesco/multipag/__init__.py b/febraban/cnab240/bradesco/multipag/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/febraban/cnab240/bradesco/multipag/bradesco_layout.pdf b/febraban/cnab240/bradesco/multipag/bradesco_layout.pdf new file mode 100644 index 0000000..ce44b62 Binary files /dev/null and b/febraban/cnab240/bradesco/multipag/bradesco_layout.pdf differ diff --git a/febraban/cnab240/bradesco/multipag/file/__init__.py b/febraban/cnab240/bradesco/multipag/file/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/febraban/cnab240/bradesco/multipag/file/file.py b/febraban/cnab240/bradesco/multipag/file/file.py new file mode 100644 index 0000000..110cf4d --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/file.py @@ -0,0 +1,46 @@ +from datetime import datetime +from febraban.cnab240.libs.fileUtils import FileUtils +from febraban.cnab240.bradesco.multipag.file.header import Header +from febraban.cnab240.bradesco.multipag.file.trailer import Trailer + + +class File: + + def __init__(self, sequenceNumber=1): + self.header = Header(sequenceNumber) + self.lots = [] + self.trailer = Trailer() + + def addLot(self, lot): + lot.setLotNumber(len(self.lots) + 1) + self.lots.append(lot) + + def toString(self, currentDatetime=None): + lotsToString = "\r\n".join([lot.toString() for lot in self.lots]) + self.header.setGeneratedFileDate(currentDatetime or datetime.now()) + self.trailer.setNumberOfLotsAndRegisters( + num=len(self.lots), + sum=2 + self._countRegistersInLots() + ) + return "%s\r\n%s\r\n%s\r\n" % ( + self.header.content, + lotsToString, + self.trailer.content + ) + + def setSender(self, sender): + self.header.setSender(sender) + self.header.setSenderBank(sender.bank) + self.trailer.setSenderBank(sender.bank) + self.header.setBankAgreement(sender.bank.bankAgreement) + + def output(self, fileName, path="/../", content=None, currentDatetime=None): + file = FileUtils.create(name=fileName, path=path) + file.write(self.toString(currentDatetime or datetime.now()) if not content else content) + file.close() + + def _countRegistersInLots(self): + count = 0 + for lot in self.lots: + count += lot.count + return count diff --git a/febraban/cnab240/bradesco/multipag/file/header.py b/febraban/cnab240/bradesco/multipag/file/header.py new file mode 100644 index 0000000..8b38b20 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/header.py @@ -0,0 +1,57 @@ +from febraban.cnab240.row import Row +from febraban.cnab240.characterType import alphaNumeric, numeric + + +class Header: + def __init__(self, sequenceNumber=1): + self.content = " " * 240 + self.defaultValues() + self.setFileSequenceNumber(sequenceNumber) + + def defaultValues(self): + structs = [ + ( 3, 7, 4, numeric, "0000"), # Service lot + ( 7, 8, 1, numeric, "0"), # Record type + ( 163, 166, 3, numeric, "089"), # Layout version + ( 142, 143, 1, numeric, "1"), # 1 - Remittance / 2 - Return + ( 166, 171, 5, numeric, "1600"), # File recording density + ( 157, 163, 6, numeric, "000000"), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setFileSequenceNumber(self, number): + structs = [ + (157, 163, 6, numeric, number), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setGeneratedFileDate(self, datetime): + structs = [ + (143, 151, 8, numeric, datetime.strftime("%d%m%Y")), # File generation date + (151, 157, 6, numeric, datetime.strftime("%H%M%S")), # File generation time + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSender(self, user): + structs = [ + (17, 18, 1, numeric, "1" if len(user.identifier) == 11 else "2"), + (18, 32, 14, numeric, user.identifier), + (72, 102, 30, alphaNumeric, user.name) + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderBank(self, bank): + structs = [ + ( 0, 3, 3, numeric, bank.bankId), + (52, 57, 5, numeric, bank.branchCode), + (58, 70, 12, numeric, bank.accountNumber), + (70, 71, 1, alphaNumeric, bank.accountVerifier[:1]), + (102, 132, 30, alphaNumeric, bank.bankName), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setBankAgreement(self, agreement): + structs = [ + (32, 52, 20, alphaNumeric, agreement), + ] + self.content = Row.setStructs(structs=structs, content=self.content) diff --git a/febraban/cnab240/bradesco/multipag/file/headerLot.py b/febraban/cnab240/bradesco/multipag/file/headerLot.py new file mode 100644 index 0000000..0455059 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/headerLot.py @@ -0,0 +1,73 @@ +from febraban.cnab240.row import Row +from febraban.cnab240.characterType import alphaNumeric, numeric + +class HeaderLot: + + def __init__(self): + self.content = " " * 240 + self.defaultValues() + + def defaultValues(self): + structs = [ + ( 3, 7, 4, numeric, "1"), + ( 7, 8, 1, numeric, "1"), + ( 8, 9, 1, alphaNumeric, "C"), + ( 9, 11, 2, numeric, "01"), + ( 13, 16, 3, numeric, "012"), + ( 222, 224, 2, numeric, "01"), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSender(self, user): + structs = [ + (17, 18, 1, numeric, "1" if len(user.identifier) == 11 else "2"), + (18, 32, 14, numeric, user.identifier), + (72, 102, 30, alphaNumeric, user.name) + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setGeneratedFileDate(self, datetime): + structs = [ + (191, 199, 8, numeric, datetime.strftime("%d%m%Y")), # Recording date + (199, 207, 8, numeric, datetime.strftime("%d%m%Y")), # Credit date + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderBank(self, bank): + structs = [ + ( 0, 3, 3, numeric, bank.bankId), + (52, 57, 5, numeric, bank.branchCode), + (58, 70, 12, numeric, bank.accountNumber), + (70, 71, 1, numeric, bank.accountVerifier[:1]), + (71, 72, 1, alphaNumeric, ""), + (102, 132, 30, alphaNumeric, bank.bankName), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderAddress(self, address): + structs = [ + (142, 192, 50, alphaNumeric, "%s %s %s" % (address.streetLine1, address.streetLine2, address.district)), + (192, 212, 20, alphaNumeric, address.city), + (212, 220, 8, numeric, address.zipCode), + (220, 222, 2, alphaNumeric, address.stateCode), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setPositionInLot(self, index): + structs = [ + (3, 7, 4, numeric, index) + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setInfo(self, kind, method): + structs = [ + ( 9, 11, 2, numeric, kind), + (11, 13, 2, numeric, method) + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setBankAgreement(self, agreement): + structs = [ + (32, 52, 20, alphaNumeric, agreement), + ] + self.content = Row.setStructs(structs=structs, content=self.content) diff --git a/febraban/cnab240/bradesco/multipag/file/lot.py b/febraban/cnab240/bradesco/multipag/file/lot.py new file mode 100644 index 0000000..83da9a8 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/lot.py @@ -0,0 +1,99 @@ +from febraban.cnab240.libs.paymentKind import PaymentKind +from febraban.cnab240.libs.paymentMethod import PaymentMethod +from febraban.cnab240.bradesco.multipag.file.headerLot import HeaderLot +from febraban.cnab240.bradesco.multipag.file.trailerLot import TrailerLot +from febraban.cnab240.bradesco.multipag.payment.nonBarCodePayment import NonBarCodePayment + + +class Lot: + + def __init__(self): + self.headerLot = HeaderLot() + self.registers = [] + self.trailerLot = TrailerLot() + self.kind = "" + self.method = "" + self.amount = 0 + self.otherAmount = 0 + self.additionAmount = 0 + self.totalAmount = 0 + self.index = 1 + self.count = 0 + + def _isNonBarCodeTax(self): + return self.kind == PaymentKind.tribute and self.method in PaymentMethod.nonBarcodeTaxes() + + def add(self, register): + register.setPositionInLot(index=self.index) + self.registers.append(register) + self.amount += register.amountInCents() + if self._isNonBarCodeTax(): + self.otherAmount += register.otherAmountInCents() + self.additionAmount += register.additionAmountInCents() + self.totalAmount += register.totalAmountInCents() + self.index += 1 + + def setLotNumber(self, index): + self.headerLot.setPositionInLot(index) + self.trailerLot.setPositionInLot(index) + for register in self.registers: + register.setLot(index) + + def setSender(self, sender): + self.headerLot.setSender(sender) + self.headerLot.setSenderBank(sender.bank) + self.headerLot.setSenderAddress(sender.address) + self.headerLot.setBankAgreement(sender.bank.bankAgreement) + self.trailerLot.setSenderBank(sender.bank) + + def toString(self): + self.count = (2+self._count(NonBarCodePayment)) + self.trailerLot.setLotNumberOfRegisters( + num=self.count + ) + + if self._isNonBarCodeTax(): + self.trailerLot.setSumOfValuesNonBarCodeTax( + sum=self.amount, + otherSum=self.otherAmount, + totalSum=self.totalAmount, + ) + elif self._isBoletoPayment(): + self.trailerLot.setSumOfValues(sum=self.totalAmount) + else: + self.trailerLot.setSumOfValues(sum=self.amount) + + registersToString = "\r\n".join([register.toString() for register in self.registers]) + return "%s\r\n%s\r\n%s" % ( + self.headerLot.content, + registersToString, + self.trailerLot.content, + ) + + def _count(self, cls): + return len([register for register in self.registers if isinstance(register, cls)]) + + def setHeaderLotType(self, kind=PaymentKind.vendor, method=PaymentMethod.tedOther): + """ + Trasfers: + kind: String - Kind of payment - 20 Fornecedores, read: NOTES 4 + method: String - Payment method - 41 TED Outro titular, 43 TED Mesmo titular, 01 ITAU account. read: NOTES 5 + + Charge-payments: + kind: String - Kind of payment - 98 Diversos, read: NOTES 4 + method: String - Payment method - 30 Pagamento Boleto Itau, 31 Pagamento Boleto outros Bancos. read: NOTES 5 + + Utilities: + kind: String - Kind of payment - 98 Diversos, read: NOTES 4 + method: String - Payment method - 13 Concessionarias. read: NOTES 5 + + Tax-payments: + kind: String - Kind of payment - 22 Tributos, read: NOTES 4 + method: String - Payment method - 91 GNRE e Tributos com Codigo de Barras, + 19 IPTU/ISS/Outros Tributos Municipais. read: NOTES 5, + 16 DARF (No barcode) + + """ + self.kind = kind + self.method = method + self.headerLot.setInfo(kind, method) diff --git a/febraban/cnab240/bradesco/multipag/file/trailer.py b/febraban/cnab240/bradesco/multipag/file/trailer.py new file mode 100644 index 0000000..f296494 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/trailer.py @@ -0,0 +1,29 @@ +from febraban.cnab240.row import Row +from febraban.cnab240.characterType import numeric + + +class Trailer: + def __init__(self): + self.content = " " * 240 + self.defaultValues() + + def defaultValues(self): + structs = [ + (3, 7, 4, numeric, "9999"), + (7, 8, 1, numeric, "9"), + (29, 35, 6, numeric, "000000"), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderBank(self, bank): + structs = [ + (0, 3, 3, numeric, bank.bankId), # Debit bank code + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setNumberOfLotsAndRegisters(self, sum, num): + structs = [ + (17, 23, 6, numeric, num), + (23, 29, 6, numeric, sum), + ] + self.content = Row.setStructs(structs=structs, content=self.content) diff --git a/febraban/cnab240/bradesco/multipag/file/trailerLot.py b/febraban/cnab240/bradesco/multipag/file/trailerLot.py new file mode 100644 index 0000000..4b38b69 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/file/trailerLot.py @@ -0,0 +1,50 @@ +from febraban.cnab240.row import Row +from febraban.cnab240.characterType import numeric + + +class TrailerLot: + + def __init__(self): + self.content = " " * 240 + self.defaultValues() + + def defaultValues(self): + structs = [ + ( 3, 7, 4, numeric, "1"), + ( 7, 8, 1, numeric, "5"), + (41, 59, 18, numeric, "000000000000000000"), + (59, 65, 6, numeric, "000000"), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setLotNumberOfRegisters(self, num): + structs = [ + (17, 23, 6, numeric, num), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSumOfValues(self, sum): + structs = [ + (23, 41, 18, numeric, sum), # Sum of values of lots + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSumOfValuesNonBarCodeTax(self, sum, otherSum, totalSum): + structs = [ + (23, 41, 18, numeric, sum), # Sum of main values of lots + (41, 59, 13, numeric, otherSum), # Sum of other entities values of lots + (59, 65, 0, numeric, totalSum), # Sum of total values of lots + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderBank(self, bank): + structs = [ + (0, 3, 3, numeric, bank.bankId), # Debit bank code + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setPositionInLot(self, index): + structs = [ + (3, 7, 4, numeric, index) # Indicates lot index + ] + self.content = Row.setStructs(structs=structs, content=self.content) diff --git a/febraban/cnab240/bradesco/multipag/payment/__init__.py b/febraban/cnab240/bradesco/multipag/payment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/febraban/cnab240/bradesco/multipag/payment/darfPayment.py b/febraban/cnab240/bradesco/multipag/payment/darfPayment.py new file mode 100644 index 0000000..44eefac --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/payment/darfPayment.py @@ -0,0 +1,106 @@ +from febraban.cnab240.bradesco.multipag.payment.nonBarCodePayment import NonBarCodePayment + + +class DarfPayment(NonBarCodePayment): + + def setPayment(self, **kwargs): + self.setSender(kwargs.get("sender")) + self.setTaxPaymentIdentifier("16") + self.setRevenueCode(kwargs.get("revenueCode")) + self.setTaxIdInfo(kwargs.get("taxId")) + self.setReferenceDate(kwargs.get("referenceDate")) + self.setReferenceNumber(kwargs.get("referenceNumber")) + self.setNominalAmount(kwargs.get("amount")) + self.setFineAmount(kwargs.get("fine")) + self.setInterestAmount(kwargs.get("interest")) + self.setTotalAmount(kwargs.get("totalAmount")) + self.setDueDate(kwargs.get("dueDate")) + self.setIdentifier(kwargs.get("identifier")) + self.setOurNumber(kwargs.get("ourNumber")) + self.setIdentifier(kwargs.get("identifier")) + self.setRevenueCode(kwargs.get("revenueCode")) + + def setRevenueCode(self, code): + self.segmentN.setRevenueCode(code) + + def setIdentifier(self, identifier): + self.segmentN.setIdentifier(identifier) + + def setOurNumber(self, ourNumber): + self.segmentN.setOurNumber(ourNumber) + + def setTaxPaymentIdentifier(self, id): + self.segmentN.setTaxPaymentIdentifier(id) + + def setRevenueCode(self, code): + self.segmentN.setRevenueCode(code) + + def setTaxIdInfo(self, taxId): + taxId = "".join(c for c in taxId if c.isdigit()) + taxIdType = "2" if len(taxId) == 11 else "1" + self.segmentN.setTaxIdType(taxIdType) + self.segmentN.setTaxId(taxId) + + def setReferenceDate(self, referenceDate): + self.segmentN.setReferenceDate(referenceDate) + + def setReferenceNumber(self, referenceNumber): + self.segmentN.setReferenceNumber(referenceNumber) + + def setNominalAmount(self, amount): + self.segmentN.setNominalAmount(amount) + self.amount = int(amount) + + def setInterestAmount(self, interestAmount): + self.segmentN.setInterestAmount(interestAmount) + self.additionAmount += int(interestAmount) + + def setFineAmount(self, fineAmount): + self.segmentN.setFineAmount(fineAmount) + self.additionAmount += int(fineAmount) + + def setTotalAmount(self, totalAmount): + self.segmentN.setTotalAmount(totalAmount) + self.totalAmount = int(totalAmount) + + def setDueDate(self, dueDate): + self.segmentN.setDueDate(dueDate) + + def setPaymentDate(self, paymentDate): + self.segmentN.setPaymentDate(paymentDate) + + def setContributorName(self, name): + self.segmentN.setContributorName(name) + + def setOurNumber(self, ourNumber): + self.segmentN.setOurNumber(ourNumber) + + def setRevenueCode(self, code): + self.segmentN.setRevenueCode(code) + + def setTaxIdType(self, taxIdType): + self.segmentN.setTaxIdType(taxIdType) + + def setTaxId(self, taxId): + self.segmentN.setTaxId(taxId) + + def amountInCents(self): + return self.amount + + def otherAmountInCents(self): + return self.otherAmount + + def additionAmountInCents(self): + return self.additionAmount + + def setIdentifier(self, identifier): + self.segmentN.setIdentifier(identifier) + + def setSender(self, user): + self.segmentN.setSenderBank(user.bank) + + def setPositionInLot(self, index): + self.segmentN.setPositionInLot(index) + + def setLot(self, lot): + self.segmentN.setLot(lot) diff --git a/febraban/cnab240/bradesco/multipag/payment/nonBarCodePayment.py b/febraban/cnab240/bradesco/multipag/payment/nonBarCodePayment.py new file mode 100644 index 0000000..98f99c5 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/payment/nonBarCodePayment.py @@ -0,0 +1,39 @@ +from febraban.cnab240.bradesco.multipag.payment.segmentN import SegmentN + + +class NonBarCodePayment: + def __init__(self): + self.segmentN = SegmentN() + self.amount = 0 + self.otherAmount = 0 + self.additionAmount = 0 + self.totalAmount = 0 + + def toString(self): + return "\r\n".join(( + self.segmentN.content, + )) + + def amountInCents(self): + return self.amount + + def otherAmountInCents(self): + return self.otherAmount + + def additionAmountInCents(self): + return self.additionAmount + + def totalAmountInCents(self): + return self.totalAmount + + def setIdentifier(self, identifier): + self.segmentN.setIdentifier(identifier) + + def setSender(self, user): + self.segmentN.setSenderBank(user.bank) + + def setPositionInLot(self, index): + self.segmentN.setPositionInLot(index) + + def setLot(self, lot): + self.segmentN.setLot(lot) diff --git a/febraban/cnab240/bradesco/multipag/payment/segmentN.py b/febraban/cnab240/bradesco/multipag/payment/segmentN.py new file mode 100644 index 0000000..176e4fe --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/payment/segmentN.py @@ -0,0 +1,127 @@ +# coding: utf-8 +from febraban.cnab240.row import Row +from febraban.cnab240.characterType import alphaNumeric, numeric + + +class SegmentN: + def __init__(self): + self.content = " " * 240 + self.defaultValues() + + def defaultValues(self): + structs = [ + ( 3, 7, 4, numeric, "1"), + ( 7, 8, 1, numeric, "3"), # Type of record + ( 13, 14, 1, alphaNumeric, "N"), # Segment code + ( 14, 15, 1, numeric, "0"), # Movement type + ( 15, 17, 2, numeric, "00"), # Movement instruction code + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setSenderBank(self, bank): + structs = [ + (0, 3, 3, numeric, bank.bankId), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setLot(self, lot): + structs = [ + (3, 7, 4, numeric, lot), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setPositionInLot(self, index): + structs = [ + (8, 13, 5, numeric, index), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setIdentifier(self, identifier): + structs = [ + (17, 37, 20, alphaNumeric, identifier), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setOurNumber(self, ourNumber): + structs = [ + (37, 57, 20, alphaNumeric, ourNumber), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setContributorName(self, name): + structs = [ + (57, 87, 30, alphaNumeric, name), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setPaymentDate(self, date): + structs = [ + (87, 95, 8, numeric, date), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setTotalAmount(self, amount): + structs = [ + (95, 110, 15, numeric, amount), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setRevenueCode(self, code): + structs = [ + (110, 116, 6, alphaNumeric, code), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setTaxIdType(self, taxIdType): + structs = [ + (116, 118, 2, numeric, taxIdType), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setTaxId(self, taxId): + structs = [ + (118, 132, 14, alphaNumeric, taxId), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setTaxPaymentIdentifier(self, id): + structs = [ + (132, 134, 2, alphaNumeric, id), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setReferenceDate(self, referenceDate): + structs = [ + (134, 142, 8, numeric, referenceDate), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setReferenceNumber(self, referenceNumber): + structs = [ + (142, 159, 17, numeric, referenceNumber), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setNominalAmount(self, nominalAmount): + structs = [ + (159, 174, 15, numeric, nominalAmount), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setFineAmount(self, fineAmount): + structs = [ + (174, 189, 15, numeric, fineAmount), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setInterestAmount(self, interestAmount): + structs = [ + (189, 204, 15, numeric, interestAmount), + ] + self.content = Row.setStructs(structs=structs, content=self.content) + + def setDueDate(self, dueDate): + structs = [ + (204, 212, 8, numeric, dueDate), + ] + self.content = Row.setStructs(structs=structs, content=self.content) diff --git a/febraban/cnab240/bradesco/multipag/result/__init__.py b/febraban/cnab240/bradesco/multipag/result/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/febraban/cnab240/bradesco/multipag/result/occurrences.py b/febraban/cnab240/bradesco/multipag/result/occurrences.py new file mode 100644 index 0000000..52bcc4c --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/result/occurrences.py @@ -0,0 +1,129 @@ +# coding: utf-8 + +occurrences = { + "00": "Crédito ou Débito Efetivado", + "01": "Insuficiência de Fundos", + "02": "Crédito ou Débito Cancelado pelo Pagador/Credor", + "03": "Débito Autorizado pela Agência", + "AA": "Controle Inválido", + "AB": "Tipo de Operação Inválido", + "AC": "Tipo de Serviço Inválido", + "AD": "Forma de Lançamento Inválida", + "AE": "Tipo/Número de Inscrição Inválido", + "AF": "Código de Convênio Inválido", + "AG": "Agência/Conta Corrente/DV Inválido", + "AH": "Nº Sequencial do Registro no Lote Inválido", + "AI": "Código de Segmento de Detalhe Inválido", + "AJ": "Tipo de Movimento Inválido", + "AK": "Código da Câmara de Compensação do Banco Favorecido/Depositário Inválido", + "AL": "Código do Banco Favorecido Inoperante nesta data ou Depositário Inválido", + "AM": "Agência Mantenedora da Conta Corrente do Favorecido Inválida", + "AN": "Conta Corrente/DV do Favorecido Inválido", + "AO": "Nome do Favorecido Não Informado", + "AP": "Data Lançamento Inválido", + "AQ": "Tipo/Quantidade da Moeda Inválido", + "AR": "Valor do Lançamento Inválido", + "AT": "Tipo/Número de Inscrição do Favorecido Inválido", + "AU": "Logradouro do Favorecido Não Informado", + "AV": "Nº do Local do Favorecido Não Informado", + "AW": "Cidade do Favorecido Não Informada", + "AX": "CEP/Complemento do Favorecido Inválido", + "AY": "Sigla do Estado do Favorecido Inválida", + "AZ": "Código/Nome do Banco Depositário Inválido", + "BA": "Código/Nome da Agência Depositária Não Informado", + "BB": "Seu Número Inválido", + "BC": "Nosso Número Inválido", + "BD": "Inclusão Efetuada com Sucesso", + "BE": "Alteração Efetuada com Sucesso", + "BF": "Exclusão Efetuada com Sucesso", + "BG": "Agência/Conta Impedida Legalmente", + "BH": "Empresa não pagou salário‘BI’ = Falecimento do mutuário", + "BJ": "Empresa não enviou remessa do mutuário", + "BK": "Empresa não enviou remessa no vencimento", + "BL": "Valor da parcela inválida", + "BM": "Identificação do contrato inválida", + "BN": "Operação de Consignação Incluída com Sucesso", + "BO": "Operação de Consignação Alterada com Sucesso", + "BP": "Operação de Consignação Excluída com Sucesso", + "BQ": "Operação de Consignação Liquidada com Sucesso", + "CA": "Código de Barras - Código do Banco Inválido", + "CB": "Código de Barras - Código da Moeda Inválido", + "CC": "Código de Barras - Dígito Verificador Geral Inválido", + "CD": "Código de Barras - Valor do Título Divergente/Inválido.", + "CE": "Código de Barras - Campo Livre Inválido", + "CF": "Valor do Documento Inválido", + "CG": "Valor do Abatimento Inválido", + "CH": "Valor do Desconto Inválido", + "CI": "Valor de Mora Inválido", + "CJ": "Valor da Multa Inválido", + "CK": "Valor do IR Inválido", + "CL": "Valor do ISS Inválido", + "CM": "Valor do IOF Inválido", + "CN": "Valor de Outras Deduções Inválido", + "CO": "Valor de Outros Acréscimos Inválido", + "CP": "Valor do INSS Inválido", + "HA": "Lote Não Aceito", + "HB": "Inscrição da Empresa Inválida para o Contrato", + "HC": "Convênio com a Empresa Inexistente/Inválido para o Contrato", + "HD": "Agência/Conta Corrente da Empresa Inexistente/Inválido para o Contrato", + "HE": "Tipo de Serviço Inválido para o Contrato", + "HF": "Conta Corrente da Empresa com Saldo Insuficiente", + "HG": "Lote de Serviço Fora de Sequência", + "HH": "Lote de Serviço Inválido", + "HI": "Arquivo não aceito", + "HJ": "Tipo de Registro Inválido", + "HK": "Código Remessa / Retorno Inválido", + "HL": "Versão de layout inválida", + "HM": "Mutuário não identificado", + "HN": "Tipo do benefício não permite empréstimo", + "HO": "Benefício cessado/suspenso", + "HP": "Benefício possui representante legal", + "HQ": "Benefício é do tipo PA (Pensão alimentícia)", + "HR": "Quantidade de contratos permitida excedida", + "HS": "Benefício não pertence ao Banco informado", + "HT": "Início do desconto informado já ultrapassado", + "HU": "Número da parcela inválida", + "HV": "Quantidade de parcela inválida", + "HW": "Margem consignável excedida para o mutuário dentro do prazo do contrato", + "HX": "Empréstimo já cadastrado", + "HY": "Empréstimo inexistente", + "HZ": "Empréstimo já encerrado", + "H1": "Arquivo sem trailer", + "H2": "Mutuário sem crédito na competência", + "H3": "Não descontado – outros motivos", + "H4": "Retorno de Crédito não pago", + "H5": "Cancelamento de empréstimo retroativo", + "H6": "Outros Motivos de Glosa", + "H7": "Margem consignável excedida para o mutuário acima do prazo do contrato", + "H8": "Mutuário desligado do empregador", + "IA": "Primeiro nome do mutuário diferente do primeiro nome do movimento do censo ou diferente da base de Titular do Benefício", + "TA": "Lote Não Aceito - Totais do Lote com Diferença", + "YA": "Título Não Encontrado", + "YB": "Identificador Registro Opcional Inválido", + "YC": "Código Padrão Inválido", + "YD": "Código de Ocorrência Inválido", + "YE": "Complemento de Ocorrência Inválido", + "YF": "Alegação já Informada", + "ZA": "Agência/Conta do Favorecido Substituída", + "ZB": "Divergência entre o primeiro e último nome do beneficiário versus primeiro e último nome na Receita Federal", + "ZC": "Confirmação de Antecipação de Valor", + "ZD": "Antecipação Parcial de Valor", + "ZE": "Título bloqueado na base", + "ZF": "Sistema em contingência – título valor maior que referência", + "ZG": "Sistema em contingência – título vencido", + "ZH": "Sistema em contingência – título indexado", + "ZI": "Beneficiário divergente", + "ZJ": "Limite de pagamentos parciais excedidos", + "ZK": "Boleto já liquidado", + # Exclusivo Layout CNAB Bradesco + "5A": "Agendado sob lista de debito", + "5B": "Pagamento não autoriza sob lista de debito", + "5C": "Lista com mais de uma modalidade", + "5D": "Lista com mais de uma data de pagamento", + "5E": "Número de lista duplicado", + "5F": "Lista de debito vencida e não autorizada", + "5I": "Ordem de Pagamento emitida", + "5J": "Ordem de pagamento com data limite vencida", + "5M": "Número de lista de debito invalida", + "5T": "Pagamento realizado em contrato na condição de TESTE", +} diff --git a/febraban/cnab240/bradesco/multipag/result/parser.py b/febraban/cnab240/bradesco/multipag/result/parser.py new file mode 100644 index 0000000..d28bf52 --- /dev/null +++ b/febraban/cnab240/bradesco/multipag/result/parser.py @@ -0,0 +1,160 @@ +from febraban.cnab240.bradesco.multipag.result import occurrences +from febraban.cnab240.libs.paymentType import NonBarcodeTaxPayment, BarcodePayment + +class PaymentResponseStatus: + + success = "success" + failed = "failed" + scheduled = "scheduled" + unknown = "unknown" + + +class PaymentType: + + transfer = "transfer" + chargePayment = "charge-payment" + nonBarcodeTaxPayment = "tax-payment" + barcodePayment = "barcode-payment" + + +class PaymentResponse: + + def __init__(self, identifier=None, occurrences=None, content=None, authentication=None, amountInCents=None, paymentType=None, nonBarcodeTax=None): + self.identifier = identifier + self.occurrences = occurrences + self.content = content or [] + self.authentication = authentication + self.amountInCents = amountInCents + self.type = paymentType + self.nonBarcodeTax = nonBarcodeTax + + def occurrencesText(self): + return [occurrences[occurrenceId] for occurrenceId in self.occurrences] + + def occurrencesTextAtIndex(self, index): + occurrenceId = self.occurrences[index] + return occurrences[occurrenceId] + + def status(self): + if "00" in self.occurrences: + return PaymentResponseStatus.success + if "BD" in self.occurrences: + return PaymentResponseStatus.scheduled + if [code in self.occurrences for code in ["RJ", "DV", "SS", "AP"]].count(True) > 0: + return PaymentResponseStatus.failed + return PaymentResponseStatus.unknown + + def contentText(self, breakLine="\n"): + return breakLine.join(self.content) + + +class PaymentParser: + + @classmethod + def parseFile(cls, file): + lines = file.readlines() + return cls.parseLines(lines) + + @classmethod + def parseText(cls, text): + lines = text.splitlines()[:-1] + return cls.parseLines(lines) + + @classmethod + def parseLines(cls, lines): + result = [] + currentResponse = None + for line in lines: + if line[7] in ["0", "1", "9"]: + continue + + if line[7] == "3" and line[13] in ["A", "J", "O", "N"]: + if currentResponse is not None: + result.append(currentResponse) + currentResponse = PaymentResponse() + + if line[7] == "3" and line[13] == "A": + currentResponse.content.append(line) + currentResponse.identifier = cls._getIdentifierSegmentA(line) + currentResponse.occurrences = cls._getOccurrences(line) + currentResponse.amountInCents = cls._getAmountSegmentA(line) + currentResponse.type = PaymentType.transfer + elif line[7] == "3" and line[13] == "J": + currentResponse.content.append(line) + currentResponse.identifier = cls._getIdentifierSegmentJ(line) + currentResponse.occurrences = cls._getOccurrences(line) + currentResponse.amountInCents = cls._getAmountSegmentJ(line) + currentResponse.type = PaymentType.chargePayment + elif line[7] == "3" and line[13] == "O": + currentResponse.content.append(line) + currentResponse.identifier = cls._getIdentifierSegmentO(line) + currentResponse.occurrences = cls._getOccurrences(line) + currentResponse.amountInCents = cls._getAmountSegmentO(line) + currentResponse.type = PaymentType.barcodePayment + elif line[7] == "3" and line[13] == "N": + currentResponse.content.append(line) + currentResponse.identifier = cls._getIdentifierSegmentN(line) + currentResponse.occurrences = cls._getOccurrences(line) + currentResponse.nonBarcodeTax = cls._getNonBarcodeTaxSegmentN(line) + currentResponse.type = ( + PaymentType.barcodePayment + if currentResponse.nonBarcodeTax == BarcodePayment.fgts + else PaymentType.nonBarcodeTaxPayment + ) + elif line[7] == "3" and line[13] == "Z": + currentResponse.content.append(line) + currentResponse.authentication = cls._getAuthentication(line) + + if line[7] == "5" and currentResponse is not None: + result.append(currentResponse) + currentResponse = None + + return result + + @classmethod + def _getOccurrences(cls, line): + occurrencesString = line[230:240].strip() + return cls._splitString(occurrencesString) + + @classmethod + def _splitString(cls, string): + return [string[i:i+2] for i in range(0, len(string), 2)] + + @classmethod + def _getAmountSegmentA(cls, line): + return int(line[119:134].strip()) + + @classmethod + def _getAmountSegmentJ(cls, line): + return int(line[152:167].strip()) + + @classmethod + def _getAmountSegmentO(cls, line): + return int(line[144:159].strip()) + + @classmethod + def _getIdentifierSegmentA(self, line): + return line[73:93].strip() + + @classmethod + def _getIdentifierSegmentJ(self, line): + return line[182:202].strip() + + @classmethod + def _getIdentifierSegmentO(self, line): + return line[174:194].strip() + + @classmethod + def _getIdentifierSegmentN(self, line): + return line[195:215].strip() + + @classmethod + def _getAuthentication(cls, line): + return line[14:78].strip() + + @classmethod + def _getNonBarcodeTaxSegmentN(self, line): + taxTypeId = line[17:19].strip() + return { + "02": NonBarcodeTaxPayment.darf, + }[taxTypeId] diff --git a/febraban/cnab240/user.py b/febraban/cnab240/user.py index 430f694..fe970ef 100644 --- a/febraban/cnab240/user.py +++ b/febraban/cnab240/user.py @@ -11,12 +11,13 @@ def __init__(self, name, identifier, bank=None, address=None): class UserBank: - def __init__(self, bankId, branchCode, accountNumber, accountVerifier, bankName=""): + def __init__(self, bankId, branchCode, accountNumber, accountVerifier, bankName="", bankAgreement=""): self.bankId = bankId self.bankName = bankName self.accountNumber = accountNumber self.branchCode = branchCode self.accountVerifier = accountVerifier + self.bankAgreement = bankAgreement class UserAddress: diff --git a/sample-bradesco-darf-payment.py b/sample-bradesco-darf-payment.py new file mode 100644 index 0000000..a38f190 --- /dev/null +++ b/sample-bradesco-darf-payment.py @@ -0,0 +1,65 @@ +from datetime import datetime +from febraban.cnab240.bradesco.multipag.file.lot import Lot +from febraban.cnab240.bradesco.multipag.file.file import File +from febraban.cnab240.user import User, UserAddress, UserBank +from febraban.cnab240.bradesco.multipag.payment.darfPayment import DarfPayment + + +myself = User( + name="STARK BANK SA", + identifier="20018183000180", + bank=UserBank( + bankId="237", + branchCode="0156", + accountNumber="000000018807", + accountVerifier="7", + bankName="BANCO BRADESCO SA", + bankAgreement="610242" + ), + address=UserAddress( + streetLine1="AV PAULISTA 1000", + streetLine2="CJ 601", + city="SAO PAULO", + stateCode="SP", + zipCode="01310000" + ) +) + +now = datetime.now() + +file = File(sequenceNumber=1) +file.setSender(myself) + +lot = Lot() +lot.setSender(myself) +lot.setHeaderLotType( + kind="22", + method="16" +) +for i in range(1, 10): + darfPayment = DarfPayment() + amount = 10000 * i + fine = 2000 + interest = 3000 + print(f"{amount + fine + interest}") + darfPayment.setPayment( + sender=myself, + taxId="18604973000103", + revenueCode="2089", + referenceDate="19012025", + referenceNumber="1234567890", + amount=f"{amount}", + fine=f"{fine}", + interest=f"{interest}", + totalAmount=f"{amount + fine + interest}", + identifier="1234567890", + dueDate="31122025", + ourNumber=f"{i}", + ) + darfPayment.setPaymentDate(datetime.now().strftime("%d%m%Y")) + lot.add(register=darfPayment) + + +file.addLot(lot) +# file.add(register=lot) +file.output(fileName="output1.REM", path="/../../") \ No newline at end of file