Compare commits

...

15 Commits
master ... 6.0

24 changed files with 2099 additions and 283 deletions

View File

@ -2,8 +2,8 @@ from trytond.pool import Pool
from . import configuration
from . import invoice
from . import facho
from . import dian
from . import ir
__all__ = ['register']
@ -12,18 +12,18 @@ def register():
Pool.register(
configuration.Configuration,
configuration.ConfigurationDianFECompany,
facho.FEGenericCode,
invoice.Invoice,
invoice.InvoiceLine,
invoice.Product,
invoice.PartyFeIdentifier,
invoice.PartyFeOrganization,
invoice.Party,
#invoice.PartyFeOrganization,
#invoice.Party,
invoice.Cron,
dian.RangoFacturacion,
dian.InvoiceResolution,
ir.Trigger,
module='account_invoice_facho', type_='model')
Pool.register(
dian.SincronizarRangoFacturacion,
module='account_invoice_facho', type_='wizard')
Pool.register(
invoice.InvoiceReportDianZip,
module='account_invoice_facho', type_='report')

View File

@ -9,35 +9,53 @@ class Configuration(
'Facho Configuration'
__name__ = 'account_invoice_facho.configuration'
dian_fe_habilitacion = fields.MultiValue(fields.Boolean('Habilitacion'))
dian_fe_key= fields.MultiValue(fields.Char('Dian FE KEY'))
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'))
dian_fe_habilitation = fields.MultiValue(fields.Boolean('Habilitation'))
dian_fe_debit_note = fields.MultiValue(fields.Boolean('Debit Note'))
dian_fe_public_key = fields.MultiValue(fields.Binary('Public Key',
help="PCKS#12"))
dian_fe_private_key = fields.MultiValue(fields.Binary('Private Key',
help="PCKS#12"))
dian_fe_cert = fields.MultiValue(fields.Binary('Cert',
help="PCKS#12"))
dian_fe_cert_passpharase = fields.MultiValue(fields.Char('Cert Passpharase'))
dian_fe_test_setid = fields.MultiValue(fields.Char('Testsetid Dian'))
dian_fe_technologic_supplier = fields.MultiValue(fields.Many2One('party.party',
'Technologic Supplier'))
dian_fe_obliged_bill = fields.MultiValue(fields.Many2One('party.party',
'Obliged to bill'))
dian_fe_software_identification = fields.MultiValue(fields.Char('Software Identification'))
dian_fe_pin = fields.MultiValue(fields.Char('PIN'))
dian_fe_invoice_resolution = fields.MultiValue(fields.Many2One('account.invoice.resolution',
'Invoice Resolution'))
@classmethod
def multivalue_model(cls, field):
pool = Pool()
return pool.get('account_invoice_facho.dian_fe_company')
class ConfigurationDianFECompany(ModelSQL, CompanyValueMixin):
'Configuration - DianFECompany'
__name__ = 'account_invoice_facho.dian_fe_company'
configuration = fields.Many2One('account_invoice_facho.configuration', 'Configuration',
required=True, ondelete='CASCADE')
dian_fe_habilitacion = fields.Boolean('Habilitacion')
dian_fe_key = fields.Char('Dian key')
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')
dian_fe_habilitation = fields.Boolean('Habilitation')
dian_fe_debit_note = fields.Boolean('Debit Note')
dian_fe_public_key = fields.Binary('Public Key',
help="PCKS#12")
dian_fe_private_key = fields.Binary('Private Key',
help="PCKS#12")
dian_fe_test_setid = fields.Char('Testsetid Dian')
dian_fe_cert = fields.Binary('Cert',
help="PCKS#12")
dian_fe_cert_passpharase = fields.Char('Cert Passpharase')
dian_fe_technologic_supplier = fields.Many2One('party.party',
'Technologic Supplier')
dian_fe_obliged_bill = fields.Many2One(
'party.party',
'Obliged to bill')
dian_fe_software_identification = fields.Char('Software Identification')
dian_fe_pin = fields.Char('PIN')
dian_fe_invoice_resolution = fields.Many2One('account.invoice.resolution',
'Invoice Resolution')

View File

@ -1,12 +1,14 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="ir.action.act_window" id="act_configuration_form">
<record model="ir.action.act_window" id="act_configuration_facho_form">
<field name="name">Configuration</field>
<field name="res_model">account_invoice_facho.configuration</field>
</record>
<menuitem name="Facho" id="menu_facho"
parent="account.menu_account_configuration"/>
<menuitem parent="menu_facho"
action="act_configuration_form"
action="act_configuration_facho_form"
id="menu_configuration"
sequence="10"/>
<record model="ir.ui.view" id="configuration_view_form">
@ -18,7 +20,7 @@
id="act_configuration_view1">
<field name="sequence" eval="1"/>
<field name="view" ref="configuration_view_form"/>
<field name="act_window" ref="act_configuration_form"/>
<field name="act_window" ref="act_configuration_facho_form"/>
</record>
</data>

19
dian.py
View File

@ -1,20 +1,13 @@
from trytond.model import ModelSQL, ModelView, fields
from trytond.wizard import Wizard, StateTransition
from trytond.pool import Pool
from trytond.pool import Pool, PoolMeta
class RangoFacturacion(ModelSQL, ModelView):
'Rango Facturacion'
__name__ = 'account_invoice_facho.dian_rango_facturacion'
class InvoiceResolution(metaclass=PoolMeta):
'Invoice Resolution'
__name__ = 'account.invoice.resolution'
NumeroResolucion = fields.Char('Numero Resolucion')
FechaResolucion = fields.Date('Fecha Resolucion')
Prefijo = fields.Char('Prefijo')
RangoInicial = fields.Integer('Rango Inicial')
RangoFinal = fields.Integer('Rango Final')
FechaVigenciaDesde = fields.Date('Fecha Vigencia Desde')
FechaVigenciaHasta = fields.Date('Fecha Vigencia Hasta')
ClaveTecnica = fields.Char('Clave Tecnica')
technical_key = fields.Char('Technical Key')
@ -27,7 +20,7 @@ class SincronizarRangoFacturacion(Wizard):
def transition_start(self):
pool = Pool()
config = pool.get('account_invoice_facho.configuration')(1)
RangoFacturacion = pool.get('account_invoice_facho.dian_rango_facturacion')
RangoFacturacion = pool.get('account.invoice.resolution')
from .exceptions import DianClientError
from facho.fe.client import dian

View File

@ -1,28 +1,20 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="ir.action.act_window" id="act_dian_rango_facturacion">
<field name="name">Rango Facturacion</field>
<field name="res_model">account_invoice_facho.dian_rango_facturacion</field>
</record>
<data>
<menuitem parent="menu_facho"
name="Dian"
id="menu_dian"/>
<menuitem parent="menu_dian"
id="menu_dian_rango_facturacion"
action="act_dian_rango_facturacion"/>
<record model="ir.action.wizard" id="sincronizar_dian_rango_facturacion">
<field name="name">Sincronizar Rango Facturacion</field>
<field name="wiz_name">account_invoice_facho.sincronizar_rango_facturacion</field>
<field name="model">account_invoice_facho.dian_rango_facturacion</field>
</record>
<record model="ir.action.keyword" id="sincronizar_dian_rango_facturacion_keyword">
<field name="keyword">form_action</field>
<field name="model">account_invoice_facho.dian_rango_facturacion,-1</field>
<field name="action" ref="sincronizar_dian_rango_facturacion"/>
<record model="ir.ui.view" id="invoice_resolution_view_form">
<field name="model">account.invoice.resolution</field>
<field name="inherit" ref="account_invoice_subtype.invoice_resolution_view_form"/>
<field name="name">invoice_resolution_form</field>
</record>
</data>
</tryton>

26
email_invoice.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html xmlns:py="http://genshi.edgewall.org/" xmlns:i18n="http://genshi.edgewall.org/i18n">
<head>
<title>Factura electr&oacute;nica</title>
</head>
<body>
<div style="display: block; text-align: center">
<div>
<h3>Estimado cliente</h3>
<p>
Adjunto a este correo encontrar&aacute; la factura correspondiente adquisici&oacute;n de Productos.<br/>
La factura electr&oacute;nica que usted est&aacute; recibiendo se conforma por dos archivos:<br/>
La representaci&oacute;n gr&aacute;fica en formato .pdf que usted podr&aacute; imprimir<br/>
La representaci&oacute;n electr&oacute;nica en formato .xml que usted deber&aacute; conservar<br/>
Si su factura presenta alg&uacute;n error, le agradecemos a m&aacute;s tardar dentro de las siguientes<br/>
48 horas, notificar en el:<br/>
Correo de autorespuesta: ${record.company.party.email}<br/>
Saludos cordiales<br/>
</p>
</div>
<hr style="margin-top: 20px; border-style: solid none none; border-color: #EEE"></hr>
<div style="font-size: 80%; color: #777">
</div>
</div>
</body>
</html>

237
icons/facho-mail-fail.svg Normal file
View File

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 7.9374999 7.9375003"
version="1.1"
id="svg168"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="facho-mail-fail.svg">
<defs
id="defs162">
<linearGradient
id="linearGradient2876"
osb:paint="solid">
<stop
style="stop-color:#f3ecec;stop-opacity:1;"
offset="0"
id="stop2874" />
</linearGradient>
<radialGradient
cx="20.687"
cy="46.616001"
r="12.228"
id="5"
xlink:href="#2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)" />
<linearGradient
id="2">
<stop
id="9"
stop-color="#2e3436" />
<stop
id="A"
offset="1"
stop-color="#2e3436"
stop-opacity="0" />
</linearGradient>
<linearGradient
y1="4.5500002"
x2="0"
y2="44.23"
id="6"
xlink:href="#4"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="4">
<stop
id="D"
stop-color="#fff"
stop-opacity="0.8" />
<stop
id="E"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
id="3">
<stop
id="B"
stop-color="#fff" />
<stop
id="C"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient2878"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient2970"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.6156714,-24.298035)"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient2972"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.6156712,-24.298036)"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2026"
id="linearGradient3457"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.65718,0,0,0.65718,-16.966,114.63)"
x1="-344.14999"
y1="274.70999"
x2="-395.85001"
y2="425.39999" />
<linearGradient
id="linearGradient2026"
y2="425.39999"
gradientUnits="userSpaceOnUse"
x2="-395.85001"
gradientTransform="matrix(-0.65718,0,0,0.65718,-16.966,114.63)"
y1="274.70999"
x1="-344.14999"
inkscape:collect="always">
<stop
id="stop2557"
style="stop-color:#ffffff"
offset="0" />
<stop
id="stop2559"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.25"
inkscape:cx="12"
inkscape:cy="14.431163"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1359"
inkscape:window-height="768"
inkscape:window-x="1426"
inkscape:window-y="133"
inkscape:window-maximized="0" />
<metadata
id="metadata165">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2938"
transform="matrix(0.07655872,0,0,0.07655872,-0.82698095,-70.45226)"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
style="fill:#3465a3;fill-opacity:1">
<g
id="g2926"
transform="matrix(0.88372,0,0,0.88372,-70.642,889.36)"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient2878)">
<path
id="path2922"
sodipodi:nodetypes="ccccc"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient2970);stroke-width:1.1316px"
d="M 93.384329,48.063965 V 133.06397 H 208.38433 V 48.063965 l -115.000001,-3e-6 z" />
<path
id="path2924"
sodipodi:nodetypes="ccccccc"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient2972)"
d="m 93.384329,51.076965 55.000001,50.985005 60,-50.985005 v -3.013 l -60,50.998005 -55.000001,-50.998005 z" />
</g>
</g>
<g
id="g2071"
transform="matrix(0.02600553,0,0,0.02600553,-0.42621541,-5.4013957)"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<rect
id="rect3417"
style="fill:#f00a10;fill-rule:evenodd"
inkscape:export-ydpi="7.7063322"
rx="39.431"
transform="scale(-1,1)"
ry="39.431"
width="145.82001"
inkscape:export-xdpi="7.7063322"
y="318.34"
x="-318.76001"
height="144.64"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png" />
<g
id="g3479"
inkscape:export-ydpi="7.7063322"
inkscape:export-xdpi="7.7063322"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
transform="matrix(0.65718,0,0,0.65718,-102.64,-95.387)">
<path
id="path3419"
style="fill:#cb1e0e"
d="m 554.13,739.6 35.77,-35.77 c 3.75,-3.75 5.63,-7.9 5.63,-12.44 -0.23,-4.09 -2.1,-7.9 -5.63,-11.42 -3.18,-3.18 -6.92,-4.99 -11.24,-5.45 -4.43,-0.34 -8.63,1.48 -12.61,5.45 l -35.78,35.78 -35.77,-35.78 c -3.64,-3.63 -7.73,-5.45 -12.27,-5.45 -4.43,0.34 -8.29,2.16 -11.58,5.45 -2.84,2.84 -4.49,6.53 -4.95,11.08 -0.45,4.77 1.2,9.03 4.95,12.78 l 35.77,35.77 -35.77,35.78 c -3.18,3.18 -4.95,7.33 -5.29,12.44 0.34,4.43 2.11,8.23 5.29,11.41 2.95,2.96 6.7,4.77 11.24,5.45 4.43,0.35 8.63,-1.47 12.61,-5.45 l 35.77,-35.77 35.78,35.77 c 3.75,3.75 7.9,5.4 12.44,4.94 4.66,-0.34 8.46,-1.98 11.41,-4.94 2.73,-2.72 4.38,-6.41 4.95,-11.07 0.68,-4.54 -0.97,-8.8 -4.95,-12.78 L 554.13,739.6" />
<path
id="path3421"
style="fill:#ffffff"
d="m 552.28,739.6 32.99,-32.98 c 3.45,-3.46 5.18,-7.28 5.18,-11.47 -0.21,-3.77 -1.94,-7.28 -5.18,-10.53 -2.94,-2.93 -6.39,-4.6 -10.37,-5.02 -4.08,-0.32 -7.96,1.36 -11.62,5.02 l -32.99,32.99 -32.99,-32.99 c -3.35,-3.35 -7.12,-5.02 -11.31,-5.02 -4.08,0.31 -7.64,1.99 -10.68,5.02 -2.62,2.62 -4.14,6.03 -4.56,10.22 -0.41,4.39 1.1,8.32 4.56,11.78 l 32.99,32.98 -32.99,32.99 c -2.93,2.93 -4.56,6.75 -4.87,11.47 0.31,4.08 1.94,7.59 4.87,10.52 2.72,2.72 6.18,4.4 10.37,5.03 4.08,0.31 7.96,-1.36 11.62,-5.03 l 32.99,-32.99 32.99,32.99 c 3.45,3.46 7.27,4.98 11.46,4.56 4.3,-0.32 7.8,-1.84 10.53,-4.56 2.51,-2.51 4.03,-5.92 4.55,-10.21 0.63,-4.19 -0.89,-8.11 -4.55,-11.78 L 552.28,739.6" />
</g>
<path
id="path3423"
style="fill:url(#linearGradient3457);fill-rule:evenodd"
d="m 280.23,324.53 h -68.77 c -18.2,0 -32.86,14.65 -32.86,32.86 v 66.55 c 0.59,14.21 2.86,5.23 7.17,-10.51 5.02,-18.29 21.35,-34.27 41.23,-46.25 15.18,-9.15 32.17,-14.99 63.1,-15.54 17.54,-0.32 15.99,-22.58 -9.87,-27.11 z"
inkscape:export-ydpi="7.7063322"
sodipodi:nodetypes="ccccsssc"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
inkscape:export-xdpi="7.7063322" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

