diff --git a/facho/fe/data/dian/codelist/__init__.py b/facho/fe/data/dian/codelist/__init__.py index feeaa45..c9f00f0 100644 --- a/facho/fe/data/dian/codelist/__init__.py +++ b/facho/fe/data/dian/codelist/__init__.py @@ -87,6 +87,7 @@ MediosPago = CodeList(path_for_codelist('MediosPago-2.1.gc'), 'code', 'name') FormasPago = CodeList(path_for_codelist('FormasPago-2.1.gc'), 'code', 'name') RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name') TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name') +TipoOperacionNCDS = CodeList(path_for_codelist('TipoOperacionNCDS-2.1.gc'), 'code', 'name') TipoOperacionND = CodeList(path_for_codelist('TipoOperacionND-2.1 - copia.gc'), 'code', 'name') TipoOperacionF = CodeList(path_for_codelist('TipoOperacionF-2.1.gc'), 'code', 'name')\ .update(CodeList(path_for_codelist('TipoOperacionF-2.1.custom.gc'), 'code', 'name')) diff --git a/facho/fe/fe.py b/facho/fe/fe.py index 3f7afdd..c136fc4 100644 --- a/facho/fe/fe.py +++ b/facho/fe/fe.py @@ -30,7 +30,6 @@ SCHEME_AGENCY_ATTRS = { POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf' POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.' - NAMESPACES = { 'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2', 'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual', @@ -124,7 +123,12 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): schemeName=self.schemeName()) if self.schemeName() == "CUDS-SHA384": - fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.') + if fachoxml.tag_document() == 'Invoice': + fachoxml.set_element('./cbc:ProfileID', + 'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.') + else: + fachoxml.set_element('./cbc:ProfileID', + 'DIAN 2.1: Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente') else: fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta') diff --git a/facho/fe/form/__init__.py b/facho/fe/form/__init__.py index 7d4a51c..a215693 100644 --- a/facho/fe/form/__init__.py +++ b/facho/fe/form/__init__.py @@ -373,6 +373,21 @@ class PrePaidPayment: #DIAN 1.7.-2020: FBD03 paid_amount: Amount = Amount(0.0) +@dataclass +class BillingResponse: + id: str + code: str + description: str + +class SupportDocumentCreditNoteResponse(BillingResponse): + """ + ReferenceID: Identifica la sección del Documento + Soporte original a la cual se aplica la corrección. + ResponseCode: Código de descripción de la corrección. + Description: Descripción de la naturaleza de la corrección. + """ + + @dataclass class BillingReference: @@ -387,7 +402,6 @@ class CreditNoteDocumentReference(BillingReference): date: fecha de emision de la factura relacionada """ - class DebitNoteDocumentReference(BillingReference): """ ident: Prefijo + Numero de la factura relacionada @@ -549,6 +563,10 @@ class DebitNoteDocumentType(str): # 6.1.3 return '92' +class CreditNoteSupportDocumentType(str): + def __str__(self): + return '95' + class Invoice: def __init__(self, type_code: str): if str(type_code) not in codelist.TipoDocumento: @@ -568,6 +586,7 @@ class Invoice: self.invoice_allowance_charge = [] self.invoice_prepaid_payment = [] self.invoice_billing_reference = None + self.invoice_discrepancy_response = None self.invoice_type_code = str(type_code) self.invoice_ident_prefix = None @@ -643,6 +662,10 @@ class Invoice: def set_billing_reference(self, billing_reference: BillingReference): self.invoice_billing_reference = billing_reference + def set_discrepancy_response(self, billing_response: BillingResponse): + self.invoice_discrepancy_response = billing_response + + def accept(self, visitor): visitor.visit_payment_mean(self.invoice_payment_mean) visitor.visit_customer(self.invoice_customer) @@ -742,3 +765,25 @@ class DebitNote(Invoice): class SupportDocument(Invoice): pass + +class SupportDocumentCreditNote(SupportDocument): + def __init__(self, invoice_document_reference: BillingReference, + invoice_discrepancy_response: BillingResponse): + super().__init__(CreditNoteSupportDocumentType()) + + if not isinstance(invoice_document_reference, BillingReference): + raise TypeError('invoice_document_reference invalid type') + self.invoice_billing_reference = invoice_document_reference + self.invoice_discrepancy_response = invoice_discrepancy_response + + def _get_codelist_tipo_operacion(self): + return codelist.TipoOperacionNCDS + + def _check_ident_prefix(self, prefix): + if len(prefix) != 6: + raise ValueError('prefix must be 6 length') + + def _set_ident_prefix_automatic(self): + if not self.invoice_ident_prefix: + self.invoice_ident_prefix = self.invoice_ident[0:6] + pass diff --git a/facho/fe/form_xml/__init__.py b/facho/fe/form_xml/__init__.py index 2dac750..8eb322f 100644 --- a/facho/fe/form_xml/__init__.py +++ b/facho/fe/form_xml/__init__.py @@ -4,3 +4,4 @@ from .debit_note import * from .utils import * from .attached_document import * from .support_document import * +from .support_document_credit_note import * diff --git a/facho/fe/form_xml/support_document.py b/facho/fe/form_xml/support_document.py index a2fbcfb..dcd5a05 100644 --- a/facho/fe/form_xml/support_document.py +++ b/facho/fe/form_xml/support_document.py @@ -81,8 +81,6 @@ class DIANSupportDocumentXML(fe.FeXML): #DIAN 1.1.-2021: NSAJ12 fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode', invoice.invoice_supplier.address.countrysubentity.code) - - #DIAN 1.1.-2021: DSAJ13 DSAJ14 #DIAN 1.1.-2021: NSAJ13 NSAJ14 fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line', invoice.invoice_supplier.address.street) @@ -293,25 +291,24 @@ class DIANSupportDocumentXML(fe.FeXML): if isinstance(reference, InvoiceDocumentReference): return fexml._set_invoice_document_reference(reference) - # def set_discrepancy_response(fexml, invoice): - # reference = invoice.invoice_discrepancy_response - # if reference is None: - # return + def set_discrepancy_response(fexml, invoice): + reference = invoice.invoice_discrepancy_response + if reference is None: + return + if isinstance(reference, DebitNoteDocumentReference): + return fexml._set_debit_note_document_reference(reference) + if isinstance(reference, CreditNoteDocumentReference): + return fexml._set_credit_note_document_reference(reference) - # if isinstance(reference, DebitNoteDocumentReference): - # return fexml._set_debit_note_document_reference(reference) - # if isinstance(reference, CreditNoteDocumentReference): - # return fexml._set_credit_note_document_reference(reference) + if isinstance(reference, InvoiceDocumentReference): + return fexml._set_invoice_document_reference(reference) - # if isinstance(reference, InvoiceDocumentReference): - # return fexml._set_invoice_document_reference(reference) - - # fexml.set_element('./cac:DiscrepancyResponse/cbc:ReferenceID', - # reference.ident) - # fexml.set_element('./cac:DiscrepancyResponse/cbc:ResponseCode:UUID', - # '1') - # fexml.set_element('./cac:DiscrepancyResponse/cbc:Description', - # 'Test') + fexml.set_element('./cac:DiscrepancyResponse/cbc:ReferenceID', + reference.id) + fexml.set_element('./cac:DiscrepancyResponse/cbc:ResponseCode', + reference.code) + fexml.set_element('./cac:DiscrepancyResponse/cbc:Description', + reference.description) def set_invoice_totals(fexml, invoice): tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0))) @@ -496,7 +493,7 @@ class DIANSupportDocumentXML(fe.FeXML): fexml.set_invoice_lines(invoice) fexml.set_payment_mean(invoice) fexml.set_allowance_charge(invoice) - #fexml.set_discrepancy_response(invoice) + fexml.set_discrepancy_response(invoice) fexml.set_billing_reference(invoice) return fexml