Se permite informar distintos impuestos en linea de factura
This commit is contained in:
parent
71197dd031
commit
9eb010092c
351
invoice.py
351
invoice.py
|
@ -28,6 +28,7 @@ from dateutil import tz
|
|||
|
||||
Bogota = tz.gettz("America/Bogota")
|
||||
|
||||
|
||||
class Cron(metaclass=PoolMeta):
|
||||
__name__ = 'ir.cron'
|
||||
|
||||
|
@ -37,26 +38,26 @@ class Cron(metaclass=PoolMeta):
|
|||
cls.method.selection.extend([
|
||||
('account.invoice|fe_delivery', 'FE Delivery')
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
class Invoice(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice'
|
||||
|
||||
_states_readonly = {'readonly': Eval('state') != 'draft'}
|
||||
|
||||
|
||||
# TODO adicionar atributo fe_identifier y permitir seleccion desde form
|
||||
fe_delivery_state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('queued', 'Queued'), # local encola
|
||||
('delivered', 'Delivered'), # remoto encola
|
||||
('exception', 'Exception'), # local exception
|
||||
('failure', 'Failure'), # remoto fallo
|
||||
('done', 'Done') # remoto ok
|
||||
('queued', 'Queued'), # local encola
|
||||
('delivered', 'Delivered'), # remoto encola
|
||||
('exception', 'Exception'), # local exception
|
||||
('failure', 'Failure'), # remoto fallo
|
||||
('done', 'Done') # remoto ok
|
||||
], 'Delivery State', states=_states_readonly)
|
||||
fe_delivery_trackid = fields.Char('Delivery TrackID',
|
||||
states=_states_readonly)
|
||||
fe_delivery_status_description = fields.Char('Status Description',
|
||||
states=_states_readonly)
|
||||
states=_states_readonly)
|
||||
fe_delivery_error_message = fields.Text('Error Message',
|
||||
states=_states_readonly)
|
||||
fe_delivery_checked_at = fields.DateTime('Delivery Checked At',
|
||||
|
@ -78,10 +79,10 @@ class Invoice(metaclass=PoolMeta):
|
|||
('10', 'Estándar'),
|
||||
('20', 'Nota Crédito que referencia una factura electrónica.'),
|
||||
('30', 'Nota Débito que referencia una factura electrónica.'),
|
||||
],'Operation Type',
|
||||
], 'Operation Type',
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft')
|
||||
},
|
||||
},
|
||||
depends=['state'])
|
||||
|
||||
fe_document_reference = fields.Many2One('account.invoice',
|
||||
|
@ -103,49 +104,48 @@ class Invoice(metaclass=PoolMeta):
|
|||
states={
|
||||
'required': True,
|
||||
'readonly': (Eval('state') != 'draft')
|
||||
},depends=['state'])
|
||||
}, depends=['state'])
|
||||
|
||||
del _states_readonly
|
||||
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(Invoice, cls).__setup__()
|
||||
cls.payment_term.states['required'] = If(Bool(Eval('_parent_subtype.fe_document')) == True, True)
|
||||
cls.payment_term.states['required'] = If(
|
||||
Bool(Eval('_parent_subtype.fe_document')) == True, True)
|
||||
cls._buttons.update({
|
||||
'xml': {
|
||||
'readonly': Eval('state').in_(['posted', 'paid']),
|
||||
'depends' : ['state'],},
|
||||
'depends': ['state'], },
|
||||
'xml_signed': {
|
||||
'readonly': Eval('state').in_(['posted', 'paid']),
|
||||
'depends' : ['state'],},
|
||||
'depends': ['state'], },
|
||||
'fe_send': {
|
||||
'readonly': Or(Eval('fe_delivery_state').in_(['done', 'exception']),
|
||||
Eval('state').in_(['draft','validated'])),
|
||||
'depends' : ['fe_delivery_state', 'state'],},
|
||||
Eval('state').in_(['draft', 'validated'])),
|
||||
'depends': ['fe_delivery_state', 'state'], },
|
||||
'fe_update_status': {
|
||||
'readonly': Eval('fe_delivery_state').in_(['done', 'exception']),
|
||||
'depends' : ['fe_delivery_state'],},
|
||||
'depends': ['fe_delivery_state'], },
|
||||
'fe_email': {
|
||||
'readonly': ~Eval('fe_delivery_state').in_(['done']),
|
||||
'depends' : ['fe_delivery_state'],},
|
||||
'depends': ['fe_delivery_state'], },
|
||||
'post': {'pre_validate':
|
||||
['OR',
|
||||
('invoice_date', '!=', None),
|
||||
('type', '!=', 'in'),
|
||||
],
|
||||
'invisible': (~Eval('state').in_(['draft', 'validated'])
|
||||
| ((Eval('state') == 'posted') & Bool(Eval('move')))),
|
||||
'readonly': If(Eval('total_amount') == 0,True),
|
||||
'depends': ['state', 'move'],}
|
||||
| ((Eval('state') == 'posted') & Bool(Eval('move')))),
|
||||
'readonly': If(Eval('total_amount') == 0, True),
|
||||
'depends': ['state', 'move'], }
|
||||
})
|
||||
|
||||
|
||||
@classmethod
|
||||
def view_attributes(cls):
|
||||
return super(Invoice, cls).view_attributes() + [
|
||||
('//page[@id="fe_colombia_invoice"]', 'states', {
|
||||
'invisible': ~Eval('fe_document', False)})]
|
||||
return super(Invoice, cls).view_attributes() + [
|
||||
('//page[@id="fe_colombia_invoice"]', 'states', {
|
||||
'invisible': ~Eval('fe_document', False)})]
|
||||
|
||||
@classmethod
|
||||
def trigger(cls, records, trigger):
|
||||
|
@ -157,19 +157,17 @@ class Invoice(metaclass=PoolMeta):
|
|||
cls.fe_send([record])
|
||||
else:
|
||||
record.fe_delivery_state = 'exception'
|
||||
record.fe_delivery_status_description = 'DOCUMENTO NO ELECTRÓNICO'
|
||||
record.fe_delivery_status_description = 'DOCUMENTO NO ELECTRÓNICO'
|
||||
record.save()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_fe_delivery_state():
|
||||
return 'draft'
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_fe_states():
|
||||
return None
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_fe_operation_type():
|
||||
return '10'
|
||||
|
@ -181,7 +179,7 @@ class Invoice(metaclass=PoolMeta):
|
|||
@staticmethod
|
||||
def default_fe_document():
|
||||
return False
|
||||
|
||||
|
||||
@classmethod
|
||||
def copy(cls, invoices, default=None):
|
||||
if default is None:
|
||||
|
@ -210,10 +208,9 @@ class Invoice(metaclass=PoolMeta):
|
|||
default.setdefault('fe_qrcode', None)
|
||||
default.setdefault('fe_xml_file', None)
|
||||
default.setdefault('fe_document_reference', None)
|
||||
|
||||
|
||||
return super(Invoice, cls).copy(invoices, default=default)
|
||||
|
||||
|
||||
@fields.depends('fe_qrcode')
|
||||
def get_fe_qrcode_img(self, name):
|
||||
qr_data = io.BytesIO()
|
||||
|
@ -225,17 +222,17 @@ class Invoice(metaclass=PoolMeta):
|
|||
qrcode_img.get_image().save(img, 'png')
|
||||
img.seek(0)
|
||||
return img.read()
|
||||
|
||||
|
||||
def get_email_invoice_count(self, name):
|
||||
pool = Pool()
|
||||
Notification_Email = pool.get('notification.email')
|
||||
Notification_Email_Log = pool.get('notification.email.log')
|
||||
notification_email = Notification_Email.search(['rec_name', '=', 'Enviar Factura por correo'])
|
||||
notification_email = Notification_Email.search(
|
||||
['rec_name', '=', 'Enviar Factura por correo'])
|
||||
domain = [('resource', '=', self)]
|
||||
|
||||
return str(Notification_Email_Log.search_count(domain))
|
||||
|
||||
|
||||
def get_fe_states_icon(self, name):
|
||||
if self.state == 'posted' or self.state == 'paid':
|
||||
if self.fe_delivery_state != 'done':
|
||||
|
@ -293,11 +290,11 @@ class Invoice(metaclass=PoolMeta):
|
|||
def on_change_fe_operation_type(self):
|
||||
if self.fe_operation_type == '10':
|
||||
self.credit_note = False
|
||||
|
||||
|
||||
@fields.depends('fe_operation_type')
|
||||
def type_code_xml(self, facho_invoice):
|
||||
if self.type == 'out':
|
||||
if self.fe_operation_type == '10':
|
||||
if self.fe_operation_type == '10':
|
||||
xml = form_xml.DIANInvoiceXML(facho_invoice)
|
||||
elif self.fe_operation_type == '20':
|
||||
xml = form_xml.DIANCreditNoteXML(facho_invoice)
|
||||
|
@ -308,24 +305,22 @@ class Invoice(metaclass=PoolMeta):
|
|||
xml = form_xml.DIANSupportDocumentXML(facho_invoice)
|
||||
elif self.fe_operation_type == '20':
|
||||
xml = form_xml.DIANSupportDocumentCreditNoteXML(facho_invoice)
|
||||
|
||||
|
||||
return xml
|
||||
|
||||
|
||||
def fe_email_count(self, name):
|
||||
pool = Pool()
|
||||
Notification_Email_Log = pool.get('notification.email.log')
|
||||
domain = [('resource', '=', self)]
|
||||
return Notification_Email_Log.search_count(domain)
|
||||
return Notification_Email_Log.search_count(domain)
|
||||
|
||||
|
||||
@classmethod
|
||||
def check_modify(cls, invoices):
|
||||
'''
|
||||
Check if the invoices can be modified
|
||||
'''
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def validate(cls, invoices):
|
||||
super().validate(invoices)
|
||||
|
@ -335,19 +330,19 @@ class Invoice(metaclass=PoolMeta):
|
|||
for taxes, unit_price, quantity, date_time in line.taxable_lines:
|
||||
for tax in taxes:
|
||||
if tax.type != 'percentage':
|
||||
raise UserError('Solo se soporta impuesto tipo porcentaje para producto')
|
||||
raise UserError(
|
||||
'Solo se soporta impuesto tipo porcentaje para producto')
|
||||
facho_invoice = invoice.tofacho()
|
||||
xml = form_xml.DIANInvoiceXML(facho_invoice)
|
||||
|
||||
|
||||
def tofacho(self):
|
||||
if self.subtype.fe_document:
|
||||
#Crear tipos de documentos electrónicos
|
||||
if self.fe_operation_type in ['20','30']:
|
||||
# Crear tipos de documentos electrónicos
|
||||
if self.fe_operation_type in ['20', '30']:
|
||||
reference = form.InvoiceDocumentReference(
|
||||
ident = self.fe_document_reference.number,
|
||||
uuid = self.fe_document_reference.fe_cufe,
|
||||
date = self.fe_document_reference.invoice_date)
|
||||
ident=self.fe_document_reference.number,
|
||||
uuid=self.fe_document_reference.fe_cufe,
|
||||
date=self.fe_document_reference.invoice_date)
|
||||
|
||||
operation_type = self.fe_operation_type
|
||||
party_tax_code = self.party.identifiers[0].type
|
||||
|
@ -363,67 +358,67 @@ class Invoice(metaclass=PoolMeta):
|
|||
party_tax_code = '31'
|
||||
if self.credit_note:
|
||||
response = form.SupportDocumentCreditNoteResponse(
|
||||
id = self.fe_document_reference.number,
|
||||
code = '5',
|
||||
description = self.description)
|
||||
id=self.fe_document_reference.number,
|
||||
code='5',
|
||||
description=self.description)
|
||||
inv = form.SupportDocumentCreditNote(reference, response)
|
||||
operation_type = '10'
|
||||
else:
|
||||
inv = form.SupportDocument('05')
|
||||
|
||||
|
||||
inv.set_period(datetime.now(tz=Bogota), datetime.now(tz=Bogota))
|
||||
inv.set_issue(datetime.now(tz=Bogota))
|
||||
if self.number:
|
||||
inv.set_ident(self.number)
|
||||
else:
|
||||
inv.set_ident("0000")
|
||||
#Adicionar tipos de operación
|
||||
# Adicionar tipos de operación
|
||||
inv.set_operation_type(operation_type)
|
||||
company = form.Party(
|
||||
legal_name = self.company.party.name,
|
||||
name = self.company.party.full_name,
|
||||
ident = form.PartyIdentification(
|
||||
legal_name=self.company.party.name,
|
||||
name=self.company.party.full_name,
|
||||
ident=form.PartyIdentification(
|
||||
str(self.company.party.identifiers[0].code),
|
||||
str(self.company.party.identifiers[0].check_digit),
|
||||
str(self.company.party.identifiers[0].type)
|
||||
),
|
||||
responsability_code = self.tax_level_code(self.company.party.tax_level_code),
|
||||
responsability_regime_code = "48",
|
||||
organization_code = self.party.type_person,
|
||||
email = self.company.party.email,
|
||||
address = form.Address('',
|
||||
self.company.party.addresses[0].street,
|
||||
form.City('05001',
|
||||
self.company.party.addresses[0].city),
|
||||
form.Country(self.company.party.addresses[0].country.code,
|
||||
self.company.party.addresses[0].country.name),
|
||||
form.CountrySubentity('05',
|
||||
self.company.party.addresses[0].subdivision.name),
|
||||
form.PostalZone(self.company.party.addresses[0].postal_code),
|
||||
),
|
||||
)
|
||||
),
|
||||
responsability_code=self.tax_level_code(self.company.party.tax_level_code),
|
||||
responsability_regime_code="48",
|
||||
organization_code=self.party.type_person,
|
||||
email=self.company.party.email,
|
||||
address=form.Address('',
|
||||
self.company.party.addresses[0].street,
|
||||
form.City('05001',
|
||||
self.company.party.addresses[0].city),
|
||||
form.Country(self.company.party.addresses[0].country.code,
|
||||
self.company.party.addresses[0].country.name),
|
||||
form.CountrySubentity('05',
|
||||
self.company.party.addresses[0].subdivision.name),
|
||||
form.PostalZone(self.company.party.addresses[0].postal_code),
|
||||
),
|
||||
)
|
||||
party = form.Party(
|
||||
legal_name = self.party.name,
|
||||
name = self.party.full_name,
|
||||
ident = form.PartyIdentification(
|
||||
legal_name=self.party.name,
|
||||
name=self.party.full_name,
|
||||
ident=form.PartyIdentification(
|
||||
str(self.party.identifiers[0].code),
|
||||
str(self.party.identifiers[0].check_digit),
|
||||
str(party_tax_code)
|
||||
),
|
||||
responsability_code = self.tax_level_code(self.party.tax_level_code),
|
||||
responsability_regime_code = "48",
|
||||
organization_code = self.party.type_person,
|
||||
email = self.party.email,
|
||||
address = form.Address('',
|
||||
self.party.addresses[0].street,
|
||||
form.City('05001', self.party.addresses[0].city),
|
||||
form.Country(self.party.addresses[0].country.code,
|
||||
self.party.addresses[0].country.name),
|
||||
form.CountrySubentity('05', self.party.addresses[0].subdivision.name),
|
||||
form.PostalZone(self.party.addresses[0].postal_code),
|
||||
),
|
||||
)
|
||||
),
|
||||
responsability_code=self.tax_level_code(self.party.tax_level_code),
|
||||
responsability_regime_code="48",
|
||||
organization_code=self.party.type_person,
|
||||
email=self.party.email,
|
||||
address=form.Address('',
|
||||
self.party.addresses[0].street,
|
||||
form.City('05001', self.party.addresses[0].city),
|
||||
form.Country(self.party.addresses[0].country.code,
|
||||
self.party.addresses[0].country.name),
|
||||
form.CountrySubentity(
|
||||
'05', self.party.addresses[0].subdivision.name),
|
||||
form.PostalZone(self.party.addresses[0].postal_code),
|
||||
),
|
||||
)
|
||||
if self.type == "in":
|
||||
supplier = party
|
||||
customer = company
|
||||
|
@ -432,17 +427,15 @@ class Invoice(metaclass=PoolMeta):
|
|||
supplier = company
|
||||
customer = party
|
||||
|
||||
|
||||
|
||||
inv.set_supplier(supplier)
|
||||
inv.set_customer(customer)
|
||||
|
||||
if self.payment_term:
|
||||
payment_mean = form.PaymentMean(
|
||||
id = self.fe_way_to_pay,
|
||||
code = self.payment_term.payment_method.fe_payment,
|
||||
due_at = datetime.now(tz=Bogota),
|
||||
payment_id = '1'
|
||||
id=self.fe_way_to_pay,
|
||||
code=self.payment_term.payment_method.fe_payment,
|
||||
due_at=datetime.now(tz=Bogota),
|
||||
payment_id='1'
|
||||
)
|
||||
else:
|
||||
raise UserError(str("Por Favor indique un plazo de pago"))
|
||||
|
@ -450,13 +443,13 @@ class Invoice(metaclass=PoolMeta):
|
|||
inv.set_payment_mean(payment_mean)
|
||||
|
||||
for line in self.lines:
|
||||
inv.add_invoice_line(line.tofacho())
|
||||
if line.type != 'title':
|
||||
inv.add_invoice_line(line.tofacho())
|
||||
|
||||
inv.calculate()
|
||||
|
||||
return inv
|
||||
|
||||
|
||||
def tax_level_code(self, tax_level):
|
||||
tax_level_codes = ''
|
||||
for codes in tax_level:
|
||||
|
@ -465,7 +458,6 @@ class Invoice(metaclass=PoolMeta):
|
|||
else:
|
||||
tax_level_codes += ';' + codes.code
|
||||
return tax_level_codes
|
||||
|
||||
|
||||
@contextmanager
|
||||
def acquire_public_key(config=None):
|
||||
|
@ -493,36 +485,31 @@ class Invoice(metaclass=PoolMeta):
|
|||
file_private_key.close()
|
||||
file_certs.close()
|
||||
|
||||
|
||||
def do_dian_request(self, request):
|
||||
with self.acquire_public_key() as ctx:
|
||||
client = dian.DianSignatureClient(ctx['file_private_key'],
|
||||
ctx['file_public_key'],
|
||||
ctx['passphrase'])
|
||||
return client.request(request)
|
||||
|
||||
|
||||
|
||||
def _force_write(self, params, invoice):
|
||||
params['fe_delivery_checked_at'] = datetime.now()
|
||||
invoice.write([invoice], params)
|
||||
|
||||
|
||||
def _dian_zip_io(self, filename, xml_invoice):
|
||||
zipdata = io.BytesIO()
|
||||
with fe.DianZIP(zipdata) as dianzip:
|
||||
dianzip.add_invoice_xml(filename, xml_invoice)
|
||||
zipdata.seek(0)
|
||||
|
||||
|
||||
return zipdata
|
||||
|
||||
|
||||
def _dian_xml_file_name(self, name):
|
||||
m = hashlib.sha256()
|
||||
m.update(name.encode('utf-8'))
|
||||
filename = m.hexdigest()
|
||||
return filename
|
||||
|
||||
|
||||
def do_fe_delivery(self, facho_invoice, invoice):
|
||||
config = Pool().get('account_invoice_facho.configuration')(1)
|
||||
|
||||
|
@ -530,7 +517,8 @@ class Invoice(metaclass=PoolMeta):
|
|||
xml = self.type_code_xml(invoice, facho_invoice)
|
||||
for extension in extensions:
|
||||
xml.add_extension(extension)
|
||||
fe_qrcode = xml.get_element_text('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode')
|
||||
fe_qrcode = xml.get_element_text(
|
||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode')
|
||||
fe_cufe = xml.get_element_text('./cbc:UUID')
|
||||
with self.acquire_public_key(config) as ctx:
|
||||
signer = fe.DianXMLExtensionSigner(ctx['file_certs'],
|
||||
|
@ -539,8 +527,8 @@ class Invoice(metaclass=PoolMeta):
|
|||
xml_signed = signer.sign_xml_string(str(xml))
|
||||
|
||||
req = dian.SendBillSync
|
||||
|
||||
filename = fe_cufe + '.xml'
|
||||
|
||||
filename = fe_cufe + '.xml'
|
||||
filename_zip = self._dian_xml_file_name(self, fe_cufe) + '.zip'
|
||||
zip_file = self._dian_zip_io(self, filename, xml_signed).read()
|
||||
args = [filename_zip, zip_file]
|
||||
|
@ -564,10 +552,10 @@ class Invoice(metaclass=PoolMeta):
|
|||
delivery_trackid = res.ZipKey
|
||||
status_description = "[]"
|
||||
error_message = "[]"
|
||||
#if res.StatusCode == '00':
|
||||
#delivery_state = 'done'
|
||||
#else:
|
||||
#delivery_state = 'failure'
|
||||
# if res.StatusCode == '00':
|
||||
# delivery_state = 'done'
|
||||
# else:
|
||||
# delivery_state = 'failure'
|
||||
else:
|
||||
status_description = res.StatusDescription
|
||||
error_message = res.ErrorMessage
|
||||
|
@ -578,17 +566,17 @@ class Invoice(metaclass=PoolMeta):
|
|||
self._force_write(self,
|
||||
{'fe_delivery_state': delivery_state,
|
||||
'fe_delivery_trackid': delivery_trackid,
|
||||
'fe_delivery_status_description' : status_description,
|
||||
'fe_delivery_error_message' : error_message,
|
||||
'fe_qrcode' : fe_qrcode,
|
||||
'fe_cufe' : fe_cufe,
|
||||
'fe_xml_file' : zip_file
|
||||
'fe_delivery_status_description': status_description,
|
||||
'fe_delivery_error_message': error_message,
|
||||
'fe_qrcode': fe_qrcode,
|
||||
'fe_cufe': fe_cufe,
|
||||
'fe_xml_file': zip_file
|
||||
},
|
||||
invoice)
|
||||
|
||||
|
||||
def fe_process(self):
|
||||
self.do_fe_delivery()
|
||||
|
||||
|
||||
@classmethod
|
||||
def fe_delivery(cls):
|
||||
pool = Pool()
|
||||
|
@ -600,12 +588,12 @@ class Invoice(metaclass=PoolMeta):
|
|||
('subtype.sequence.invoice_resolution.valid_date_time_to',
|
||||
'>=', date.today()),
|
||||
('fe_delivery_state', 'not in', ['done', 'exeception'])]):
|
||||
|
||||
|
||||
facho_invoice = inv.tofacho()
|
||||
cls.do_fe_delivery(cls, facho_invoice, inv)
|
||||
if inv.fe_delivery_state in ['delivered', 'failure'] and habilitation:
|
||||
inv.fe_update_status([inv])
|
||||
|
||||
|
||||
@fields.depends('credit_note')
|
||||
def fe_extensions(self, inv):
|
||||
pool = Pool()
|
||||
|
@ -627,24 +615,23 @@ class Invoice(metaclass=PoolMeta):
|
|||
invoice_resolution.technical_key,
|
||||
ambiente,)
|
||||
elif self.type == "in":
|
||||
cufe = fe.DianXMLExtensionCUDS(inv,
|
||||
cufe = fe.DianXMLExtensionCUDS(inv,
|
||||
facho.dian_fe_pin,
|
||||
ambiente,)
|
||||
|
||||
|
||||
|
||||
security_code = fe.DianXMLExtensionSoftwareSecurityCode(facho.dian_fe_software_identification,
|
||||
facho.dian_fe_pin,
|
||||
inv.invoice_ident)
|
||||
authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
|
||||
#cufe = fe.DianXMLExtensionCUFE(inv,
|
||||
#facho.dian_fe_invoice_resolution.technical_key,
|
||||
#ambiente,
|
||||
#)
|
||||
# cufe = fe.DianXMLExtensionCUFE(inv,
|
||||
# facho.dian_fe_invoice_resolution.technical_key,
|
||||
# ambiente,
|
||||
# )
|
||||
nit = form.PartyIdentification(
|
||||
str(facho.dian_fe_technologic_supplier.identifiers[0].code),
|
||||
str(facho.dian_fe_technologic_supplier.identifiers[0].check_digit),
|
||||
str(facho.dian_fe_technologic_supplier.identifiers[0].type)
|
||||
)
|
||||
)
|
||||
software_provider = fe.DianXMLExtensionSoftwareProvider(nit,
|
||||
nit.dv,
|
||||
facho.dian_fe_software_identification)
|
||||
|
@ -655,21 +642,19 @@ class Invoice(metaclass=PoolMeta):
|
|||
invoice_resolution.prefix,
|
||||
invoice_resolution.from_number,
|
||||
invoice_resolution.to_number)
|
||||
return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
|
||||
return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def xml(cls, invoices):
|
||||
for invoice in invoices:
|
||||
facho_invoice = invoice.tofacho()
|
||||
xml = cls.type_code_xml(invoice, facho_invoice)
|
||||
xml_encode = bytes(str(xml),'utf-8')
|
||||
xml_encode = bytes(str(xml), 'utf-8')
|
||||
zip_file = cls._dian_zip_io(cls, 'xml', str(xml)).read()
|
||||
invoice.fe_xml_file = zip_file
|
||||
invoice.save()
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def xml_signed(cls, invoices):
|
||||
|
@ -688,11 +673,10 @@ class Invoice(metaclass=PoolMeta):
|
|||
passphrase=ctx['passphrase'],
|
||||
localpolicy=True)
|
||||
xml_signed = signer.sign_xml_string(xml_document)
|
||||
xml_encode = bytes(str(xml_signed),'utf-8')
|
||||
invoice.fe_xml_file = xml_encode
|
||||
xml_encode = bytes(str(xml_signed), 'utf-8')
|
||||
invoice.fe_xml_file = xml_encode
|
||||
invoice.save()
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def fe_send(cls, invoices):
|
||||
|
@ -702,7 +686,6 @@ class Invoice(metaclass=PoolMeta):
|
|||
cls.do_fe_delivery(cls, facho_invoice, invoice)
|
||||
invoice.save()
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def fe_update_status(self, invoices):
|
||||
|
@ -715,7 +698,7 @@ class Invoice(metaclass=PoolMeta):
|
|||
if config.dian_fe_habilitation:
|
||||
req = dian.Habilitacion.GetStatusZip
|
||||
|
||||
resp = self.do_dian_request(self, req(trackId = invoice.fe_delivery_trackid))
|
||||
resp = self.do_dian_request(self, req(trackId=invoice.fe_delivery_trackid))
|
||||
params = {}
|
||||
params['fe_delivery_status_description'] = resp.StatusDescription
|
||||
params['fe_delivery_error_message'] = resp.ErrorMessage
|
||||
|
@ -725,7 +708,6 @@ class Invoice(metaclass=PoolMeta):
|
|||
params['fe_delivery_state'] = 'failure'
|
||||
self._force_write(self, params, invoice)
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def fe_email(cls, invoices, from_=None):
|
||||
|
@ -737,11 +719,16 @@ class Invoice(metaclass=PoolMeta):
|
|||
trigger = notification_email.triggers[0]
|
||||
trigger.notification_email.send_email(invoices, trigger)
|
||||
|
||||
|
||||
class PaymentTerm(metaclass=PoolMeta):
|
||||
'Payment Term'
|
||||
__name__ = 'account.invoice.payment_term'
|
||||
|
||||
payment_method = fields.Many2One('account.invoice.payment.method', "Payment Method", required=True)
|
||||
payment_method = fields.Many2One(
|
||||
'account.invoice.payment.method',
|
||||
"Payment Method",
|
||||
required=True)
|
||||
|
||||
|
||||
class PaymentMethod(metaclass=PoolMeta):
|
||||
'Payment Method'
|
||||
|
@ -752,15 +739,16 @@ class PaymentMethod(metaclass=PoolMeta):
|
|||
[
|
||||
('10', 'Efectivo'),
|
||||
('20', 'Cheque'),
|
||||
('30','Transferencia Crédito'),
|
||||
('31','Transferencia Débito'),
|
||||
('30', 'Transferencia Crédito'),
|
||||
('31', 'Transferencia Débito'),
|
||||
('42', 'Consignación Bancaria')
|
||||
],"Payment Fe",states={
|
||||
'readonly': If(Bool(Eval('fe_method')) == False, True),
|
||||
'required': If(Bool(Eval('fe_method')) == True, True)
|
||||
], "Payment Fe", states={
|
||||
'readonly': If(Bool(Eval('fe_method')) == False, True),
|
||||
'required': If(Bool(Eval('fe_method')) == True, True)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
class Product(metaclass=PoolMeta):
|
||||
__name__ = 'product.product'
|
||||
|
||||
|
@ -768,14 +756,14 @@ class Product(metaclass=PoolMeta):
|
|||
code = "001"
|
||||
if self.code:
|
||||
code = self.code
|
||||
|
||||
|
||||
return form.StandardItem(
|
||||
description = self.name,
|
||||
id_ = code,
|
||||
name = 'Estándar de adopción del contribuyente'
|
||||
description=self.name,
|
||||
id_=code,
|
||||
name='Estándar de adopción del contribuyente'
|
||||
)
|
||||
|
||||
|
||||
|
||||
class InvoiceLine(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice.line'
|
||||
|
||||
|
@ -784,43 +772,49 @@ class InvoiceLine(metaclass=PoolMeta):
|
|||
super(InvoiceLine, cls).__setup__()
|
||||
cls.product.states['required'] = True
|
||||
cls.unit_price.domain = [('unit_price', '!=', 0)]
|
||||
|
||||
|
||||
|
||||
def _get_price_type(self, line_tax):
|
||||
if line_tax.subtotals:
|
||||
tax, = line_tax.subtotals
|
||||
tax_scheme = tax.scheme.name
|
||||
|
||||
return tax_scheme
|
||||
|
||||
def tofacho(self):
|
||||
tax_subtotals = []
|
||||
line_tax = form.TaxTotalOmit()
|
||||
line_withholding = form.WithholdingTaxTotalOmit()
|
||||
|
||||
|
||||
for taxes, unit_price, quantity, date_time in self.taxable_lines:
|
||||
if len(taxes) != 0:
|
||||
for tax in taxes:
|
||||
line_percent = tax.rate * 100
|
||||
if line_percent > 0:
|
||||
line_tax = form.TaxTotal(
|
||||
subtotals = [
|
||||
subtotals=[
|
||||
form.TaxSubTotal(
|
||||
percent = abs(line_percent),
|
||||
percent=abs(line_percent),
|
||||
scheme=form.TaxScheme(tax.fe_tax_type))
|
||||
])
|
||||
elif line_percent < 0:
|
||||
line_withholding = form.WithholdingTaxTotal(
|
||||
subtotals = [
|
||||
subtotals=[
|
||||
form.WithholdingTaxSubTotal(
|
||||
percent = abs(line_percent),
|
||||
percent=abs(line_percent),
|
||||
scheme=form.TaxScheme(tax.fe_tax_type))
|
||||
])
|
||||
|
||||
|
||||
return form.InvoiceLine(
|
||||
quantity = form.Quantity(abs(self.quantity), '94'),
|
||||
description = self.description,
|
||||
item = self.product.tofacho(),
|
||||
price = form.Price(
|
||||
amount = form.Amount(abs(self.unit_price)),
|
||||
type_code = '01',
|
||||
type = 'IVA'
|
||||
),
|
||||
tax = line_tax,
|
||||
withholding = line_withholding)
|
||||
quantity=form.Quantity(abs(self.quantity), '94'),
|
||||
description=self.description,
|
||||
item=self.product.tofacho(),
|
||||
price=form.Price(
|
||||
amount=form.Amount(abs(self.unit_price)),
|
||||
type_code='01',
|
||||
type=self._get_price_type(line_tax)
|
||||
),
|
||||
tax=line_tax,
|
||||
withholding=line_withholding)
|
||||
|
||||
|
||||
class InvoiceReportDianZip(Report):
|
||||
|
@ -840,25 +834,26 @@ class InvoiceReportDianZip(Report):
|
|||
invoice, = Invoice.browse(records)
|
||||
invoice.invoice_report_cache = None
|
||||
invoice.save()
|
||||
Report = pool.get('account.invoice', type='report')
|
||||
Report = pool.get('account.invoice', type='report')
|
||||
ext, content, _, name = Report.execute([invoice.id], {})
|
||||
if not invoice.fe_cufe:
|
||||
raise UserError(str('Factura no enviada a la Dian'))
|
||||
zip_file = io.BytesIO(invoice.fe_xml_file)
|
||||
name = invoice._dian_xml_file_name(invoice.fe_cufe + '.xml')
|
||||
filename = name + '.' + ext
|
||||
filename = name + '.' + ext
|
||||
with zipfile.ZipFile(zip_file, 'a') as pdf_add:
|
||||
pdf_add.writestr(filename, content)
|
||||
zip_file.seek(0)
|
||||
return ('zip', zip_file.read(), False, name)
|
||||
|
||||
|
||||
|
||||
class InvoiceSubtype(metaclass=PoolMeta):
|
||||
'Invoice Subtype'
|
||||
__name__ = 'account.invoice.subtype'
|
||||
|
||||
fe_document = fields.Boolean('Fe Document')
|
||||
|
||||
|
||||
class SendInvoice(Wizard):
|
||||
'Send Invoices'
|
||||
__name__ = 'account.invoice.send_invoices'
|
||||
|
@ -876,4 +871,6 @@ class SendInvoice(Wizard):
|
|||
Invoice.fe_send([record])
|
||||
elif record.state == 'posted' and record.fe_delivery_state == 'exception' or record.fe_delivery_state == 'done':
|
||||
continue
|
||||
|
||||
|
||||
1
|
||||
|
|
Loading…
Reference in New Issue