204
icons/facho-mail-ok.svg Normal file
View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 7.9374999 7.9375003"
version="1.1"
id="svg168"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="facho-mail-ok.svg">
<defs
id="defs162">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient3453"
gradientUnits="userSpaceOnUse"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862" />
<linearGradient
id="linearGradient2876"
osb:paint="solid">
<stop
style="stop-color:#f3ecec;stop-opacity:1;"
offset="0"
id="stop2874" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient3449"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.6156714,-24.298035)"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2876"
id="linearGradient3451"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.6156712,-24.298036)"
x1="94.434196"
y1="114.862"
x2="210.5658"
y2="114.862" />
<radialGradient
cx="20.687"
cy="46.616001"
r="12.228"
id="5"
xlink:href="#2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)" />
<linearGradient
id="2">
<stop
id="9"
stop-color="#2e3436" />
<stop
id="A"
offset="1"
stop-color="#2e3436"
stop-opacity="0" />
</linearGradient>
<linearGradient
y1="4.5500002"
x2="0"
y2="44.23"
id="6"
xlink:href="#4"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="4">
<stop
id="D"
stop-color="#fff"
stop-opacity="0.8" />
<stop
id="E"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#3"
id="linearGradient3455"
gradientUnits="userSpaceOnUse"
x1="18.389"
y1="-12.905"
x2="34.681"
y2="29.688" />
<linearGradient
id="3">
<stop
id="B"
stop-color="#fff" />
<stop
id="C"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.25"
inkscape:cx="12"
inkscape:cy="12"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1359"
inkscape:window-height="768"
inkscape:window-x="1426"
inkscape:window-y="133"
inkscape:window-maximized="0" />
<metadata
id="metadata165">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g3735"
transform="matrix(0.06750311,0,0,0.06156108,-6.222416,-2.2032372)"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient3453)">
<path
id="path2820"
sodipodi:nodetypes="ccccc"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient3449);stroke-width:1.1316px"
d="M 93.384329,48.063965 V 133.06397 H 208.38433 V 48.063965 l -115.000001,-3e-6 z" />
<path
id="path3612"
sodipodi:nodetypes="ccccccc"
style="fill:#3465a3;fill-opacity:1;stroke:url(#linearGradient3451)"
d="m 93.384329,51.076965 55.000001,50.985005 60,-50.985005 v -3.013 l -60,50.998005 -55.000001,-50.998005 z" />
</g>
<g
transform="matrix(0.0954752,0,0,0.0870709,3.5183606,1.9253427)"
id="8">
<path
d="m 31.44716,45.129018 c 0,0.906037 -4.491673,1.640524 -10.032432,1.640524 -5.540759,0 -10.032431,-0.734487 -10.032431,-1.640524 0,-0.906036 4.491672,-1.640523 10.032431,-1.640523 5.540759,0 10.032432,0.734487 10.032432,1.640523 z"
id="F"
opacity="0.8"
fill="url(#5)"
style="fill:url(#5)" />
<path
d="M 37.395259,3.9928032 C 36.751767,3.881258 36.084975,4.1531965 35.70893,4.7391151 L 19.687179,29.697689 11.077028,21.800115 C 10.295804,21.298722 9.2618142,21.512776 8.7604174,22.294002 l -4.4617137,4.963236 c -0.5013867,0.781219 -0.2742552,1.815825 0.5069644,2.317217 0,0 15.6848449,14.93278 15.7046779,14.94441 0.183096,0.117517 0.37856,0.183941 0.579198,0.223816 0.65542,0.130262 1.354145,-0.132654 1.738024,-0.730775 L 44.435002,10.35218 C 44.936393,9.570958 44.709267,8.5363529 43.928039,8.0349601 L 38.026151,4.2321538 C 37.830842,4.1068047 37.609756,4.0299838 37.395259,3.9928032 Z"
id="G"
fill="#8bb300"
stroke="#445800"
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="1.061" />
<path
d="m 37,5.09375 c -0.222462,0.068582 -0.368311,0.2935582 -0.6875,0.75 l -8.125,12.71875 -7.25,11.1875 c -0.07531,0.06635 -0.114229,0.155323 -0.15625,0.25 -0.04202,0.09468 -0.09546,0.182583 -0.15625,0.28125 -0.121581,0.197334 -0.311651,0.38921 -0.75,0.46875 -0.306118,0.05555 -0.454585,0.03303 -0.625,-0.0625 -0.170415,-0.09553 -0.338659,-0.262637 -0.65625,-0.5 L 11,23.25 c -0.211436,-0.196035 -0.366685,-0.338043 -0.5,-0.4375 -0.133315,-0.09946 -0.255459,-0.151284 -0.375,-0.15625 -0.119541,-0.005 -0.23023,0.04256 -0.34375,0.125 C 9.66773,22.863687 9.5440059,22.977083 9.375,23.125 l -3.53125,3.84375 c -0.4763125,0.442708 -0.6947169,0.828134 -0.65625,1.21875 0.038467,0.390616 0.3182284,0.733606 0.84375,1.125 0,0 3.557027,3.391995 7.125,6.78125 1.783986,1.694627 3.566493,3.38424 4.90625,4.65625 0.669879,0.636005 1.233193,1.159628 1.625,1.53125 0.195903,0.185811 0.363216,0.337601 0.46875,0.4375 0.05277,0.04995 0.09738,0.09896 0.125,0.125 0.01381,0.01302 0.02395,0.02442 0.03125,0.03125 0.0011,9.44e-4 0.03118,-4.3e-5 0.03125,0 0.08073,0.05181 0.08877,0.0943 0.1875,0.1875 0.09873,0.0932 0.255536,0.234231 0.625,0.53125 0.139903,0.11247 0.326711,0.128203 0.46875,0.0625 0.142039,-0.0657 0.254912,-0.193662 0.375,-0.34375 0.240177,-0.300175 0.448124,-0.693175 0.625,-0.96875 L 43.40625,10.0625 C 43.524201,9.8787288 43.630105,9.7136106 43.6875,9.59375 43.744895,9.4738894 43.775145,9.3861103 43.75,9.28125 43.724855,9.1763897 43.635632,9.0844462 43.53125,9 43.426868,8.9155538 43.309755,8.8373201 43.125,8.71875 c -0.01033,-0.00186 -0.02092,-0.00186 -0.03125,0 L 37.8125,5.4375 C 37.622121,5.3160067 37.502367,5.215151 37.375,5.15625 37.247633,5.097349 37.114744,5.0583758 37,5.09375 Z"
id="H"
opacity="0.8"
fill="none"
stroke="url(#6)"
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="1.061"
style="stroke:url(#6)" />
<path
d="M 36.96875,4.5 C 36.634637,4.5401947 36.326814,4.7168023 36.125,5.03125 L 25.25,21.9375 c 4.538877,-1.517457 9.095334,-2.802858 13.65625,-3.875 l 5.125,-8 c 0.357447,-0.5569403 0.180055,-1.2687651 -0.375,-1.625 L 37.75,4.625 C 37.638068,4.553162 37.498851,4.5323019 37.3125,4.5 37.200153,4.4805254 37.080121,4.4866018 36.96875,4.5 Z M 9.875,22.0625 c -0.2851202,0.06083 -0.5453222,0.229783 -0.71875,0.5 C 9.1473,22.58404 9.13686,22.60492 9.125,22.625 l -4.40625,4.90625 c -0.00619,0.0096 0.00588,0.02152 0,0.03125 -0.3339753,0.552285 -0.1704409,1.243682 0.375,1.59375 0.021536,0.0089 0.04242,0.01939 0.0625,0.03125 0,0 0.496977,0.467173 0.53125,0.5 3.0185158,-1.352167 6.036186,-2.634284 9.0625,-3.84375 l -3.96875,-3.625 c -0.0098,-0.0063 -0.02139,0.006 -0.03125,0 -0.279841,-0.169766 -0.58988,-0.217075 -0.875,-0.15625 z"
id="I"
opacity="0.8"
fill="url(#7)"
stroke-width="1.061"
style="fill:url(#linearGradient3455)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

