implementacion de envio de factura para habilitacion
This commit is contained in:
parent
558f09b6a7
commit
80ec627f98
|
@ -2,7 +2,6 @@ from trytond.pool import Pool
|
|||
from . import configuration
|
||||
|
||||
from . import invoice
|
||||
from . import party
|
||||
from . import facho
|
||||
from . import dian
|
||||
|
||||
|
@ -18,6 +17,7 @@ def register():
|
|||
invoice.InvoiceLine,
|
||||
invoice.Product,
|
||||
invoice.Party,
|
||||
invoice.Cron,
|
||||
dian.RangoFacturacion,
|
||||
module='account_invoice_facho', type_='model')
|
||||
Pool.register(
|
||||
|
|
|
@ -13,10 +13,10 @@ class Configuration(
|
|||
dian_fe_numeracion_username = fields.MultiValue(fields.Char('Username'))
|
||||
dian_fe_numeracion_password = fields.MultiValue(fields.Char('Password'))
|
||||
dian_fe_numeracion_key = fields.MultiValue(fields.Char('Dian FE Numeracion Key'))
|
||||
dian_fe_llave_publica = fields.MultiValue(fields.Binary('Privada PCKS#12'))
|
||||
dian_fe_llave_privada = fields.MultiValue(fields.Binary('Publica PCKS#12'))
|
||||
dian_fe_llave_frasepaso = fields.MultiValue(fields.Chat('Frasepaso PCKS#12'))
|
||||
dian_fe_test_setid = fields.MultiValue(fields.Chat('Dian testsetid'))
|
||||
dian_fe_llave_publica = fields.MultiValue(fields.Char('Publica PCKS#12'))
|
||||
dian_fe_llave_privada = fields.MultiValue(fields.Char('Privada PCKS#12'))
|
||||
dian_fe_llave_frasepaso = fields.MultiValue(fields.Char('Frasepaso PCKS#12'))
|
||||
dian_fe_test_setid = fields.MultiValue(fields.Char('Dian testsetid'))
|
||||
dian_fe_NITProveedorTecnologico = fields.MultiValue(fields.Char('NIT Proveedor Tecnologico'))
|
||||
dian_fe_NITObligadoFacturarElectronicamente = fields.MultiValue(fields.Char('NIT Obligactior FE'))
|
||||
dian_fe_IdentificadorSoftware = fields.MultiValue(fields.Char('IdentificadorSoftware'))
|
||||
|
@ -38,10 +38,10 @@ class ConfigurationDianFECompany(ModelSQL, CompanyValueMixin):
|
|||
dian_fe_numeracion_password = fields.Char('Password')
|
||||
dian_fe_numeracion_key = fields.Char('Dian FE Numeracion Key')
|
||||
dian_fe_key = fields.Char('Dian FE Key')
|
||||
dian_fe_llave_publica = fields.Binary('Publica PCKS#12')
|
||||
dian_fe_llave_privada = fields.Binary('Publica PCKS#12')
|
||||
dian_fe_test_setid = fields.Chat('Dian testsetid')
|
||||
dian_fe_llave_frasepaso = fields.Chat('Frasepaso PCKS#12')
|
||||
dian_fe_llave_publica = fields.Char('Publica PCKS#12')
|
||||
dian_fe_llave_privada = fields.Char('Publica PCKS#12')
|
||||
dian_fe_test_setid = fields.Char('Dian testsetid')
|
||||
dian_fe_llave_frasepaso = fields.Char('Frasepaso PCKS#12')
|
||||
dian_fe_NITProveedorTecnologico = fields.Char('NIT Proveedor Tecnologico')
|
||||
dian_fe_NITObligadoFacturarElectronicamente = fields.Char('NIT Obligactior FE')
|
||||
dian_fe_IdentificadorSoftware = fields.Char('IdentificadorSoftware')
|
||||
|
|
114
invoice.py
114
invoice.py
|
@ -1,5 +1,5 @@
|
|||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta
|
||||
from trytond.model import fields, ModelView
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.pyson import Eval
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.rpc import RPC
|
||||
|
@ -7,10 +7,19 @@ from trytond.exceptions import UserError
|
|||
|
||||
from facho.fe import form
|
||||
from facho import fe
|
||||
from fache.fe.client import dian
|
||||
from facho.fe.client import dian
|
||||
|
||||
import io
|
||||
|
||||
class Cron(metaclass=PoolMeta):
|
||||
__name__ = 'ir.cron'
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.method.selection.extend([
|
||||
('account.invoice|fe_delivery', 'FE Delivery')
|
||||
])
|
||||
|
||||
class Party(metaclass=PoolMeta):
|
||||
__name__ = 'party.party'
|
||||
|
@ -18,27 +27,28 @@ class Party(metaclass=PoolMeta):
|
|||
fe_tipo_responsabilidad = fields.Many2One('account_invoice_facho.fe_generic_code',
|
||||
'Tipo Responsabilidad',
|
||||
domain=[('resource', '=', 'tipo_responsabilidad')],
|
||||
states=_states,
|
||||
depends=_depends)
|
||||
|
||||
required=True)
|
||||
fe_tipo_organizacion = fields.Many2One('account_invoice_facho.fe_generic_code',
|
||||
'Tipo Organizacion',
|
||||
domain=[('resource', '=', 'tipo_organizacion')],
|
||||
states=_states,
|
||||
depends=_depends)
|
||||
required=True)
|
||||
|
||||
|
||||
|
||||
def tofacho(self):
|
||||
return form.Party(
|
||||
name = self.name
|
||||
name = self.name,
|
||||
ident = self.name, # TODO
|
||||
responsability_code = self.fe_tipo_responsabilidad.code,
|
||||
organization_code = self.fe_tipo_organizacion.code,
|
||||
)
|
||||
|
||||
|
||||
class Invoice(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice'
|
||||
|
||||
_states = {'invisible': ~Eval('is_fe_colombia', False),
|
||||
'required': Eval('is_fe_colombia', False)}
|
||||
_states = {'invisible': ~Eval('is_fe_colombia', False)}
|
||||
|
||||
_depends = ['is_fe_colombia']
|
||||
|
||||
is_fe_colombia = fields.Boolean('FE Colombia?',
|
||||
|
@ -47,12 +57,13 @@ class Invoice(metaclass=PoolMeta):
|
|||
states=_states,
|
||||
depends=_depends)
|
||||
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
|
||||
], 'Delivery', states=_states, dependes=_depends)
|
||||
], 'Delivery State', states=_states, depends=_depends)
|
||||
fe_delivery_trackid = fields.Char('Delivery TrackID',
|
||||
states=_states,
|
||||
depends=_depends)
|
||||
|
@ -62,7 +73,10 @@ class Invoice(metaclass=PoolMeta):
|
|||
del _states
|
||||
del _depends
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_fe_delivery_state():
|
||||
return 'draft'
|
||||
|
||||
@staticmethod
|
||||
def default_is_fe_colombia():
|
||||
return Transaction().context.get('is_fe_colombia', False)
|
||||
|
@ -73,7 +87,6 @@ class Invoice(metaclass=PoolMeta):
|
|||
|
||||
for invoice in invoices:
|
||||
for line in invoice.lines:
|
||||
tax_subtotals = []
|
||||
for taxes, unit_price, quantity in line.taxable_lines:
|
||||
for tax in taxes:
|
||||
if tax.type != 'percentage':
|
||||
|
@ -85,7 +98,6 @@ class Invoice(metaclass=PoolMeta):
|
|||
for (model, field, error) in validator.errors:
|
||||
raise UserError('model %s in field %s has %s' % (model, field, error))
|
||||
|
||||
|
||||
def tofacho(self):
|
||||
inv = form.Invoice()
|
||||
inv.set_period(self.invoice_date, self.invoice_date)
|
||||
|
@ -100,52 +112,74 @@ class Invoice(metaclass=PoolMeta):
|
|||
inv.calculate()
|
||||
return inv
|
||||
|
||||
|
||||
def fe_get_status(self):
|
||||
config = pool.get('account_invoice_facho.configuration')(1)
|
||||
def do_dian_request(self, request, config=None):
|
||||
if config is None:
|
||||
config = Pool().get('account_invoice_facho.configuration')(1)
|
||||
client = dian.DianSignatureClient(config.dian_fe_llave_privada,
|
||||
config.dian_fe_llave_publica,
|
||||
password=config.dian_fe_llave_frasepaso)
|
||||
return client.request(request)
|
||||
|
||||
def fe_update_status(self):
|
||||
req = dian.GetStatusZip
|
||||
if self.fe_habilitacion:
|
||||
req = dian.Habilitacion.GetStatusZip
|
||||
resp = client.request(req(trackId = self.fe_delivery_trackid))
|
||||
resp = self.do_dian_request(req(trackId = self.fe_delivery_trackid))
|
||||
|
||||
self.fe_delivery_status = str(resp)
|
||||
if resp['IsValid']:
|
||||
self.fe_delivery_state = 'done'
|
||||
params = {}
|
||||
params['fe_delivery_status'] = resp.StatusDescription
|
||||
if resp.IsValid:
|
||||
params['fe_delivery_state'] = 'donde'
|
||||
else:
|
||||
self.fe_delivery_state = 'failure'
|
||||
self.save()
|
||||
|
||||
params['fe_delivery_state'] = 'failure'
|
||||
|
||||
self._force_write(params)
|
||||
|
||||
def _force_write(self, params):
|
||||
self.state = 'draft'
|
||||
self.write([self], params)
|
||||
|
||||
|
||||
def fe_delivery_test(self):
|
||||
if self.fe_delivery_state != 'queued':
|
||||
config = Pool().get('account_invoice_facho.configuration')(1)
|
||||
if self.fe_delivery_state not in ['queued', 'draft']:
|
||||
return
|
||||
|
||||
|
||||
facho_invoice = self.tofacho()
|
||||
xml_invoice = from.DIANInvoiceXML(facho_invoice)
|
||||
xml_invoice = form.DIANInvoiceXML(facho_invoice)
|
||||
|
||||
zipdata = io.BytesIO()
|
||||
with fe.DianZIP(zipdata) as dianzip:
|
||||
name_invoice = dianzip.add_invoice_xml(facho_invoice.invoice_ident, str(xml_invoice))
|
||||
dianzip.add_invoice_xml(facho_invoice.invoice_ident, str(xml_invoice))
|
||||
|
||||
config = pool.get('account_invoice_facho.configuration')(1)
|
||||
client = dian.DianSignatureClient(config.dian_fe_llave_privada,
|
||||
config.dian_fe_llave_publica,
|
||||
password=config.dian_fe_llave_frasepaso)
|
||||
zipdata.seek(0)
|
||||
filename = 'invoice_%s' % (facho_invoice.invoice_ident)
|
||||
req = client.required(dian.Habilitacion.SendTestSetAsync(
|
||||
res = self.do_dian_request(dian.Habilitacion.SendTestSetAsync(
|
||||
filename, zipdata.read(),
|
||||
config.dian_fe_test_setid
|
||||
))
|
||||
if req['ErrorMessageList']:
|
||||
raise UserError(str(req))
|
||||
self.fe_delivery_trackid = req['ZipKey']
|
||||
self.state = 'delivered'
|
||||
self.save()
|
||||
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
|
||||
self.fe_delivery_test()
|
||||
|
||||
@classmethod
|
||||
def fe_delivery(cls):
|
||||
for inv in cls.search([('is_fe_colombia', '=', True),
|
||||
('state', 'in', ['posted', 'paid'])]):
|
||||
inv.fe_process()
|
||||
if inv.fe_delivery_state == 'delivered':
|
||||
inv.fe_update_status()
|
||||
|
||||
|
||||
class Product(metaclass=PoolMeta):
|
||||
__name__ = 'product.product'
|
||||
|
||||
|
@ -161,7 +195,7 @@ class InvoiceLine(metaclass=PoolMeta):
|
|||
|
||||
def tofacho(self):
|
||||
tax_subtotals = []
|
||||
for taxes, unit_price, quantity in line.taxable_lines:
|
||||
for taxes, unit_price, quantity in self.taxable_lines:
|
||||
for tax in taxes:
|
||||
tax_subtotals.append(form.TaxSubTotal(
|
||||
percent = tax.rate
|
||||
|
@ -171,7 +205,7 @@ class InvoiceLine(metaclass=PoolMeta):
|
|||
quantity = self.quantity,
|
||||
description = self.description,
|
||||
# TODO debe ser decimal
|
||||
price_amount = float(line.unit_price),
|
||||
price_amount = float(self.unit_price),
|
||||
item = self.product.tofacho(),
|
||||
tax = form.TaxTotal(
|
||||
subtotals = tax_subtotals
|
||||
|
|
11
invoice.xml
11
invoice.xml
|
@ -13,6 +13,17 @@
|
|||
<field name="inherit" ref="account_invoice.invoice_view_form"/>
|
||||
<field name="name">invoice_fe_colombia_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="invoice_fe_page_in_form">
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit" ref="account_invoice.invoice_view_form"/>
|
||||
<field name="name">invoice_page_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="party_fe_colombia_form">
|
||||
<field name="model">party.party</field>
|
||||
<field name="inherit" ref="party.party_view_form"/>
|
||||
<field name="name">party_form</field>
|
||||
</record>
|
||||
<menuitem name="Customer Invoice Fe Colombia"
|
||||
parent="account_invoice.menu_invoices" action="act_invoice_in_form"
|
||||
id="menu_invoice_fe_colombia_in_form" sequence="3"/>
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
<field name="dian_fe_NITObligadoFacturarElectronicamente"/>
|
||||
<label name="dian_fe_IdentificadorSoftware"/>
|
||||
<field name="dian_fe_IdentificadorSoftware"/>
|
||||
<label name="dian_fe_certificado"/>
|
||||
<field name="dian_fe_certificado"/>
|
||||
<label name="dian_fe_llave_publica"/>
|
||||
<field name="dian_fe_llave_publica"/>
|
||||
<label name="dian_fe_llave_privada"/>
|
||||
<field name="dian_fe_llave_privada"/>
|
||||
<label name="dian_fe_test_setid"/>
|
||||
<field name="dian_fe_test_setid"/>
|
||||
<label name="dian_fe_llave_frasepaso"/>
|
||||
<field name="dian_fe_llave_frasepaso"/>
|
||||
</form>
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
<data>
|
||||
<xpath expr="/form/field[@name='reference']"
|
||||
position="after">
|
||||
<label name="tipo_responsabilidad"/>
|
||||
<field name="tipo_responsabilidad"/>
|
||||
<label name="tipo_organizacion"/>
|
||||
<field name="tipo_organizacion"/>
|
||||
<label name="fe_habilitacion"/>
|
||||
<field name="fe_habilitacion"/>
|
||||
</xpath>
|
||||
</data>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath expr="/form/notebook/page[@id='payment']"
|
||||
position="after">
|
||||
<page string="FE Colombia" name="fe_colombia">
|
||||
<label name="fe_delivery_state"/>
|
||||
<field name="fe_delivery_state"/>
|
||||
<label name="fe_delivery_status"/>
|
||||
<field name="fe_delivery_status"/>
|
||||
<label name="fe_delivery_trackid"/>
|
||||
<field name="fe_delivery_trackid"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</data>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath expr="/form/notebook/page[@name='identifiers']"
|
||||
position="after">
|
||||
<page string="FE Colombia" name="fe_colombia">
|
||||
<label name="fe_tipo_responsabilidad"/>
|
||||
<field name="fe_tipo_responsabilidad"/>
|
||||
<label name="fe_tipo_organizacion"/>
|
||||
<field name="fe_tipo_organizacion"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</data>
|
Loading…
Reference in New Issue