From 3a385c63e3d4b5ce30e9896b409f8c33a8dd774f Mon Sep 17 00:00:00 2001 From: Rodia Date: Mon, 30 Dec 2024 19:00:51 -0500 Subject: [PATCH] Feat: Attachment, ParentDocumentLine --- facho/fe/form_xml/attached_document.py | 60 +- facho/fe/form_xml/invoice.py | 879 ++++++++++++++----------- tests/test_attached_document.py | 58 +- 3 files changed, 614 insertions(+), 383 deletions(-) diff --git a/facho/fe/form_xml/attached_document.py b/facho/fe/form_xml/attached_document.py index 1eff60a..c6495fd 100644 --- a/facho/fe/form_xml/attached_document.py +++ b/facho/fe/form_xml/attached_document.py @@ -5,11 +5,12 @@ __all__ = ['AttachedDocument'] class AttachedDocument(): - def __init__(self, invoice, id): + def __init__(self, invoice, DIANInvoiceXML, id): self.schema =\ 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2' self.id = id self.invoice = invoice + self.DIANInvoiceXML = DIANInvoiceXML self.attached_document_invoice = self.attached_document_invoice() # self.fexml.placeholder_for( @@ -43,7 +44,8 @@ class AttachedDocument(): # DIAN 1.9.-2023: AE05 self.fexml.set_element( - './cbc:IssueDate', self.invoice.invoice_issue.strftime('%Y-%m-%d')) + './cbc:IssueDate', + self.invoice.invoice_issue.strftime('%Y-%m-%d')) # DIAN 1.9.-2023: AE06 self.fexml.set_element( @@ -163,11 +165,63 @@ class AttachedDocument(): # DIAN 1.9.-2023: AE37 self.fexml.set_element( './cac:Attachment/cac:ExternalReference/cbc:Description', - ' ') + self._build_attachment(self.DIANInvoiceXML) + ) + + def _build_attachment(self, DIANInvoiceXML): + document = ( + '' + ) + DIANInvoiceXML.tostring() + attachment = "".format( + document) + + return attachment def set_parent_document_line_reference(self): self.fexml.placeholder_for( './cac:ParentDocumentLineReference') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cbc:LineID', 1) + self.fexml.placeholder_for( + './cac:ParentDocumentLineReference/cac:DocumentReference') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cbc:ID', + '1234') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cbc:UUID', + '1234', + schemeName="CUFE-SHA384") + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cbc:IssueDate', + '2024-11-28') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cbc:DocumentType', + 'ApplicationResponse') + self.fexml.placeholder_for( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:MimeCode', + 'text/xml') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:EncodingCode', + 'UTF-8') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:Description', + ' ') + self.fexml.placeholder_for( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:ResultOfVerification') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:ResultOfVerification/cbc:ValidatorID', + 'Unidad Especial Dirección de Impuestos y Aduanas Nacionales') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:ResultOfVerification/cbc:ValidationResultCode', + '02') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:ResultOfVerification/cbc:ValidationDate', + '2024-11-28') + self.fexml.set_element( + './cac:ParentDocumentLineReference/cac:DocumentReference/cac:ResultOfVerification/cbc:ValidationTime', + '10:35:11-05:00') def toFachoXML(self): return self.fexml diff --git a/facho/fe/form_xml/invoice.py b/facho/fe/form_xml/invoice.py index c009d43..cbf541c 100644 --- a/facho/fe/form_xml/invoice.py +++ b/facho/fe/form_xml/invoice.py @@ -1,6 +1,7 @@ from .. import fe from ..form import * from collections import defaultdict +from .attached_document import AttachedDocument __all__ = ['DIANInvoiceXML'] @@ -10,354 +11,478 @@ class DIANInvoiceXML(fe.FeXML): lo indicado para la facturacion electronica. """ - def __init__(self, invoice, tag_document = 'Invoice'): + def __init__(self, invoice, tag_document='Invoice'): super().__init__(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1') self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl') self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource') self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode') self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID') - + # ZE02 se requiere existencia para firmar ublextension = self.fragment('./ext:UBLExtensions/ext:UBLExtension', append=True) extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent') - self.attach_invoice(invoice) + self.attach_invoice = self.attach_invoice(invoice) + + # self.attach_document = self.attached_document_invoice(attach_invoice) + + def attach_invoice(fexml, invoice): + """adiciona etiquetas a FEXML y retorna FEXML + en caso de fallar validacion retorna None""" + + fexml.placeholder_for('./ext:UBLExtensions') + fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1') + fexml.set_element( + './cbc:CustomizationID', invoice.invoice_operation_type) + fexml.placeholder_for('./cbc:ProfileID') + fexml.placeholder_for('./cbc:ProfileExecutionID') + fexml.set_element('./cbc:ID', invoice.invoice_ident) + fexml.placeholder_for('./cbc:UUID') + fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d')) + # DIAN 1.7.-2020: FAD10 + fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00')) + fexml.set_element( + './cbc:%sTypeCode' % (fexml.tag_document()), + invoice.invoice_type_code, + listAgencyID='195', + listAgencyName='No matching global declaration available for the validation root', + listURI='http://www.dian.gov.co') + fexml.set_element('./cbc:DocumentCurrencyCode', 'COP') + fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines)) + if fexml.tag_document() == 'Invoice': + fexml.set_element('./cac:%sPeriod/cbc:StartDate' % ( + fexml.tag_document()), + invoice.invoice_period_start.strftime( + '%Y-%m-%d')) + fexml.set_element('./cac:%sPeriod/cbc:EndDate' % ( + fexml.tag_document()), + invoice.invoice_period_end.strftime('%Y-%m-%d')) + fexml.set_billing_reference(invoice) + fexml.customize(invoice) + fexml.set_supplier(invoice) + fexml.set_customer(invoice) + fexml.set_payment_mean(invoice) + fexml.set_invoice_totals(invoice) + fexml.set_legal_monetary(invoice) + fexml.set_invoice_lines(invoice) + fexml.set_allowance_charge(invoice) + + return fexml + + def attached_document_invoice(fexml, invoice): + attach_invoice = fexml.attach_invoice(invoice) + attached_document = AttachedDocument( + invoice, '123', attach_invoice) + + return attached_document def set_supplier(fexml, invoice): fexml.placeholder_for('./cac:AccountingSupplierParty') - #DIAN 1.7.-2020: CAJ02 - #DIAN 1.7.-2020: FAJ02 - fexml.set_element('./cac:AccountingSupplierParty/cbc:AdditionalAccountID', - invoice.invoice_supplier.organization_code) + # DIAN 1.7.-2020: CAJ02 + # DIAN 1.7.-2020: FAJ02 + fexml.set_element( + './cac:AccountingSupplierParty/cbc:AdditionalAccountID', + invoice.invoice_supplier.organization_code) - #DIAN 1.7.-2020: CAJ06 - #DIAN 1.7.-2020: FAJ06 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name', - invoice.invoice_supplier.name) + # DIAN 1.7.-2020: CAJ06 + # DIAN 1.7.-2020: FAJ06 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name', + invoice.invoice_supplier.name) - #DIAN 1.7.-2020: CAJ07, CAJ08 - #DIAN 1.7.-2020: FAJ07 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address') + # DIAN 1.7.-2020: CAJ07, CAJ08 + # DIAN 1.7.-2020: FAJ07 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address') - #DIAN 1.7.-2020: FAJ08 - #DIAN 1.7.-2020: CAJ09 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID', - invoice.invoice_supplier.address.city.code) - #DIAN 1.7.-2020: FAJ09 - #DIAN 1.7.-2020: CAJ10 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', - invoice.invoice_supplier.address.city.name) - #DIAN 1.7.-2020: FAJ11 - #DIAN 1.7.-2020: CAJ11 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity', - invoice.invoice_supplier.address.countrysubentity.name) + # DIAN 1.7.-2020: FAJ08 + # DIAN 1.7.-2020: CAJ09 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID', + invoice.invoice_supplier.address.city.code) + # DIAN 1.7.-2020: FAJ09 + # DIAN 1.7.-2020: CAJ10 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', + invoice.invoice_supplier.address.city.name) + # DIAN 1.7.-2020: FAJ11 + # DIAN 1.7.-2020: CAJ11 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity', + invoice.invoice_supplier.address.countrysubentity.name) - #DIAN 1.7.-2020: FAJ12 - #DIAN 1.7.-2020: CAJ12 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', - invoice.invoice_supplier.address.countrysubentity.code) - #DIAN 1.7.-2020: FAJ14 - #DIAN 1.7.-2020: CAJ13, CAJ14 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', - invoice.invoice_supplier.address.street) + # DIAN 1.7.-2020: FAJ12 + # DIAN 1.7.-2020: CAJ12 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', + invoice.invoice_supplier.address.countrysubentity.code) + # DIAN 1.7.-2020: FAJ14 + # DIAN 1.7.-2020: CAJ13, CAJ14 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', + invoice.invoice_supplier.address.street) - #DIAN 1.7.-2020: FAJ16 - #DIAN 1.7.-2020: CAJ16, CAJ16 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode', - invoice.invoice_supplier.address.country.code) + # DIAN 1.7.-2020: FAJ16 + # DIAN 1.7.-2020: CAJ16, CAJ16 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode', + invoice.invoice_supplier.address.country.code) - #DIAN 1.7.-2020: FAJ17 - #DIAN 1.7.-2020: CAJ17 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name', - invoice.invoice_supplier.address.country.name, - #DIAN 1.7.-2020: FAJ18 - languageID = 'es') + # DIAN 1.7.-2020: FAJ17 + # DIAN 1.7.-2020: CAJ17 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name', + invoice.invoice_supplier.address.country.name, + # DIAN 1.7.-2020: FAJ18 + languageID='es') supplier_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy() - supplier_company_id_attrs.update({'schemeID': invoice.invoice_supplier.ident.dv, - 'schemeName': invoice.invoice_supplier.ident.type_fiscal}) + supplier_company_id_attrs.update({ + 'schemeID': invoice.invoice_supplier.ident.dv, + 'schemeName': invoice.invoice_supplier.ident.type_fiscal + }) - #DIAN 1.7.-2020: FAJ19 - #DIAN 1.7.-2020: CAJ19 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme') + # DIAN 1.7.-2020: FAJ19 + # DIAN 1.7.-2020: CAJ19 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme') - #DIAN 1.7.-2020: FAJ20 - #DIAN 1.7.-2020: CAJ20 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', - invoice.invoice_supplier.legal_name) + # DIAN 1.7.-2020: FAJ20 + # DIAN 1.7.-2020: CAJ20 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', + invoice.invoice_supplier.legal_name) - #DIAN 1.7.-2020: FAJ21 - #DIAN 1.7.-2020: CAJ21 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', - invoice.invoice_supplier.ident, - #DIAN 1.7.-2020: FAJ22,FAJ23,FAJ24,FAJ25 - **supplier_company_id_attrs) - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', - #DIAN 1.7.-2020: FAJ26 - #DIAN 1.7.-2020: CAJ26 - invoice.invoice_supplier.responsability_code, - #DIAN 1.7.-2020: FAJ27 - #DIAN 1.7.-2020: CAJ27 - listName=invoice.invoice_supplier.responsability_regime_code) - #DIAN 1.7.-2020: FAJ28 - #DIAN 1.7.-2020: CAJ28 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress') + # DIAN 1.7.-2020: FAJ21 + # DIAN 1.7.-2020: CAJ21 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', + invoice.invoice_supplier.ident, + # DIAN 1.7.-2020: FAJ22,FAJ23,FAJ24,FAJ25 + **supplier_company_id_attrs) + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', + # DIAN 1.7.-2020: FAJ26 + # DIAN 1.7.-2020: CAJ26 + invoice.invoice_supplier.responsability_code, + # DIAN 1.7.-2020: FAJ27 + # DIAN 1.7.-2020: CAJ27 + listName=invoice.invoice_supplier.responsability_regime_code) + # DIAN 1.7.-2020: FAJ28 + # DIAN 1.7.-2020: CAJ28 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress') - #DIAN 1.7.-2020: FAJ29 - #DIAN 1.7.-2020: CAJ29 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID', - invoice.invoice_supplier.address.city.code) + # DIAN 1.7.-2020: FAJ29 + # DIAN 1.7.-2020: CAJ29 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID', + invoice.invoice_supplier.address.city.code) - #DIAN 1.7.-2020: FAJ30 - #DIAN 1.7.-2020: CAJ30 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName', invoice.invoice_supplier.address.city.name) + # DIAN 1.7.-2020: FAJ30 + # DIAN 1.7.-2020: CAJ30 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName', invoice.invoice_supplier.address.city.name) - #DIAN 1.7.-2020: FAJ31 - #DIAN 1.7.-2020: CAJ31 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity', - invoice.invoice_supplier.address.countrysubentity.name) + # DIAN 1.7.-2020: FAJ31 + # DIAN 1.7.-2020: CAJ31 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity', + invoice.invoice_supplier.address.countrysubentity.name) - #DIAN 1.7.-2020: FAJ32 - #DIAN 1.7.-2020: CAJ32 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode', - invoice.invoice_supplier.address.countrysubentity.code) + # DIAN 1.7.-2020: FAJ32 + # DIAN 1.7.-2020: CAJ32 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode', + invoice.invoice_supplier.address.countrysubentity.code) - #DIAN 1.7.-2020: FAJ33,FAJ34 - #DIAN 1.7.-2020: CAJ33,CAJ34 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line', - invoice.invoice_supplier.address.street) + # DIAN 1.7.-2020: FAJ33,FAJ34 + # DIAN 1.7.-2020: CAJ33,CAJ34 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line', + invoice.invoice_supplier.address.street) - #DIAN 1.7.-2020: FAJ35,FAJ36 - #DIAN 1.7.-2020: CAJ35,CAJ36 + # DIAN 1.7.-2020: FAJ35,FAJ36 + # DIAN 1.7.-2020: CAJ35,CAJ36 fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode', invoice.invoice_supplier.address.country.code) - #DIAN 1.7.-2020: FAJ37,FAJ38 - #DIAN 1.7.-2020: CAJ37,CAJ38 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name', - invoice.invoice_supplier.address.country.name, - languageID='es') + # DIAN 1.7.-2020: FAJ37,FAJ38 + # DIAN 1.7.-2020: CAJ37,CAJ38 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name', + invoice.invoice_supplier.address.country.name, + languageID='es') - #DIAN 1.7.-2020: FAJ39 - #DIAN 1.7.-2020: CAJ39 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') + # DIAN 1.7.-2020: FAJ39 + # DIAN 1.7.-2020: CAJ39 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') - #DIAN 1.7.-2020: CAJ40 - #DIAN 1.7.-2020: FAJ40 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', - invoice.invoice_customer.tax_scheme.code) + # DIAN 1.7.-2020: CAJ40 + # DIAN 1.7.-2020: FAJ40 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', + invoice.invoice_customer.tax_scheme.code) - #DIAN 1.7.-2020: CAJ41 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', - invoice.invoice_customer.tax_scheme.name) + # DIAN 1.7.-2020: CAJ41 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', + invoice.invoice_customer.tax_scheme.name) - #DIAN 1.7.-2020: FAJ42 - #DIAN 1.7.-2020: CAJ42 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity') + # DIAN 1.7.-2020: FAJ42 + # DIAN 1.7.-2020: CAJ42 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity') - #DIAN 1.7.-2020: FAJ43 - #DIAN 1.7.-2020: CAJ43 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName', - invoice.invoice_supplier.legal_name) + # DIAN 1.7.-2020: FAJ43 + # DIAN 1.7.-2020: CAJ43 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName', + invoice.invoice_supplier.legal_name) - #DIAN 1.7.-2020: FAJ44,FAJ45,FAJ46,FAJ47,FAJ48 - #DIAN 1.7.-2020: CAJ44,CAJ45,CAJ46,CAJ47,CAJ48 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID', - invoice.invoice_supplier.ident, - **supplier_company_id_attrs) + # DIAN 1.7.-2020: FAJ44,FAJ45,FAJ46,FAJ47,FAJ48 + # DIAN 1.7.-2020: CAJ44,CAJ45,CAJ46,CAJ47,CAJ48 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID', + invoice.invoice_supplier.ident, + **supplier_company_id_attrs) - #DIAN 1.7.-2020: FAJ49 - #DIAN 1.7.-2020: CAJ49 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme') + # DIAN 1.7.-2020: FAJ49 + # DIAN 1.7.-2020: CAJ49 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme') - #DIAN 1.7.-2020: FAJ50 - #DIAN 1.7.-2020: CAJ50 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme/cbc:ID', - invoice.invoice_ident_prefix) + # DIAN 1.7.-2020: FAJ50 + # DIAN 1.7.-2020: CAJ50 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme/cbc:ID', + invoice.invoice_ident_prefix) - #DIAN 1.7.-2020: CAJ67 - fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:Contact') - - #DIAN 1.7.-2020: FAJ71 - #DIAN 1.7.-2020: CAJ71 - fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail', - invoice.invoice_supplier.email) + # DIAN 1.7.-2020: CAJ67 + fexml.placeholder_for( + './cac:AccountingSupplierParty/cac:Party/cac:Contact') + # DIAN 1.7.-2020: FAJ71 + # DIAN 1.7.-2020: CAJ71 + fexml.set_element( + './cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail', + invoice.invoice_supplier.email) def set_customer(fexml, invoice): fexml.placeholder_for('./cac:AccountingCustomerParty') - fexml.set_element('./cac:AccountingCustomerParty/cbc:AdditionalAccountID', - invoice.invoice_customer.organization_code) - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID', - invoice.invoice_customer.ident) - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name', - invoice.invoice_customer.name) + fexml.set_element( + './cac:AccountingCustomerParty/cbc:AdditionalAccountID', + invoice.invoice_customer.organization_code) + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID', + invoice.invoice_customer.ident) + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name', + invoice.invoice_customer.name) - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation') + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation') customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy() - #DIAN 1.7.-2020: FAK25 - #DIAN 1.7.-2020: CAK25 - customer_company_id_attrs.update({'schemeID': invoice.invoice_customer.ident.dv, - 'schemeName': invoice.invoice_customer.ident.type_fiscal}) + # DIAN 1.7.-2020: FAK25 + # DIAN 1.7.-2020: CAK25 + customer_company_id_attrs.update({ + 'schemeID': invoice.invoice_customer.ident.dv, + 'schemeName': invoice.invoice_customer.ident.type_fiscal}) - #DIAN 1.7.-2020: FAK07 - #DIAN 1.7.-2020: CAK07 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address') + # DIAN 1.7.-2020: FAK07 + # DIAN 1.7.-2020: CAK07 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address') - #DIAN 1.7.-2020: FAK08 - #DIAN 1.7.-2020: CAK08 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID', - invoice.invoice_customer.address.city.code) - #DIAN 1.7.-2020: FAK09 - #DIAN 1.7.-2020: CAK09 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', invoice.invoice_customer.address.city.name) + # DIAN 1.7.-2020: FAK08 + # DIAN 1.7.-2020: CAK08 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID', + invoice.invoice_customer.address.city.code) + # DIAN 1.7.-2020: FAK09 + # DIAN 1.7.-2020: CAK09 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', invoice.invoice_customer.address.city.name) - #DIAN 1.7.-2020: FAK11 - #DIAN 1.7.-2020: CAK11 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity', - invoice.invoice_customer.address.countrysubentity.name) + # DIAN 1.7.-2020: FAK11 + # DIAN 1.7.-2020: CAK11 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity', + invoice.invoice_customer.address.countrysubentity.name) - #DIAN 1.7.-2020: FAK12 - #DIAN 1.7.-2020: CAK12 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', - invoice.invoice_customer.address.countrysubentity.code) + # DIAN 1.7.-2020: FAK12 + # DIAN 1.7.-2020: CAK12 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', + invoice.invoice_customer.address.countrysubentity.code) - #DIAN 1.7.-2020: CAK13, CAK14 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', - invoice.invoice_customer.address.street) + # DIAN 1.7.-2020: CAK13, CAK14 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', + invoice.invoice_customer.address.street) - #DIAN 1.7.-2020: CAK16 - #DIAN 1.7.-2020: FAK16 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode', - invoice.invoice_customer.address.country.code) + # DIAN 1.7.-2020: CAK16 + # DIAN 1.7.-2020: FAK16 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode', + invoice.invoice_customer.address.country.code) - #DIAN 1.7.-2020: FAK17 - #DIAN 1.7.-2020: CAK17 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name', - invoice.invoice_customer.address.country.name, - #DIAN 1.7.-2020: FAK18 - #DIAN 1.7.-2020: CAK18 - languageID='es') + # DIAN 1.7.-2020: FAK17 + # DIAN 1.7.-2020: CAK17 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name', + invoice.invoice_customer.address.country.name, + # DIAN 1.7.-2020: FAK18 + # DIAN 1.7.-2020: CAK18 + languageID='es') - #DIAN 1.7.-2020: FAK17,FAK19 - #DIAN 1.7.-2020: CAK19 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme') + # DIAN 1.7.-2020: FAK17,FAK19 + # DIAN 1.7.-2020: CAK19 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme') - #DIAN 1.7.-2020: FAK17,FAK20 - #DIAN 1.7.-2020: CAK20 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', - invoice.invoice_customer.legal_name) + # DIAN 1.7.-2020: FAK17,FAK20 + # DIAN 1.7.-2020: CAK20 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName', + invoice.invoice_customer.legal_name) - #DIAN 1.7.-2020: CAK21 - #DIAN 1.7.-2020: FAK21 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', - invoice.invoice_customer.ident, - #DIAN 1.7.-2020: CAK22, CAK23, CAK24, CAK25 - **customer_company_id_attrs) + # DIAN 1.7.-2020: CAK21 + # DIAN 1.7.-2020: FAK21 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID', + invoice.invoice_customer.ident, + # DIAN 1.7.-2020: CAK22, CAK23, CAK24, CAK25 + **customer_company_id_attrs) - #DIAN 1.7.-2020: CAK26 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', - #DIAN 1.7.-2020: FAK26 - invoice.invoice_customer.responsability_code, - #DIAN 1.7.-2020: FAK27 - #DIAN 1.7.-2020: CAK27 - listName=invoice.invoice_customer.responsability_regime_code) + # DIAN 1.7.-2020: CAK26 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode', + # DIAN 1.7.-2020: FAK26 + invoice.invoice_customer.responsability_code, + # DIAN 1.7.-2020: FAK27 + # DIAN 1.7.-2020: CAK27 + listName=invoice.invoice_customer.responsability_regime_code) - #DIAN 1.7.-2020: FAK28 - #DIAN 1.7.-2020: CAK28 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress') + # DIAN 1.7.-2020: FAK28 + # DIAN 1.7.-2020: CAK28 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress') - #DIAN 1.7.-2020: FAK29 - #DIAN 1.7.-2020: CAK29 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID', - invoice.invoice_customer.address.city.code) + # DIAN 1.7.-2020: FAK29 + # DIAN 1.7.-2020: CAK29 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID', + invoice.invoice_customer.address.city.code) - #DIAN 1.7.-2020: FAK30 - #DIAN 1.7.-2020: CAK30 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName', - invoice.invoice_customer.address.city.name) + # DIAN 1.7.-2020: FAK30 + # DIAN 1.7.-2020: CAK30 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName', + invoice.invoice_customer.address.city.name) - #DIAN 1.7.-2020: FAK31 - #DIAN 1.7.-2020: CAK31 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity', - invoice.invoice_customer.address.countrysubentity.name) + # DIAN 1.7.-2020: FAK31 + # DIAN 1.7.-2020: CAK31 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity', + invoice.invoice_customer.address.countrysubentity.name) - #DIAN 1.7.-2020: FAK32 - #DIAN 1.7.-2020: CAK32 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode', - invoice.invoice_customer.address.countrysubentity.code) + # DIAN 1.7.-2020: FAK32 + # DIAN 1.7.-2020: CAK32 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode', + invoice.invoice_customer.address.countrysubentity.code) - #DIAN 1.7.-2020: FAK33 - #DIAN 1.7.-2020: CAK33 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine') + # DIAN 1.7.-2020: FAK33 + # DIAN 1.7.-2020: CAK33 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine') - #DIAN 1.7.-2020: FAK34 - #DIAN 1.7.-2020: CAK34 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line', - invoice.invoice_customer.address.street) + # DIAN 1.7.-2020: FAK34 + # DIAN 1.7.-2020: CAK34 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line', + invoice.invoice_customer.address.street) - #DIAN 1.7.-2020: CAK35 - #DIAN 1.7.-2020: FAK35 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country') + # DIAN 1.7.-2020: CAK35 + # DIAN 1.7.-2020: FAK35 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country') - #DIAN 1.7.-2020: CAK36 - #DIAN 1.7.-2020: FAK36 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode', - invoice.invoice_customer.address.country.code) + # DIAN 1.7.-2020: CAK36 + # DIAN 1.7.-2020: FAK36 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode', + invoice.invoice_customer.address.country.code) - #DIAN 1.7.-2020: CAK37 - #DIAN 1.7.-2020: FAK37 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name', invoice.invoice_customer.address.country.name) + # DIAN 1.7.-2020: CAK37 + # DIAN 1.7.-2020: FAK37 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name', invoice.invoice_customer.address.country.name) - #DIAN 1.7.-2020: FAK38 - #DIAN 1.7.-2020: CAK38 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode', - invoice.invoice_customer.address.country.code, - languageID='es') + # DIAN 1.7.-2020: FAK38 + # DIAN 1.7.-2020: CAK38 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode', + invoice.invoice_customer.address.country.code, + languageID='es') - #DIAN 1.7.-2020: CAK39 - #DIAN 1.7.-2020: FAK39 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') + # DIAN 1.7.-2020: CAK39 + # DIAN 1.7.-2020: FAK39 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme') - #DIAN 1.7.-2020: CAK40 Machete Construir Validación - #DIAN 1.7.-2020: FAK40 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', - invoice.invoice_customer.tax_scheme.code) + # DIAN 1.7.-2020: CAK40 Machete Construir Validación + # DIAN 1.7.-2020: FAK40 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID', + invoice.invoice_customer.tax_scheme.code) - #DIAN 1.7.-2020: FAK41 - #DIAN 1.7.-2020: CAK41 Machete Construir Validación - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', - invoice.invoice_customer.tax_scheme.name) - #DIAN 1.7.-2020: FAK42 - #DIAN 1.7.-2020: CAK42 - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity') + # DIAN 1.7.-2020: FAK41 + # DIAN 1.7.-2020: CAK41 Machete Construir Validación + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name', + invoice.invoice_customer.tax_scheme.name) - #DIAN 1.7.-2020: FAK43 - #DIAN 1.7.-2020: CAK43 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName', - invoice.invoice_customer.legal_name) + # DIAN 1.7.-2020: FAK42 + # DIAN 1.7.-2020: CAK42 + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity') - #DIAN 1.7.-2020: CAK44 - #DIAN 1.7.-2020: FAK44,FAK45,FAK46,FAK47,FAK48 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID', - invoice.invoice_customer.ident, - **customer_company_id_attrs) + # DIAN 1.7.-2020: FAK43 + # DIAN 1.7.-2020: CAK43 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName', + invoice.invoice_customer.legal_name) - fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity') + # DIAN 1.7.-2020: CAK44 + # DIAN 1.7.-2020: FAK44,FAK45,FAK46,FAK47,FAK48 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID', + invoice.invoice_customer.ident, + **customer_company_id_attrs) - #DIAN 1.7.-2020: FAK55 - #DIAN 1.7.-2020: CAK51, CAK55 - fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail', - invoice.invoice_customer.email) + fexml.placeholder_for( + './cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity') + # DIAN 1.7.-2020: FAK55 + # DIAN 1.7.-2020: CAK51, CAK55 + fexml.set_element( + './cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail', + invoice.invoice_customer.email) def set_payment_mean(fexml, invoice): payment_mean = invoice.invoice_payment_mean - fexml.set_element('./cac:PaymentMeans/cbc:ID', payment_mean.id) - fexml.set_element('./cac:PaymentMeans/cbc:PaymentMeansCode', payment_mean.code) - fexml.set_element('./cac:PaymentMeans/cbc:PaymentDueDate', payment_mean.due_at.strftime('%Y-%m-%d')) - fexml.set_element('./cac:PaymentMeans/cbc:PaymentID', payment_mean.payment_id) + fexml.set_element( + './cac:PaymentMeans/cbc:ID', payment_mean.id) + fexml.set_element( + './cac:PaymentMeans/cbc:PaymentMeansCode', payment_mean.code) + fexml.set_element( + './cac:PaymentMeans/cbc:PaymentDueDate', payment_mean.due_at.strftime('%Y-%m-%d')) + fexml.set_element( + './cac:PaymentMeans/cbc:PaymentID', payment_mean.payment_id) def set_element_amount_for(fexml, xml, xpath, amount): if not isinstance(amount, Amount): @@ -505,38 +630,45 @@ class DIANInvoiceXML(fe.FeXML): cod_impuesto, amount_of = item next_append = index > 0 - #DIAN 1.7.-2020: FAS01 - line = fexml.fragment('./cac:WithholdingTaxTotal', append=next_append) - #DIAN 1.7.-2020: FAU06 + # DIAN 1.7.-2020: FAS01 + line = fexml.fragment( + './cac:WithholdingTaxTotal', append=next_append) + # DIAN 1.7.-2020: FAU06 tax_amount = amount_of['tax_amount'] - fexml.set_element_amount_for(line, - '/cac:WithholdingTaxTotal/cbc:TaxAmount', - tax_amount) + fexml.set_element_amount_for( + line, + '/cac:WithholdingTaxTotal/cbc:TaxAmount', + tax_amount) - #DIAN 1.7.-2020: FAS05 - fexml.set_element_amount_for(line, - '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', - amount_of['taxable_amount']) + # DIAN 1.7.-2020: FAS05 + fexml.set_element_amount_for( + line, + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', + amount_of['taxable_amount']) - #DIAN 1.7.-2020: FAU06 - fexml.set_element_amount_for(line, - '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', - amount_of['tax_amount']) + # DIAN 1.7.-2020: FAU06 + fexml.set_element_amount_for( + line, + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', + amount_of['tax_amount']) - #DIAN 1.7.-2020: FAS07 + # DIAN 1.7.-2020: FAS07 if percent_for[cod_impuesto]: - line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent', - percent_for[cod_impuesto]) - + line.set_element( + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent', + percent_for[cod_impuesto]) if percent_for[cod_impuesto]: - line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', - percent_for[cod_impuesto]) - - line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', - cod_impuesto) - line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', - 'ReteRenta') + line.set_element( + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', + percent_for[cod_impuesto]) + + line.set_element( + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', + cod_impuesto) + line.set_element( + '/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', + 'ReteRenta') # abstract method def tag_document(fexml): @@ -547,82 +679,115 @@ class DIANInvoiceXML(fe.FeXML): return 'Invoiced' def set_invoice_line_tax(fexml, line, invoice_line): - fexml.set_element_amount_for(line, - './cac:TaxTotal/cbc:TaxAmount', - invoice_line.tax_amount) + fexml.set_element_amount_for( + line, + './cac:TaxTotal/cbc:TaxAmount', + invoice_line.tax_amount) + + # DIAN 1.7.-2020: FAX05 + fexml.set_element_amount_for( + line, + './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', + invoice_line.taxable_amount) - #DIAN 1.7.-2020: FAX05 - fexml.set_element_amount_for(line, - './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', - invoice_line.taxable_amount) for subtotal in invoice_line.tax.subtotals: - line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP') + line.set_element( + './cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', + subtotal.tax_amount, + currencyID='COP') if subtotal.percent is not None: - line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2)) + line.set_element( + './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2)) if subtotal.scheme is not None: - #DIAN 1.7.-2020: FAX15 - line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) - line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) - + # DIAN 1.7.-2020: FAX15 + line.set_element( + './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) + line.set_element( + './cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) def set_invoice_line_withholding(fexml, line, invoice_line): - fexml.set_element_amount_for(line, - './cac:WithholdingTaxTotal/cbc:TaxAmount', - invoice_line.withholding_amount) - #DIAN 1.7.-2020: FAX05 - fexml.set_element_amount_for(line, - './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', - invoice_line.withholding_taxable_amount) + fexml.set_element_amount_for( + line, + './cac:WithholdingTaxTotal/cbc:TaxAmount', + invoice_line.withholding_amount) + + # DIAN 1.7.-2020: FAX05 + fexml.set_element_amount_for( + line, + './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount', + invoice_line.withholding_taxable_amount) for subtotal in invoice_line.withholding.subtotals: - line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP') + line.set_element( + './cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', + subtotal.tax_amount, + currencyID='COP') if subtotal.percent is not None: - line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2)) + line.set_element( + './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2)) if subtotal.scheme is not None: - #DIAN 1.7.-2020: FAX15 - line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) - line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) + # DIAN 1.7.-2020: FAX15 + line.set_element( + './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code) + line.set_element( + './cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name) - def set_invoice_lines(fexml, invoice): next_append = False for index, invoice_line in enumerate(invoice.invoice_lines): - line = fexml.fragment('./cac:%sLine' % (fexml.tag_document()), append=next_append) + line = fexml.fragment( + './cac:%sLine' % (fexml.tag_document()), + append=next_append) next_append = True line.set_element('./cbc:ID', index + 1) - line.set_element('./cbc:%sQuantity' % (fexml.tag_document_concilied()), invoice_line.quantity, unitCode = 'NAR') - fexml.set_element_amount_for(line, - './cbc:LineExtensionAmount', - invoice_line.total_amount) + line.set_element( + './cbc:%sQuantity' % ( + fexml.tag_document_concilied()), + invoice_line.quantity, + unitCode='NAR') + fexml.set_element_amount_for( + line, + './cbc:LineExtensionAmount', + invoice_line.total_amount) - if not isinstance(invoice_line.tax, TaxTotalOmit): + if not isinstance( + invoice_line.tax, TaxTotalOmit): fexml.set_invoice_line_tax(line, invoice_line) - if not isinstance(invoice_line.withholding, WithholdingTaxTotalOmit): + if not isinstance( + invoice_line.withholding, WithholdingTaxTotalOmit): fexml.set_invoice_line_withholding(line, invoice_line) - line.set_element('./cac:Item/cbc:Description', invoice_line.item.description) + line.set_element( + './cac:Item/cbc:Description', invoice_line.item.description) - line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID', - invoice_line.item.id, - schemeID=invoice_line.item.scheme_id, - schemeName=invoice_line.item.scheme_name, - schemeAgencyID=invoice_line.item.scheme_agency_id) + line.set_element( + './cac:Item/cac:StandardItemIdentification/cbc:ID', + invoice_line.item.id, + schemeID=invoice_line.item.scheme_id, + schemeName=invoice_line.item.scheme_name, + schemeAgencyID=invoice_line.item.scheme_agency_id) - line.set_element('./cac:Price/cbc:PriceAmount', invoice_line.price.amount, currencyID=invoice_line.price.amount.currency.code) - #DIAN 1.7.-2020: FBB04 - line.set_element('./cac:Price/cbc:BaseQuantity', - invoice_line.price.quantity, - unitCode=invoice_line.quantity.code) + line.set_element( + './cac:Price/cbc:PriceAmount', + invoice_line.price.amount, + currencyID=invoice_line.price.amount.currency.code) + + # DIAN 1.7.-2020: FBB04 + line.set_element( + './cac:Price/cbc:BaseQuantity', + invoice_line.price.quantity, + unitCode=invoice_line.quantity.code) for idx, charge in enumerate(invoice_line.allowance_charge): next_append_charge = idx > 0 - fexml.append_allowance_charge(line, index + 1, charge, append=next_append_charge) + fexml.append_allowance_charge( + line, index + 1, charge, append=next_append_charge) def set_allowance_charge(fexml, invoice): for idx, charge in enumerate(invoice.invoice_allowance_charge): @@ -650,46 +815,6 @@ class DIANInvoiceXML(fe.FeXML): fexml.set_element_amount_for( line, './cbc:BaseAmount', charge.base_amount) - def attach_invoice(fexml, invoice): - """adiciona etiquetas a FEXML y retorna FEXML - en caso de fallar validacion retorna None""" - - fexml.placeholder_for('./ext:UBLExtensions') - fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1') - fexml.set_element('./cbc:CustomizationID', invoice.invoice_operation_type) - fexml.placeholder_for('./cbc:ProfileID') - fexml.placeholder_for('./cbc:ProfileExecutionID') - fexml.set_element('./cbc:ID', invoice.invoice_ident) - fexml.placeholder_for('./cbc:UUID') - fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d')) - #DIAN 1.7.-2020: FAD10 - fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00')) - fexml.set_element('./cbc:%sTypeCode' % (fexml.tag_document()), - invoice.invoice_type_code, - listAgencyID='195', - listAgencyName='No matching global declaration available for the validation root', - listURI='http://www.dian.gov.co') - fexml.set_element('./cbc:DocumentCurrencyCode', 'COP') - fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines)) - if fexml.tag_document() == 'Invoice': - fexml.set_element('./cac:%sPeriod/cbc:StartDate' % ( - fexml.tag_document()), - invoice.invoice_period_start.strftime('%Y-%m-%d')) - - fexml.set_element('./cac:%sPeriod/cbc:EndDate' % ( - fexml.tag_document()), - invoice.invoice_period_end.strftime('%Y-%m-%d')) - fexml.set_billing_reference(invoice) - fexml.customize(invoice) - fexml.set_supplier(invoice) - fexml.set_customer(invoice) - fexml.set_payment_mean(invoice) - fexml.set_invoice_totals(invoice) - fexml.set_legal_monetary(invoice) - fexml.set_invoice_lines(invoice) - fexml.set_allowance_charge(invoice) - return fexml - def customize(fexml, invoice): """adiciona etiquetas a FEXML y retorna FEXML en caso de fallar validacion retorna None""" diff --git a/tests/test_attached_document.py b/tests/test_attached_document.py index 32160b9..b8e9e75 100644 --- a/tests/test_attached_document.py +++ b/tests/test_attached_document.py @@ -8,13 +8,29 @@ import pytest from facho.fe import form_xml from datetime import datetime import helpers - from fixtures import simple_invoice +simple_invoice = simple_invoice + +def test_xml_with_required_elements(simple_invoice): + + DIANInvoiceXML = form_xml.DIANInvoiceXML( + simple_invoice) + + doc = form_xml.AttachedDocument( + simple_invoice, + DIANInvoiceXML, + id='123') -def test_xml_with_required_elements(): - doc = form_xml.AttachedDocument(simple_invoice, id='123') xml = doc.toFachoXML() + + DIANInvoiceXML = form_xml.DIANInvoiceXML( + simple_invoice, 'Invoice').attach_invoice + + attached_document = ( + '' + ) + DIANInvoiceXML.tostring() + assert xml.get_element_text( '/atd:AttachedDocument/cbc:UBLVersionID') == 'UBL 2.1' assert xml.get_element_text( @@ -70,5 +86,41 @@ def test_xml_with_required_elements(): '/atd:AttachedDocument/cac:ReceiverParty/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name' ) == 'IVA' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:Attachment/cac:ExternalReference/cbc:MimeCode' + ) == "text/xml" + assert xml.get_element_text( + '/atd:AttachedDocument/cac:Attachment/cac:ExternalReference/cbc:EncodingCode' + ) == "UTF-8" + assert xml.get_element_text( + '/atd:AttachedDocument/cac:Attachment/cac:ExternalReference/cbc:Description' + ) == "".format(attached_document) + + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cbc:LineID' + ) == '1' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cbc:ID' + ) == '1234' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cbc:UUID' + ) == '1234' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cbc:IssueDate' + ) == '2024-11-28' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cbc:DocumentType' + ) == 'ApplicationResponse' + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:MimeCode' + ) == 'text/xml' + + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:EncodingCode' + ) == "UTF-8" + assert xml.get_element_text( + '/atd:AttachedDocument/cac:ParentDocumentLineReference/cac:DocumentReference/cac:Attachment/cac:ExternalReference/cbc:Description' + ) == " " + with open("output.xml", "w") as fh: fh.write(xml.tostring())