196
icons/facho-not-posted.svg Normal file
View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 7.9374999 7.9375003"
version="1.1"
id="svg168"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="facho-mail-ok.svg">
<defs
id="defs162">
<linearGradient
id="linearGradient2876"
osb:paint="solid">
<stop
style="stop-color:#f3ecec;stop-opacity:1;"
offset="0"
id="stop2874" />
</linearGradient>
<radialGradient
cx="20.687"
cy="46.616001"
r="12.228"
id="5"
xlink:href="#2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)" />
<linearGradient
id="2">
<stop
id="9"
stop-color="#2e3436" />
<stop
id="A"
offset="1"
stop-color="#2e3436"
stop-opacity="0" />
</linearGradient>
<linearGradient
y1="4.5500002"
x2="0"
y2="44.23"
id="6"
xlink:href="#4"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="4">
<stop
id="D"
stop-color="#fff"
stop-opacity="0.8" />
<stop
id="E"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
id="3">
<stop
id="B"
stop-color="#fff" />
<stop
id="C"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.25"
inkscape:cx="12"
inkscape:cy="15.5597"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1680"
inkscape:window-height="1020"
inkscape:window-x="1366"
inkscape:window-y="1"
inkscape:window-maximized="1"
showguides="false" />
<metadata
id="metadata165">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2079"
transform="matrix(0,-0.1771524,0.13864384,0,-0.19369734,9.3184576)">
<path
id="path2077"
sodipodi:nodetypes="cccccc"
style="color:#000000;display:block;fill:none;stroke:#ffffff;stroke-width:7.1343;stroke-linecap:round;stroke-linejoin:round"
d="M 11.75,54.375 V 5.625 h 27.688 l 8.812,8.813 v 39.937 z" />
<path
id="rect1089"
sodipodi:nodetypes="cccccc"
style="color:#000000;display:block;fill:#ffffff;fill-opacity:1;stroke:#3465a4;stroke-width:2.3781;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 11.75,54.375 V 5.625 h 27.688 l 8.812,8.813 v 39.937 z" />
<path
id="path1713"
sodipodi:nodetypes="cccc"
style="color:#000000;display:block;fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:2.3781;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 39.437,14.438 V 5.625 l 8.813,8.813 z" />
</g>
<path
id="path1326"
style="fill:none;stroke:#3465a4;stroke-width:0.372681;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 4.7335098,3.2555105 V 1.7920186" />
<g
id="g1344"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-opacity:1"
transform="matrix(-0.05219354,0,0,-0.16850794,4.816813,10.366819)"
inkscape:transform-center-x="-0.4252448"
inkscape:transform-center-y="0.16642046">
<path
id="path1346"
sodipodi:nodetypes="cc"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:3.9739;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 17.052,22.068 H 45.951" />
<path
id="path1348"
sodipodi:nodetypes="cc"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:3.9739;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 17.052,27.13 H 37.878" />
<path
id="path1350"
sodipodi:nodetypes="cc"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:3.9739;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 17.052,32.192 H 50.529" />
<path
id="path1352"
sodipodi:nodetypes="cc"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:3.9739;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 17.052,42.316 H 34.849" />
<path
id="path1354"
sodipodi:nodetypes="cc"
style="fill:#3465a4;fill-opacity:1;stroke:#3465a4;stroke-width:3.9739;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="m 17.052,37.254 h 30.95" />
</g>
<path
id="path2120"
sodipodi:nodetypes="cc"
style="fill:none;stroke:#3465a4;stroke-width:0.372681;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 5.6848078,1.7948457 H 6.4493072" />
<path
id="path2122"
sodipodi:nodetypes="cc"
style="fill:none;stroke:#3465a4;stroke-width:0.372681;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 5.6848077,3.147133 H 6.4493073" />
<path
id="path2124"
sodipodi:nodetypes="cc"
style="fill:none;stroke:#3465a4;stroke-width:0.372681;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 5.6848078,2.4475845 H 6.4493072" />
<g
id="Capa_x0020_1"
style="fill-rule:evenodd"
transform="matrix(0,-0.83556362,0.6539327,0,2.6037086,7.892856)">
<path
id="path58241"
style="fill:#949096;stroke:#2c2c2c;stroke-width:0.106927;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:162"
d="m 2.7227232,3.1073611 c -0.1464898,0 -0.2892372,0.01535 -0.4277075,0.04344 v 0.330805 c -0.1855181,0.04485 -0.3592743,0.116801 -0.5175261,0.213854 L 1.5433197,3.4615571 c -0.1197581,0.07946 -0.2293581,0.172676 -0.3309387,0.274 -0.1010459,0.101303 -0.1946069,0.210903 -0.27373285,0.330821 l 0.23363535,0.233903 c -0.096769,0.158626 -0.1689445,0.332115 -0.21385385,0.5179 h -0.3304041 c -0.028336,0.138203 -0.04384,0.281271 -0.04384,0.427708 0,0.146436 0.015504,0.289504 0.04384,0.427707 h 0.3304041 c 0.0449091,0.185786 0.11708495,0.359275 0.21385385,0.517954 l -0.23363535,0.233903 c 0.0791261,0.119865 0.17268695,0.229465 0.27373285,0.330778 0.1015806,0.101313 0.2111806,0.194553 0.3309387,0.274 l 0.2341699,-0.233902 c 0.1582518,0.09709 0.332008,0.168997 0.5175261,0.213853 v 0.330832 c 0.1384703,0.02807 0.2812177,0.04341 0.4277075,0.04341 0.1464898,0 0.2897718,-0.01534 0.4277075,-0.04341 v -0.330832 c 0.1860528,-0.04486 0.3592744,-0.116764 0.5180608,-0.213853 l 0.2341698,0.233902 c 0.1197583,-0.07945 0.2293583,-0.172687 0.3304043,-0.274 0.1015806,-0.101313 0.1946069,-0.210913 0.2742674,-0.330778 L 4.2731631,6.1915491 c 0.097303,-0.158679 0.1689446,-0.332168 0.213854,-0.517954 h 0.3309387 c 0.028335,-0.138203 0.043305,-0.281271 0.043305,-0.427707 0,-0.146437 -0.01497,-0.289505 -0.043305,-0.427708 H 4.4870171 c -0.044909,-0.185785 -0.1165506,-0.359274 -0.213854,-0.5179 L 4.507333,4.0663771 C 4.4276725,3.9464591 4.3346462,3.8368591 4.2330656,3.7355561 4.1320196,3.6342321 4.0224196,3.5410131 3.9026613,3.4615561 L 3.6684915,3.6954591 C 3.5097051,3.5984061 3.3364835,3.5264551 3.1504307,3.4816051 V 3.1508001 C 3.012495,3.1227101 2.869213,3.1073601 2.7227232,3.1073611 Z m 0,1.069269 c 0.5902364,0 1.0692688,0.479032 1.0692688,1.069268 0,0.590237 -0.4790324,1.069269 -1.0692688,1.069269 -0.5902363,0 -1.0692688,-0.479032 -1.0692688,-1.069269 0,-0.590236 0.4790325,-1.069268 1.0692688,-1.069268 z" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

