diff --git a/__init__.py b/__init__.py index 9909ace..340f9ac 100644 --- a/__init__.py +++ b/__init__.py @@ -16,6 +16,8 @@ def register(): invoice.Invoice, invoice.InvoiceLine, invoice.Product, + invoice.PartyFeIdentifier, + invoice.PartyFeOrganization, invoice.Party, invoice.Cron, dian.RangoFacturacion, diff --git a/invoice.py b/invoice.py index 264a808..87f50ea 100644 --- a/invoice.py +++ b/invoice.py @@ -1,4 +1,4 @@ -from trytond.model import fields, ModelView +from trytond.model import fields, ModelView, ModelSQL from trytond.pool import PoolMeta, Pool from trytond.pyson import Eval from trytond.transaction import Transaction @@ -10,6 +10,8 @@ from facho import fe from facho.fe.client import dian import io +from datetime import datetime + class Cron(metaclass=PoolMeta): __name__ = 'ir.cron' @@ -21,35 +23,82 @@ class Cron(metaclass=PoolMeta): ('account.invoice|fe_delivery', 'FE Delivery') ]) + class Party(metaclass=PoolMeta): __name__ = 'party.party' - fe_tipo_responsabilidad = fields.Many2One('account_invoice_facho.fe_generic_code', - 'Tipo Responsabilidad', - domain=[('resource', '=', 'tipo_responsabilidad')], - required=True) - fe_tipo_organizacion = fields.Many2One('account_invoice_facho.fe_generic_code', - 'Tipo Organizacion', - domain=[('resource', '=', 'tipo_organizacion')], - required=True) + fe_identifiers = fields.One2Many('account_invoice_facho.party.fe_identifier', + 'party', 'Fe Identifiers', required=True) + fe_organizations = fields.One2Many('account_invoice_facho.party.fe_organization', + 'party', 'Fe Organizations', required=True) - + @property + def fe_identifier(self): + try: + return self.fe_identifiers[0] + except IndexError: + return None + + @property + def fe_organization(self): + try: + return self.fe_organizations[0] + except IndexError: + return None def tofacho(self): + tax_identifier = self.tax_identifer + if tax_identifer is None: + tax_identifer = '' return form.Party( name = self.name, - ident = self.name, # TODO - responsability_code = self.fe_tipo_responsabilidad.code, - organization_code = self.fe_tipo_organizacion.code, + ident = tax_identifer, + responsability_code = self.fe_identifier.fe_code, + organization_code = self.fe_organization.fe_code, ) +class PartyFeOrganization(ModelSQL, ModelView): + 'Party Facturacion Electronica Organizacion' + __name__ = 'account_invoice_facho.party.fe_organization' + + name = fields.Char('Name', required=True) + party = fields.Many2One('party.party', 'Party', ondelete='CASCADE', + required=True, select=True) + fe_tipo = fields.Many2One('account_invoice_facho.fe_generic_code', + 'Tipo Organizacion', + domain=[('resource', '=', 'tipo_organizacion')], + required=True) + + @property + def fe_code(self): + return self.fe_tipo.code + + +class PartyFeIdentifier(ModelSQL, ModelView): + 'Party Facturaction Electron Identificador' + __name__ = 'account_invoice_facho.party.fe_identifier' + _rec_name = 'code' + code = fields.Char('Code', required=True) + party = fields.Many2One('party.party', 'Party', ondelete='CASCADE', + required=True, select=True) + fe_tipo = fields.Many2One('account_invoice_facho.fe_generic_code', + 'Tipo Responsabilidad', + domain=[('resource', '=', 'tipo_responsabilidad')], + required=True) + + @property + def fe_code(self): + return self.fe_tipo.code + + class Invoice(metaclass=PoolMeta): __name__ = 'account.invoice' - _states = {'invisible': ~Eval('is_fe_colombia', False)} - - _depends = ['is_fe_colombia'] + _states = {'invisible': ~Eval('is_fe_colombia', False), + 'readonly': Eval('state') != 'draft'} + _states_readonly = {'readonly': Eval('state') != 'draft'} + _depends = ['is_fe_colombia', 'state'] is_fe_colombia = fields.Boolean('FE Colombia?', states={'invisible': False}) @@ -63,14 +112,18 @@ class Invoice(metaclass=PoolMeta): ('exception', 'Exception'), # local exception ('failure', 'Failure'), # remoto fallo ('done', 'Done') # remoto ok - ], 'Delivery State', states=_states, depends=_depends) + ], 'Delivery State', states=_states_readonly, depends=_depends) fe_delivery_trackid = fields.Char('Delivery TrackID', - states=_states, + states=_states_readonly, depends=_depends) fe_delivery_status = fields.Text('Delivery Status', - states=_states, + states=_states_readonly, depends=_depends) - del _states + fe_delivery_checked_at = fields.DateTime('Delivery Checked At', + states=_states_readonly, + depends=_depends) + + del _states, _states_readonly del _depends @staticmethod @@ -137,9 +190,9 @@ class Invoice(metaclass=PoolMeta): def _force_write(self, params): self.state = 'draft' + params['fe_delivery_checked_at'] = datetime.now() self.write([self], params) - def fe_delivery_test(self): config = Pool().get('account_invoice_facho.configuration')(1) if self.fe_delivery_state not in ['queued', 'draft']: @@ -161,11 +214,9 @@ class Invoice(metaclass=PoolMeta): )) if not res.ZipKey: raise UserError(str(res)) - # HACK force draft for allow write self._force_write({'fe_delivery_state': 'delivered', 'fe_delivery_trackid': res.ZipKey}) - def fe_process(self): if self.fe_habilitacion: # TODO forzar facturas contabilidadas @@ -176,7 +227,7 @@ class Invoice(metaclass=PoolMeta): for inv in cls.search([('is_fe_colombia', '=', True), ('state', 'in', ['posted', 'paid'])]): inv.fe_process() - if inv.fe_delivery_state == 'delivered': + if inv.fe_delivery_state in ['delivered', 'failure']: inv.fe_update_status() diff --git a/view/invoice_page_form.xml b/view/invoice_page_form.xml index 21cce3e..a1f225d 100644 --- a/view/invoice_page_form.xml +++ b/view/invoice_page_form.xml @@ -5,10 +5,15 @@ diff --git a/view/party_form.xml b/view/party_form.xml index 506ec72..37a7460 100644 --- a/view/party_form.xml +++ b/view/party_form.xml @@ -3,10 +3,8 @@ -