192
icons/facho-send-fail.svg Normal file
View File

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 7.9374999 7.9375003"
version="1.1"
id="svg168"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="facho-send-fail.svg">
<defs
id="defs162">
<linearGradient
id="linearGradient2876"
osb:paint="solid">
<stop
style="stop-color:#f3ecec;stop-opacity:1;"
offset="0"
id="stop2874" />
</linearGradient>
<radialGradient
cx="20.687"
cy="46.616001"
r="12.228"
id="5"
xlink:href="#2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)" />
<linearGradient
id="2">
<stop
id="9"
stop-color="#2e3436" />
<stop
id="A"
offset="1"
stop-color="#2e3436"
stop-opacity="0" />
</linearGradient>
<linearGradient
y1="4.5500002"
x2="0"
y2="44.23"
id="6"
xlink:href="#4"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="4">
<stop
id="D"
stop-color="#fff"
stop-opacity="0.8" />
<stop
id="E"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
id="3">
<stop
id="B"
stop-color="#fff" />
<stop
id="C"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2026"
id="linearGradient2986"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.65718,0,0,0.65718,-16.966,114.63)"
x1="-344.14999"
y1="274.70999"
x2="-395.85001"
y2="425.39999" />
<linearGradient
id="linearGradient2026"
y2="425.39999"
gradientUnits="userSpaceOnUse"
x2="-395.85001"
gradientTransform="matrix(-0.65718,0,0,0.65718,-16.966,114.63)"
y1="274.70999"
x1="-344.14999"
inkscape:collect="always">
<stop
id="stop2557"
style="stop-color:#ffffff"
offset="0" />
<stop
id="stop2559"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.25"
inkscape:cx="12"
inkscape:cy="21.622174"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1359"
inkscape:window-height="768"
inkscape:window-x="1426"
inkscape:window-y="133"
inkscape:window-maximized="0" />
<metadata
id="metadata165">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="M 0.09278877,4.4518483 2.0366828,5.1808129 3.0086299,7.8536629 4.3989997,5.997257 6.896417,6.8817159 7.8683641,0.07809049 Z M 3.5767326,5.6376418 3.1315811,6.8452816 2.6038135,5.3300201 6.6869631,1.6215368 Z"
id="path2952"
style="fill:#3465a3;fill-opacity:1;stroke-width:0.485974"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<g
id="g2984"
transform="matrix(0.02745618,0,0,0.02745618,-0.91663178,-4.853659)"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<rect
id="rect2974"
style="fill:#f00a10;fill-rule:evenodd"
inkscape:export-ydpi="7.7063322"
rx="39.431"
transform="scale(-1,1)"
ry="39.431"
width="145.82001"
inkscape:export-xdpi="7.7063322"
y="318.34"
x="-318.76001"
height="144.64"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png" />
<g
id="g2980"
inkscape:export-ydpi="7.7063322"
inkscape:export-xdpi="7.7063322"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
transform="matrix(0.65718,0,0,0.65718,-102.64,-95.387)">
<path
id="path2976"
style="fill:#cb1e0e"
d="m 554.13,739.6 35.77,-35.77 c 3.75,-3.75 5.63,-7.9 5.63,-12.44 -0.23,-4.09 -2.1,-7.9 -5.63,-11.42 -3.18,-3.18 -6.92,-4.99 -11.24,-5.45 -4.43,-0.34 -8.63,1.48 -12.61,5.45 l -35.78,35.78 -35.77,-35.78 c -3.64,-3.63 -7.73,-5.45 -12.27,-5.45 -4.43,0.34 -8.29,2.16 -11.58,5.45 -2.84,2.84 -4.49,6.53 -4.95,11.08 -0.45,4.77 1.2,9.03 4.95,12.78 l 35.77,35.77 -35.77,35.78 c -3.18,3.18 -4.95,7.33 -5.29,12.44 0.34,4.43 2.11,8.23 5.29,11.41 2.95,2.96 6.7,4.77 11.24,5.45 4.43,0.35 8.63,-1.47 12.61,-5.45 l 35.77,-35.77 35.78,35.77 c 3.75,3.75 7.9,5.4 12.44,4.94 4.66,-0.34 8.46,-1.98 11.41,-4.94 2.73,-2.72 4.38,-6.41 4.95,-11.07 0.68,-4.54 -0.97,-8.8 -4.95,-12.78 L 554.13,739.6" />
<path
id="path2978"
style="fill:#ffffff"
d="m 552.28,739.6 32.99,-32.98 c 3.45,-3.46 5.18,-7.28 5.18,-11.47 -0.21,-3.77 -1.94,-7.28 -5.18,-10.53 -2.94,-2.93 -6.39,-4.6 -10.37,-5.02 -4.08,-0.32 -7.96,1.36 -11.62,5.02 l -32.99,32.99 -32.99,-32.99 c -3.35,-3.35 -7.12,-5.02 -11.31,-5.02 -4.08,0.31 -7.64,1.99 -10.68,5.02 -2.62,2.62 -4.14,6.03 -4.56,10.22 -0.41,4.39 1.1,8.32 4.56,11.78 l 32.99,32.98 -32.99,32.99 c -2.93,2.93 -4.56,6.75 -4.87,11.47 0.31,4.08 1.94,7.59 4.87,10.52 2.72,2.72 6.18,4.4 10.37,5.03 4.08,0.31 7.96,-1.36 11.62,-5.03 l 32.99,-32.99 32.99,32.99 c 3.45,3.46 7.27,4.98 11.46,4.56 4.3,-0.32 7.8,-1.84 10.53,-4.56 2.51,-2.51 4.03,-5.92 4.55,-10.21 0.63,-4.19 -0.89,-8.11 -4.55,-11.78 L 552.28,739.6" />
</g>
<path
id="path2982"
style="fill:url(#linearGradient2986);fill-rule:evenodd"
d="m 280.23,324.53 h -68.77 c -18.2,0 -32.86,14.65 -32.86,32.86 v 66.55 c 0.59,14.21 2.86,5.23 7.17,-10.51 5.02,-18.29 21.35,-34.27 41.23,-46.25 15.18,-9.15 32.17,-14.99 63.1,-15.54 17.54,-0.32 15.99,-22.58 -9.87,-27.11 z"
inkscape:export-ydpi="7.7063322"
sodipodi:nodetypes="ccccsssc"
inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
inkscape:export-xdpi="7.7063322" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

186
icons/facho-send-ok.svg Normal file
View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 7.9374999 7.9375003"
version="1.1"
id="svg168"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="facho-send-ok.svg">
<defs
id="defs162">
<linearGradient
id="linearGradient2876"
osb:paint="solid">
<stop
style="stop-color:#f3ecec;stop-opacity:1;"
offset="0"
id="stop2874" />
</linearGradient>
<radialGradient
cx="20.687"
cy="46.616001"
r="12.228"
id="5"
xlink:href="#2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)" />
<linearGradient
id="2">
<stop
id="9"
stop-color="#2e3436" />
<stop
id="A"
offset="1"
stop-color="#2e3436"
stop-opacity="0" />
</linearGradient>
<linearGradient
y1="4.5500002"
x2="0"
y2="44.23"
id="6"
xlink:href="#4"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="4">
<stop
id="D"
stop-color="#fff"
stop-opacity="0.8" />
<stop
id="E"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<linearGradient
id="3">
<stop
id="B"
stop-color="#fff" />
<stop
id="C"
offset="1"
stop-color="#fff"
stop-opacity="0" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#2"
id="radialGradient2964"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8204677,0,0,0.1341645,4.4416214,38.87484)"
cx="20.687"
cy="46.616001"
r="12.228" />
<linearGradient
inkscape:collect="always"
xlink:href="#4"
id="linearGradient2966"
gradientUnits="userSpaceOnUse"
y1="4.5500002"
x2="0"
y2="44.23" />
<linearGradient
x1="18.389"
y1="-12.905"
x2="34.681"
y2="29.688"
id="7"
xlink:href="#3"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.25"
inkscape:cx="12"
inkscape:cy="9.0379046"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1359"
inkscape:window-height="768"
inkscape:window-x="1426"
inkscape:window-y="133"
inkscape:window-maximized="0" />
<metadata
id="metadata165">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g133"
transform="matrix(1.4918618,0,0,1.4918618,-0.39893873,1.9512831)">
<path
d="m 0.325281,1.692508 1.299999,0.487504 0.649999,1.787497 0.9298275,-1.241492 1.670176,0.591492 0.649999,-4.55 z M 2.6552055,2.48552 2.357507,3.293144 2.004555,2.279795 4.7352065,-0.200294 Z"
id="path112"
style="fill:#3465a3;fill-opacity:1;stroke-width:0.325001"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<g
transform="matrix(0.06373488,0,0,0.06373488,2.265015,0.955526)"
id="g2962">
<path
d="m 31.44716,45.129018 c 0,0.906037 -4.491673,1.640524 -10.032432,1.640524 -5.540759,0 -10.032431,-0.734487 -10.032431,-1.640524 0,-0.906036 4.491672,-1.640523 10.032431,-1.640523 5.540759,0 10.032432,0.734487 10.032432,1.640523 z"
id="path2954"
opacity="0.8"
fill="url(#5)"
style="fill:url(#radialGradient2964)" />
<path
d="M 37.395259,3.9928032 C 36.751767,3.881258 36.084975,4.1531965 35.70893,4.7391151 L 19.687179,29.697689 11.077028,21.800115 C 10.295804,21.298722 9.2618142,21.512776 8.7604174,22.294002 l -4.4617137,4.963236 c -0.5013867,0.781219 -0.2742552,1.815825 0.5069644,2.317217 0,0 15.6848449,14.93278 15.7046779,14.94441 0.183096,0.117517 0.37856,0.183941 0.579198,0.223816 0.65542,0.130262 1.354145,-0.132654 1.738024,-0.730775 L 44.435002,10.35218 C 44.936393,9.570958 44.709267,8.5363529 43.928039,8.0349601 L 38.026151,4.2321538 C 37.830842,4.1068047 37.609756,4.0299838 37.395259,3.9928032 Z"
id="path2956"
fill="#8bb300"
stroke="#445800"
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="1.061" />
<path
d="m 37,5.09375 c -0.222462,0.068582 -0.368311,0.2935582 -0.6875,0.75 l -8.125,12.71875 -7.25,11.1875 c -0.07531,0.06635 -0.114229,0.155323 -0.15625,0.25 -0.04202,0.09468 -0.09546,0.182583 -0.15625,0.28125 -0.121581,0.197334 -0.311651,0.38921 -0.75,0.46875 -0.306118,0.05555 -0.454585,0.03303 -0.625,-0.0625 -0.170415,-0.09553 -0.338659,-0.262637 -0.65625,-0.5 L 11,23.25 c -0.211436,-0.196035 -0.366685,-0.338043 -0.5,-0.4375 -0.133315,-0.09946 -0.255459,-0.151284 -0.375,-0.15625 -0.119541,-0.005 -0.23023,0.04256 -0.34375,0.125 C 9.66773,22.863687 9.5440059,22.977083 9.375,23.125 l -3.53125,3.84375 c -0.4763125,0.442708 -0.6947169,0.828134 -0.65625,1.21875 0.038467,0.390616 0.3182284,0.733606 0.84375,1.125 0,0 3.557027,3.391995 7.125,6.78125 1.783986,1.694627 3.566493,3.38424 4.90625,4.65625 0.669879,0.636005 1.233193,1.159628 1.625,1.53125 0.195903,0.185811 0.363216,0.337601 0.46875,0.4375 0.05277,0.04995 0.09738,0.09896 0.125,0.125 0.01381,0.01302 0.02395,0.02442 0.03125,0.03125 0.0011,9.44e-4 0.03118,-4.3e-5 0.03125,0 0.08073,0.05181 0.08877,0.0943 0.1875,0.1875 0.09873,0.0932 0.255536,0.234231 0.625,0.53125 0.139903,0.11247 0.326711,0.128203 0.46875,0.0625 0.142039,-0.0657 0.254912,-0.193662 0.375,-0.34375 0.240177,-0.300175 0.448124,-0.693175 0.625,-0.96875 L 43.40625,10.0625 C 43.524201,9.8787288 43.630105,9.7136106 43.6875,9.59375 43.744895,9.4738894 43.775145,9.3861103 43.75,9.28125 43.724855,9.1763897 43.635632,9.0844462 43.53125,9 43.426868,8.9155538 43.309755,8.8373201 43.125,8.71875 c -0.01033,-0.00186 -0.02092,-0.00186 -0.03125,0 L 37.8125,5.4375 C 37.622121,5.3160067 37.502367,5.215151 37.375,5.15625 37.247633,5.097349 37.114744,5.0583758 37,5.09375 Z"
id="path2958"
opacity="0.8"
fill="none"
stroke="url(#6)"
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="1.061"
style="stroke:url(#linearGradient2966)" />
<path
d="M 36.96875,4.5 C 36.634637,4.5401947 36.326814,4.7168023 36.125,5.03125 L 25.25,21.9375 c 4.538877,-1.517457 9.095334,-2.802858 13.65625,-3.875 l 5.125,-8 c 0.357447,-0.5569403 0.180055,-1.2687651 -0.375,-1.625 L 37.75,4.625 C 37.638068,4.553162 37.498851,4.5323019 37.3125,4.5 37.200153,4.4805254 37.080121,4.4866018 36.96875,4.5 Z M 9.875,22.0625 c -0.2851202,0.06083 -0.5453222,0.229783 -0.71875,0.5 C 9.1473,22.58404 9.13686,22.60492 9.125,22.625 l -4.40625,4.90625 c -0.00619,0.0096 0.00588,0.02152 0,0.03125 -0.3339753,0.552285 -0.1704409,1.243682 0.375,1.59375 0.021536,0.0089 0.04242,0.01939 0.0625,0.03125 0,0 0.496977,0.467173 0.53125,0.5 3.0185158,-1.352167 6.036186,-2.634284 9.0625,-3.84375 l -3.96875,-3.625 c -0.0098,-0.0063 -0.02139,0.006 -0.03125,0 -0.279841,-0.169766 -0.58988,-0.217075 -0.875,-0.15625 z"
id="path2960"
opacity="0.8"
fill="url(#7)"
stroke-width="1.061"
style="fill:url(#7)" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,16 +1,30 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields, ModelView, ModelSQL
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval
from trytond.pyson import Eval, And, Or, If, Bool
from trytond.transaction import Transaction
from trytond.rpc import RPC
from trytond.exceptions import UserError
from trytond.config import config
from trytond.report import Report
from facho.fe import form
from facho.fe import form, form_xml
from facho import fe
from facho.fe.client import dian
import io
from datetime import datetime
import qrcode
import zipfile
import hashlib
import tempfile
from contextlib import contextmanager
from datetime import datetime, date
from dateutil import tz
Bogota = tz.gettz("America/Bogota")
class Cron(metaclass=PoolMeta):
@ -22,233 +36,558 @@ class Cron(metaclass=PoolMeta):
cls.method.selection.extend([
('account.invoice|fe_delivery', 'FE Delivery')
])
class Party(metaclass=PoolMeta):
__name__ = 'party.party'
fe_identifiers = fields.One2Many('account_invoice_facho.party.fe_identifier',
'party', 'Fe Identifiers')
fe_organizations = fields.One2Many('account_invoice_facho.party.fe_organization',
'party', 'Fe Organizations')
fe_identifier = fields.Function(fields.Many2One('account_invoice_facho.party.fe_identifier',
'Fe Identifier'),
'get_fe_identifier')
fe_organization = fields.Function(fields.Many2One('account_invoice_facho.party.fe_organization',
'Fe Organization'),
'get_fe_organization')
def get_fe_identifier(self, name):
try:
return self.fe_identifiers[0]
except IndexError:
return None
def get_fe_organization(self, name):
try:
return self.fe_organizations[0]
except IndexError:
return None
def tofacho(self):
tax_identifier = self.tax_identifier
if tax_identifier is None:
tax_identifier = ''
return form.Party(
name = self.name,
ident = tax_identifier,
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),
'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})
fe_habilitacion = fields.Boolean('FE Habilitacion?',
states=_states,
depends=_depends)
# TODO adicionar atributo fe_identifier y permitir seleccion desde form
fe_delivery_state = fields.Selection([
('draft', 'draft'),
('draft', 'Draft'),
('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, depends=_depends)
], 'Delivery State', states=_states_readonly)
fe_delivery_trackid = fields.Char('Delivery TrackID',
states=_states_readonly,
depends=_depends)
fe_delivery_status = fields.Text('Delivery Status',
states=_states_readonly,
depends=_depends)
states=_states_readonly)
fe_delivery_status_description = fields.Char('Status Description',
states=_states_readonly)
fe_delivery_error_message = fields.Text('Error Message',
states=_states_readonly)
fe_delivery_checked_at = fields.DateTime('Delivery Checked At',
states=_states_readonly,
depends=_depends)
del _states, _states_readonly
del _depends
states=_states_readonly)
fe_cufe = fields.Char('Cufe',
states=_states_readonly)
fe_qrcode = fields.Char('QR Code',
states=_states_readonly)
fe_qrcode_img = fields.Function(fields.Binary('QR'),
'get_fe_qrcode_img')
fe_states = fields.Char('States',
states=_states_readonly)
fe_states_icon = fields.Function(fields.Char('Fe States'),
'get_fe_states_icon')
fe_xml_file = fields.Binary('Fe XML File',
states=_states_readonly)
fe_operation_type = fields.Selection(
[
('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',
states={
'readonly': (Eval('state') != 'draft')
},
depends=['state'])
fe_document_reference = fields.Many2One('account.invoice',
'Document Reference',
domain=[('type', '=', Eval('type'))],
states={
'invisible': (Bool(~Eval('credit_note')))
},
depends=['type', 'fe_delivery_state', 'credit_note'])
del _states_readonly
@classmethod
def __setup__(cls):
super(Invoice, cls).__setup__()
cls._buttons.update({
'xml': {
'readonly': Eval('state').in_(['posted', 'paid']),
'depends' : ['state'],},
'xml_signed': {
'readonly': Eval('state').in_(['posted', 'paid']),
'depends' : ['state'],},
'fe_send': {
'readonly': Or(Eval('fe_delivery_state').in_(['done']),
Eval('state').in_(['draft','validated'])),
'depends' : ['fe_delivery_state', 'state'],},
'fe_update_status': {
'readonly': Eval('fe_delivery_state').in_(['done']),
'depends' : ['fe_delivery_state'],},
'fe_email': {
'readonly': ~Eval('fe_delivery_state').in_(['done']),
'depends' : ['fe_delivery_state'],}
})
@classmethod
def trigger(cls, records, trigger):
"Action function for the triggers"
for record in records:
record.fe_delivery_state = 'queued'
record.save()
cls.fe_send(records)
@staticmethod
def default_fe_delivery_state():
return 'draft'
@staticmethod
def default_is_fe_colombia():
return Transaction().context.get('is_fe_colombia', False)
def default_fe_states():
return None
@staticmethod
def default_fe_operation_type():
return '10'
@fields.depends('fe_qrcode')
def get_fe_qrcode_img(self, name):
qr_data = io.BytesIO()
if self.fe_qrcode:
qrcode_img = qrcode.make(self.fe_qrcode)
else:
qrcode_img = qrcode.make(None)
with qr_data as img:
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'])
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':
icon = 'facho-send-fail'
elif self.fe_delivery_state == 'done' and self.fe_email_count(name) == 0:
icon = 'facho-mail-fail'
else:
icon = 'facho-mail-ok'
else:
icon = 'facho-not-posted'
return icon
@fields.depends('fe_operation_type', 'credit_note')
def on_change_credit_note(self):
config = Pool().get('account_invoice_facho.configuration')(1)
if not self.credit_note:
self.fe_operation_type = '10'
else:
if not config.dian_fe_debit_note:
self.fe_operation_type = '20'
else:
self.fe_operation_type = '30'
@fields.depends('fe_operation_type', 'credit_note')
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.fe_operation_type == '10':
xml = form_xml.DIANInvoiceXML(facho_invoice)
elif self.fe_operation_type == '20':
xml = form_xml.DIANCreditNoteXML(facho_invoice)
else:
xml = form_xml.DIANDebitNoteXML(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)
@classmethod
def check_modify(cls, invoices):
'''
Check if the invoices can be modified
'''
return False
@classmethod
def validate(cls, invoices):
super().validate(invoices)
for invoice in invoices:
for line in invoice.lines:
for taxes, unit_price, quantity in line.taxable_lines:
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')
facho_invoice = invoice.tofacho()
validator = form.DianResolucion0001Validator()
validator.validate(facho_invoice)
for (model, field, error) in validator.errors:
raise UserError('model %s in field %s has %s' % (model, field, error))
xml = form_xml.DIANInvoiceXML(facho_invoice)
def tofacho(self):
inv = form.Invoice()
inv.set_period(self.invoice_date, self.invoice_date)
inv.set_issue(self.invoice_date)
inv.set_ident(self.number)
inv.set_customer(self.party.tofacho())
inv.set_supplier(self.company.party.tofacho())
#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)
if self.fe_operation_type == '10':
inv = form.Invoice('01')
elif self.fe_operation_type == '20':
inv = form.CreditNote(reference)
else:
inv = form.DebitNote(reference)
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
inv.set_operation_type(self.fe_operation_type)
inv.set_supplier(form.Party(
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(
'', '', 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),
),
))
inv.set_customer(form.Party(
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(self.party.identifiers[0].type)
),
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(
'', '', 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),
),
))
inv.set_payment_mean(form.PaymentMean(
id = '1',
code = '10',
due_at = datetime.now(tz=Bogota),
payment_id = '1'
))
for line in self.lines:
inv.add_invoice_line(line.tofacho())
inv.calculate()
return inv
def do_dian_request(self, request, config=None):
def tax_level_code(self, tax_level):
tax_level_codes = ''
for codes in tax_level:
if len(tax_level_codes) == 0:
tax_level_codes = codes.code
else:
tax_level_codes += ';' + codes.code
return tax_level_codes
@contextmanager
def acquire_public_key(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 create_temporary_file(content):
f = tempfile.NamedTemporaryFile()
f.write(content)
f.flush()
return f
file_public_key = create_temporary_file(config.dian_fe_public_key)
file_private_key = create_temporary_file(config.dian_fe_private_key)
file_certs = create_temporary_file(config.dian_fe_cert)
passphrase = config.dian_fe_cert_passpharase
try:
yield {'file_public_key': file_public_key.name,
'file_private_key': file_private_key.name,
'file_certs': file_certs.name,
'passphrase': passphrase}
finally:
file_public_key.close()
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 fe_update_status(self):
config = Pool().get('account_invoice_facho.configuration')(1)
req = dian.GetStatusZip
if config.dian_fe_habilitacion:
req = dian.Habilitacion.GetStatusZip
resp = self.do_dian_request(req(trackId = self.fe_delivery_trackid))
params = {}
params['fe_delivery_status'] = resp.StatusDescription
if resp.IsValid:
params['fe_delivery_state'] = 'donde'
else:
params['fe_delivery_state'] = 'failure'
self._force_write(params)
def _force_write(self, params):
self.state = 'draft'
def _force_write(self, params, invoice):
params['fe_delivery_checked_at'] = datetime.now()
self.write([self], params)
def _dian_zip_io(self, facho_invoice):
xml_invoice = form.DIANInvoiceXML(facho_invoice)
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(facho_invoice.invoice_ident, str(xml_invoice))
dianzip.add_invoice_xml(filename, xml_invoice)
zipdata.seek(0)
return zipdata
def do_fe_delivery(self):
config = Pool().get('account_invoice_facho.configuration')(1)
if self.fe_delivery_state not in ['queued', 'draft']:
return
facho_invoice = self.tofacho()
req = dian.SendBillAsync
filename = 'invoice_%s' % (facho_invoice.invoice_ident)
args = [filename, self._dian_zip_io(facho_invoice).read()]
if config.dian_fe_habilitacion:
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)
extensions = self.fe_extensions(invoice, facho_invoice)
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_cufe = xml.get_element_text('./cbc:UUID')
with self.acquire_public_key(config) as ctx:
signer = fe.DianXMLExtensionSigner(ctx['file_certs'],
ctx['passphrase'],
localpolicy=True)
xml_signed = signer.sign_xml_string(str(xml))
req = dian.SendBillSync
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]
if config.dian_fe_habilitation:
req = dian.Habilitacion.SendTestSetAsync
args.append(config.dian_fe_test_setid)
res = self.do_dian_request(self, req(*args))
delivery_trackid = 'n/a'
delivery_state = 'exception'
res = self.do_dian_request(req(*args))
if not res.ZipKey:
raise UserError(str(res))
self._force_write({'fe_delivery_state': 'delivered',
'fe_delivery_trackid': res.ZipKey})
if config.dian_fe_habilitation:
if not res.ZipKey:
delivery_trackid = "[]"
status_description = "[]"
error_message = "[]"
fe_qrcode = None
delivery_state = "failure"
else:
delivery_state = 'delivered'
delivery_trackid = res.ZipKey
status_description = "[]"
error_message = "[]"
#if res.StatusCode == '00':
#delivery_state = 'done'
#else:
#delivery_state = 'failure'
else:
status_description = res.StatusDescription
error_message = res.ErrorMessage
if res.StatusCode == '00':
delivery_state = 'done'
else:
delivery_state = 'failure'
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
},
invoice)
def fe_process(self):
self.do_fe_delivery()
@classmethod
def fe_delivery(cls):
for inv in cls.search([('is_fe_colombia', '=', True),
('state', 'in', ['posted', 'paid'])]):
pool = Pool()
FACHO = pool.get('account_invoice_facho.dian_fe_company')
facho = FACHO(1)
habilitation = facho.dian_fe_habilitation
for inv in cls.search([('type', '=', 'out'),
('state', 'in', ['posted', 'paid']),
('subtype.sequence.invoice_resolution.valid_date_time_to',
'>=', date.today()),
('fe_delivery_state', '!=', 'done')]):
inv.fe_process()
if inv.fe_delivery_state in ['delivered', 'failure']:
if inv.fe_delivery_state in ['delivered', 'failure'] and habilitation:
inv.fe_update_status()
@fields.depends('credit_note')
def fe_extensions(self, inv):
pool = Pool()
FACHO = pool.get('account_invoice_facho.dian_fe_company')
facho = FACHO(1)
invoice_resolution = self.subtype.sequence.invoice_resolution
if facho.dian_fe_habilitation:
ambiente = fe.AMBIENTE_PRUEBAS
else:
ambiente = fe.AMBIENTE_PRODUCCION
if self.credit_note:
cufe = fe.DianXMLExtensionCUDE(inv,
facho.dian_fe_pin,
ambiente,)
else:
cufe = fe.DianXMLExtensionCUFE(inv,
invoice_resolution.technical_key,
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,
#)
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)
inv_authorization = fe.DianXMLExtensionInvoiceAuthorization(
str(invoice_resolution.resolution_number),
invoice_resolution.valid_date_time_from,
invoice_resolution.valid_date_time_to,
invoice_resolution.prefix,
invoice_resolution.from_number,
invoice_resolution.to_number)
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')
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):
pool = Pool()
FACHO = pool.get('account_invoice_facho.dian_fe_company')
facho = FACHO(1)
for invoice in invoices:
facho_invoice = invoice.tofacho()
extensions = cls.fe_extensions(invoice, facho_invoice)
xml = cls.type_code_xml(invoice, facho_invoice)
for extension in extensions:
xml.add_extension(extension)
xml_document = xml.tostring(xml_declaration=True, encoding='UTF-8').encode('utf-8')
with cls.acquire_public_key() as ctx:
signer = fe.DianXMLExtensionSigner(ctx['file_certs'],
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
invoice.save()
@classmethod
@ModelView.button
def fe_send(cls, invoices):
facho_invoice = invoices[0].tofacho()
cls.do_fe_delivery(cls, facho_invoice, invoices[0])
invoices[0].save()
@classmethod
@ModelView.button
def fe_update_status(self, invoices):
config = Pool().get('account_invoice_facho.configuration')(1)
req = dian.GetStatusZip
for invoice in invoices:
if invoice.fe_delivery_state != 'delivered':
raise UserError(str("La factura debe estar enviada"))
if config.dian_fe_habilitation:
req = dian.Habilitacion.GetStatusZip
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
if resp.IsValid:
params['fe_delivery_state'] = 'done'
else:
params['fe_delivery_state'] = 'failure'
self._force_write(self, params, invoice)
@classmethod
@ModelView.button
def fe_email(cls, invoices, from_=None):
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'])
trigger = notification_email.triggers[0]
trigger.notification_email.send_email(invoices, trigger)
class Product(metaclass=PoolMeta):
__name__ = 'product.product'
def tofacho(self):
return form.StandardItem(
description = self.name,
id = self.code
id_ = self.code
)
@ -257,19 +596,60 @@ class InvoiceLine(metaclass=PoolMeta):
def tofacho(self):
tax_subtotals = []
for taxes, unit_price, quantity in self.taxable_lines:
for tax in taxes:
tax_subtotals.append(form.TaxSubTotal(
percent = tax.rate
))
line_tax = form.TaxTotalOmit()
for taxes, unit_price, quantity, date_time in self.taxable_lines:
#for tax in taxes:
line_percent = taxes[0].rate * 100 if len(taxes) != 0 else 00.00
if len(taxes) != 0:
line_tax = form.TaxTotal(
subtotals = [
form.TaxSubTotal(
percent = abs(line_percent),
scheme=form.TaxScheme('01')
)
]
)
return form.InvoiceLine(
quantity = self.quantity,
quantity = form.Quantity(abs(self.quantity), '94'),
description = self.description,
# TODO debe ser decimal
price_amount = float(self.unit_price),
item = self.product.tofacho(),
tax = form.TaxTotal(
subtotals = tax_subtotals
)
price = form.Price(
amount = form.Amount(abs(self.unit_price)),
type_code = '01',
type = 'IVA'
),
tax = line_tax
)
class InvoiceReportDianZip(Report):
__name__ = 'account.invoice.dian.zip'
@classmethod
def __setup__(cls):
super(InvoiceReportDianZip, cls).__setup__()
cls.__rpc__['execute'] = RPC(False)
@classmethod
def execute(cls, records, data):
pool = Pool()
if len(records) > 1:
raise UserError(str("Imprimir solo uno"))
Invoice = pool.get('account.invoice')
invoice, = Invoice.browse(records)
invoice.invoice_report_cache = None
invoice.save()
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
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)

View File

@ -1,31 +1,101 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="ir.action.act_window" id="act_invoice_in_form">
<field name="name">Invoices Fe</field>
<field name="res_model">account.invoice</field>
<field name="domain" eval="[('is_fe_colombia', '=', True)]" pyson="1"/>
<field name="context" eval="{'is_fe_colombia': True}" pyson="1"/>
</record>
<record model="ir.ui.view" id="invoice_fe_colombia_in_form">
<field name="model">account.invoice</field>
<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"/>
</data>
<data>
<record model="ir.ui.view" id="invoice_fe_colombia_in_form">
<field name="model">account.invoice</field>
<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_colombia_in_tree">
<field name="model">account.invoice</field>
<field name="inherit" ref="account_invoice.invoice_view_tree"/>
<field name="name">invoice_fe_colombia_tree</field>
</record>
<record model="ir.action.report" id="email_invoice_fe">
<field name="name">Send Email Invoice</field>
<field name="model">account.invoice</field>
<field name="report_name">account.invoice.email_invoice_fe</field>
<field name="report">account_invoice_facho/email_invoice.html</field>
<field name="template_extension">html</field>
<field name="single" eval="True"/>
</record>
<record model="ir.action.report" id="report_invoice_fe">
<field name="name">Invoice Fe</field>
<field name="report_name">account.invoice.dian.zip</field>
<field name="model">account.invoice</field>
<field name="report">account_invoice_subtype/invoice.fodt</field>
<field name="single" eval="True"/>
</record>
<record model="ir.action.keyword" id="report_invoice_keyword">
<field name="keyword">form_print</field>
<field name="model">account.invoice,-1</field>
<field name="action" ref="report_invoice_fe"/>
</record>
<record model="ir.ui.icon" id="facho_mail_ok">
<field name="name">facho-mail-ok</field>
<field name="path">icons/facho-mail-ok.svg</field>
</record>
<record model="ir.ui.icon" id="facho_mail_fail">
<field name="name">facho-mail-fail</field>
<field name="path">icons/facho-mail-fail.svg</field>
</record>
<record model="ir.ui.icon" id="facho_send_fail">
<field name="name">facho-send-fail</field>
<field name="path">icons/facho-send-fail.svg</field>
</record>
<record model="ir.ui.icon" id="facho_not_posted">
<field name="name">facho-not-posted</field>
<field name="path">icons/facho-not-posted.svg</field>
</record>
<record model="ir.model.button" id="facho_xml_button">
<field name="name">xml</field>
<field name="string">XML</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
</record>
<record model="ir.model.button-res.group"
id="invoice_facho_button_group_account">
<field name="button" ref="facho_xml_button"/>
<field name="group" ref="account.group_account"/>
</record>
<record model="ir.model.button" id="facho_xml_signed_button">
<field name="name">xml_signed</field>
<field name="string">Xml Signed</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
</record>
<record model="ir.model.button-res.group"
id="invoice_facho_xml_signed_button_group_account">
<field name="button" ref="facho_xml_signed_button"/>
<field name="group" ref="account.group_account"/>
</record>
<record model="ir.model.button" id="facho_fe_update_status_button">
<field name="name">fe_update_status</field>
<field name="string">FE Status</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
</record>
<record model="ir.model.button-res.group"
id="invoice_facho_fe_update_status_button_group_account">
<field name="button" ref="facho_fe_update_status_button"/>
<field name="group" ref="account.group_account"/>
</record>
<record model="ir.model.button" id="facho_fe_send_button">
<field name="name">fe_send</field>
<field name="string">FE Send</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
</record>
<record model="ir.model.button-res.group"
id="invoice_facho_fe_send_button_group_account">
<field name="button" ref="facho_fe_send_button"/>
<field name="group" ref="account.group_account"/>
</record>
<record model="ir.model.button" id="facho_fe_email_button">
<field name="name">fe_email</field>
<field name="string">Fe Email</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
</record>
<record model="ir.model.button-res.group"
id="invoice_facho_fe_email_button_group_account">
<field name="button" ref="facho_fe_email_button"/>
<field name="group" ref="account.group_account"/>
</record>
</data>
</tryton>

57
ir.py Normal file
View File

@ -0,0 +1,57 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
from trytond.transaction import Transaction
class Trigger(metaclass=PoolMeta):
__name__ = 'ir.trigger'
@classmethod
def __setup__(cls):
super().__setup__()
cls.action.selection.append(
('account.invoice|trigger', "Account Invoice"),
)
@classmethod
def __register__(cls, module_name):
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(cls, module_name)
sql_table = cls.__table__()
super(Trigger, cls).__register__(module_name)
table_h = cls.__table_handler__(module_name)
# Migration from 3.4:
# change minimum_delay into timedelta minimum_time_delay
if table.column_exist('minimum_delay'):
cursor.execute(*sql_table.select(
sql_table.id, sql_table.minimum_delay,
where=sql_table.minimum_delay != Null))
for id_, delay in cursor.fetchall():
delay = datetime.timedelta(hours=delay)
cursor.execute(*sql_table.update(
[sql_table.minimum_time_delay],
[delay],
where=sql_table.id == id_))
table.drop_column('minimum_delay')
# Migration from 5.4: merge action
if (table_h.column_exist('action_model')
and table_h.column_exist('action_function')):
pool = Pool()
Model = pool.get('ir.model')
model = Model.__table__()
action_model = model.select(
model.model, where=model.id == sql_table.action_model)
cursor.execute(*sql_table.update(
[sql_table.action],
[Concat(action_model, Concat(
'|', sql_table.action_function))]))
table_h.drop_column('action_model')
table_h.drop_column('action_function')

20
ir.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="ir.trigger" id="posted_invoice_trigger">
<field name="name">When a customer invoice is posted</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
<field name="on_write" eval="True"/>
<field name="action">account.invoice|trigger</field>
<field name="condition" eval="And(Eval('self', {}).get('state', '') == 'posted', Eval('self', {}).get('type') == 'out')" pyson="1"/>
</record>
<record model="ir.trigger" id="fe_status_done_trigger">
<field name="name">When fe status is done</field>
<field name="model" search="[('model', '=', 'account.invoice')]"/>
<field name="on_write" eval="True"/>
<field name="action">notification.email|trigger</field>
<field name="condition" eval="And(Eval('self', {}).get('fe_delivery_state', '') == 'done', Eval('self', {}).get('type') == 'out')" pyson="1"/>
<field name="notification_email" ref="send_email_fe_invoice"/>
</record>
</data>
</tryton>

163
locale/es.po Normal file
View File

@ -0,0 +1,163 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:account.invoice,fe_delivery_trackid:"
msgid "Delivery TrackID"
msgstr "Pista del envío"
msgctxt "field:account.invoice,fe_delivery_state:"
msgid "Delivery State"
msgstr "Estado del envío"
msgctxt "field:account.invoice,fe_delivery_status_description:"
msgid "Status Description"
msgstr "Descripción del estado"
msgctxt "field:account.invoice,fe_delivery_error_message:"
msgid "Error Message"
msgstr "Mensaje de error"
msgctxt "field:account.invoice,fe_delivery_checked_at:"
msgid "Delivery Checked At"
msgstr "Hora del envío"
msgctxt "field:account.invoice,fe_qrcode:"
msgid "QR Code"
msgstr "Código QR"
msgctxt "field:account.invoice,fe_states:"
msgid "States"
msgstr "Estados"
msgctxt "field:account.invoice,fe_xml_file:"
msgid "Fe XML File"
msgstr "Archivo FE XML"
msgctxt "field:account.invoice,fe_operation_type:"
msgid "Operation Type"
msgstr "Tipo de Documento"
msgctxt "field:account.invoice,fe_document_reference:"
msgid "Document of Reference"
msgstr "Documento de Referencia"
msgctxt "field:account_invoice_facho.configuration,dian_fe_habilitation:"
msgid "Habilitation"
msgstr "Habilitación"
msgctxt "field:account_invoice_facho.configuration,dian_fe_debit_note:"
msgid "Debit Note"
msgstr "Nota Débito"
msgctxt "field:account_invoice_facho.configuration,dian_fe_public_key:"
msgid "Public Key"
msgstr "Llave Pública"
msgctxt "field:account_invoice_facho.configuration,dian_fe_private_key:"
msgid "Private Key"
msgstr "Llave Privada"
msgctxt "field:account_invoice_facho.configuration,dian_fe_test_setid:"
msgid "Testsetid Dian"
msgstr "Id Set pruebas Dian"
msgctxt "field:account_invoice_facho.configuration,dian_fe_cert:"
msgid "Cert"
msgstr "Certificado"
msgctxt "field:account_invoice_facho.configuration,dian_fe_cert_passpharase:"
msgid "Cert Passpharase"
msgstr "Clave de paso"
msgctxt "field:account_invoice_facho.configuration,dian_fe_technologic_supplier:"
msgid "Technologic Supplier"
msgstr "Proveedor Tecnológico"
msgctxt "field:account_invoice_facho.configuration,dian_fe_obliged_bill:"
msgid "Obliged to bill"
msgstr "Obligado a facturar"
msgctxt "field:account_invoice_facho.configuration,dian_fe_software_identification:"
msgid "Software Identification"
msgstr "Identificación de Software"
msgctxt "field:account_invoice_facho.configuration,dian_fe_invoice_resolution:"
msgid "Invoice Resolution"
msgstr "Resolución de Facturación"
msgctxt "model:ir.model.button,string:facho_xml_button"
msgid "Xml"
msgstr "Crear Xml"
msgctxt "model:ir.model.button,string:facho_xml_signed_button"
msgid "Xml Signed"
msgstr "Firmar Xml"
msgctxt "model:ir.model.button,string:facho_fe_update_status_button"
msgid "FE Status"
msgstr "Estado FE"
msgctxt "model:ir.model.button,string:facho_fe_send_button"
msgid "FE Send"
msgstr "Enviar FE"
msgctxt "model:ir.model.button,string:facho_fe_email_button"
msgid "fe_email"
msgstr "Correo FE"
msgctxt "model:ir.ui.menu,name:menu_configuration"
msgid "Configuration"
msgstr "Configuración"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Draft"
msgstr "Borrador"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Draft"
msgstr "Borrador"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Queued"
msgstr "En Cola"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Delivered"
msgstr "Enviado"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Exception"
msgstr "Excepción"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Failure"
msgstr "Fallido"
msgctxt "selection:account.invoice,fe_delivery_state:"
msgid "Done"
msgstr "Hecho"
msgctxt "model:ir.action,name:act_configuration_facho_form"
msgid "Configuration"
msgstr "Configuración"
msgctxt "model:ir.trigger,name:posted_invoice_trigger"
msgid "When a customer invoice is posted"
msgstr "Cuando la factura de cliente esté contabilizada"
msgctxt "model:ir.trigger,name:fe_status_done_trigger"
msgid "When fe status is done"
msgstr "Cuando el estado de FE esté en hecho"
msgctxt "model:ir.action,name:email_invoice_fe"
msgid "Send Email Invoice"
msgstr "Enviar Factura por correo"
msgctxt "model:ir.action,name:report_invoice_fe"
msgid "Invoice FE"
msgstr "Factura FE"
msgctxt "selection:ir.cron,method:"
msgid "FE Delivery"
msgstr "Envío de FE"

7
message.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data grouped="1">
</data>
</tryton>

11
notification.xml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="notification.email" id="send_email_fe_invoice">
<field name="content" search="[('report_name', '=', 'account.invoice.email_invoice_fe')]"/>
<field name="subject">${record.company.party.identifiers[0].code};${record.company.rec_name};${record.number};${record.fe_operation_type};${record.company.rec_name}</field>
<field name="recipients" search="[('model.model', '=', 'account.invoice'), ('name', '=', 'party')]"/>
</record>
</data>
</tryton>

View File

@ -68,7 +68,7 @@ setup(name=name,
package_data={
'trytond.modules.account_invoice_facho': (info.get('xml', [])
+ ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.fodt',
'icons/*.svg', 'tests/*.rst']),
'*.html', 'icons/*.svg', 'tests/*.rst']),
},
classifiers=[
'Development Status :: 5 - Production/Stable',

View File

@ -1,11 +1,15 @@
[tryton]
version=5.4.0
version=6.0.0
depends:
ir
company
account_invoice
account_invoice_subtype
notification_email
xml:
facho.xml
configuration.xml
invoice.xml
dian.xml
message.xml
notification.xml
ir.xml

View File

@ -1,21 +1,27 @@
<?xml version="1.0"?>
<form>
<label name="dian_fe_habilitacion"/>
<field name="dian_fe_habilitacion"/>
<label name="dian_fe_key"/>
<field name="dian_fe_key"/>
<label name="dian_fe_NITProveedorTecnologico"/>
<field name="dian_fe_NITProveedorTecnologico"/>
<label name="dian_fe_NITObligadoFacturarElectronicamente"/>
<field name="dian_fe_NITObligadoFacturarElectronicamente"/>
<label name="dian_fe_IdentificadorSoftware"/>
<field name="dian_fe_IdentificadorSoftware"/>
<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_habilitation"/>
<field name="dian_fe_habilitation"/>
<label name="dian_fe_debit_note"/>
<field name="dian_fe_debit_note"/>
<label name="dian_fe_technologic_supplier"/>
<field name="dian_fe_technologic_supplier"/>
<label name="dian_fe_obliged_bill"/>
<field name="dian_fe_obliged_bill"/>
<label name="dian_fe_software_identification"/>
<field name="dian_fe_software_identification"/>
<label name="dian_fe_public_key"/>
<field name="dian_fe_public_key"/>
<label name="dian_fe_private_key"/>
<field name="dian_fe_private_key"/>
<label name="dian_fe_cert"/>
<field name="dian_fe_cert"/>
<label name="dian_fe_test_setid"/>
<field name="dian_fe_test_setid"/>
<label name="dian_fe_llave_frasepaso"/>
<field name="dian_fe_llave_frasepaso"/>
<label name="dian_fe_cert_passpharase"/>
<field name="dian_fe_cert_passpharase"/>
<label name="dian_fe_pin"/>
<field name="dian_fe_pin"/>
<label name="dian_fe_invoice_resolution"/>
<field name="dian_fe_invoice_resolution"/>
</form>

View File

@ -1,8 +1,35 @@
<?xml version="1.0"?>
<data>
<xpath expr="/form/field[@name='reference']"
<xpath expr="/form/notebook/page[@id='payment']"
position="after">
<label name="fe_habilitacion"/>
<field name="fe_habilitacion"/>
<page string="FE Colombia" name="fe_colombia">
<label name="fe_delivery_state"/>
<field name="fe_delivery_state"/>
<label name="fe_delivery_status_description"/>
<field name="fe_delivery_status_description"/>
<newline/>
<label name="fe_delivery_error_message"/>
<field name="fe_delivery_error_message"/>
<newline/>
<label name="fe_delivery_trackid"/>
<field name="fe_delivery_trackid"/>
<label name="fe_delivery_checked_at"/>
<field name="fe_delivery_checked_at"/>
<label name="fe_qrcode"/>
<field name="fe_qrcode" widget="url"/>
<label name="fe_xml_file"/>
<field name="fe_xml_file"/>
<label name="fe_operation_type"/>
<field name="fe_operation_type"/>
<newline/>
<button name="xml" icon="tryton-ok"/>
<button name="xml_signed" icon="tryton-ok"/>
<button name="fe_send" icon="tryton-ok"/>
<button name="fe_update_status" icon="tryton-ok"/>
</page>
</xpath>
<xpath expr="//field[@name='credit_note']" position="after">
<label name="fe_document_reference"/>
<field name="fe_document_reference"/>
</xpath>
</data>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="//field[@name='description']" position="after">
<field name="fe_states" icon="fe_states_icon"/>
</xpath>
<xpath expr="//field[@name='description']" position="after">
<button name="fe_email"/>
</xpath>
<xpath expr="//field[@name='description']" position="after">
<button name="fe_send"/>
</xpath>
</data>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath
expr="/form/field[@name='report_text']" position="after">
<label name="technical_key"/>
<field name="technical_key"/>
</xpath>
</data>