idea
This commit is contained in:
parent
7b3d9e77a1
commit
f720cbdfe0
26 changed files with 1380 additions and 620 deletions
14
COPYRIGHT
Normal file
14
COPYRIGHT
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Copyright (C) 2020 ETRIVIAL
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
5
MANIFEST.in
Normal file
5
MANIFEST.in
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
include CHANGELOG
|
||||||
|
include COPYRIGHT
|
||||||
|
include LICENSE
|
||||||
|
include README.rst
|
||||||
|
include doc/*
|
|
@ -1,3 +0,0 @@
|
||||||
# account_invoice_facho
|
|
||||||
|
|
||||||
Modulo facturacion electronica Colombia - TrytonERP
|
|
1
README.rst
Symbolic link
1
README.rst
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
doc/index.rst
|
25
__init__.py
Normal file
25
__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from trytond.pool import Pool
|
||||||
|
from . import configuration
|
||||||
|
|
||||||
|
from . import invoice
|
||||||
|
from . import party
|
||||||
|
from . import facho
|
||||||
|
from . import dian
|
||||||
|
|
||||||
|
__all__ = ['register']
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
Pool.register(
|
||||||
|
configuration.Configuration,
|
||||||
|
configuration.ConfigurationDianFECompany,
|
||||||
|
facho.FEGenericCode,
|
||||||
|
invoice.Invoice,
|
||||||
|
party.Party,
|
||||||
|
dian.RangoFacturacion,
|
||||||
|
module='account_invoice_facho', type_='model')
|
||||||
|
Pool.register(
|
||||||
|
dian.SincronizarRangoFacturacion,
|
||||||
|
module='account_invoice_facho', type_='wizard')
|
||||||
|
Pool.register(
|
||||||
|
module='account_invoice_facho', type_='report')
|
41
configuration.py
Normal file
41
configuration.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
from trytond.pool import Pool
|
||||||
|
from trytond.model import ModelSQL, ModelView, ModelSingleton, fields
|
||||||
|
from trytond.modules.company.model import (
|
||||||
|
CompanyMultiValueMixin, CompanyValueMixin)
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration(
|
||||||
|
ModelSingleton, ModelSQL, ModelView, CompanyMultiValueMixin):
|
||||||
|
'Facho Configuration'
|
||||||
|
__name__ = 'account_invoice_facho.configuration'
|
||||||
|
|
||||||
|
dian_fe_key= fields.MultiValue(fields.Char('Dian FE KEY'))
|
||||||
|
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_certificado = fields.MultiValue(fields.Binary('Certificado PCKS#12'))
|
||||||
|
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'))
|
||||||
|
|
||||||
|
@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_numeracion_username = fields.Char('Username')
|
||||||
|
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_certificado = fields.Binary('Certificado PCKS#12')
|
||||||
|
dian_fe_NITProveedorTecnologico = fields.Char('NIT Proveedor Tecnologico')
|
||||||
|
dian_fe_NITObligadoFacturarElectronicamente = fields.Char('NIT Obligactior FE')
|
||||||
|
dian_fe_IdentificadorSoftware = fields.Char('IdentificadorSoftware')
|
25
configuration.xml
Normal file
25
configuration.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<tryton>
|
||||||
|
<data>
|
||||||
|
<record model="ir.action.act_window" id="act_configuration_form">
|
||||||
|
<field name="name">Configuration</field>
|
||||||
|
<field name="res_model">account_invoice_facho.configuration</field>
|
||||||
|
</record>
|
||||||
|
<menuitem parent="menu_facho"
|
||||||
|
action="act_configuration_form"
|
||||||
|
id="menu_configuration"
|
||||||
|
sequence="10"/>
|
||||||
|
<record model="ir.ui.view" id="configuration_view_form">
|
||||||
|
<field name="model">account_invoice_facho.configuration</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="name">configuration_form</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.action.act_window.view"
|
||||||
|
id="act_configuration_view1">
|
||||||
|
<field name="sequence" eval="1"/>
|
||||||
|
<field name="view" ref="configuration_view_form"/>
|
||||||
|
<field name="act_window" ref="act_configuration_form"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</tryton>
|
58
dian.py
Normal file
58
dian.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
from trytond.model import ModelSQL, ModelView, fields
|
||||||
|
from trytond.wizard import Wizard, StateTransition
|
||||||
|
from trytond.pool import Pool
|
||||||
|
|
||||||
|
|
||||||
|
class RangoFacturacion(ModelSQL, ModelView):
|
||||||
|
'Rango Facturacion'
|
||||||
|
__name__ = 'account_invoice_facho.dian_rango_facturacion'
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SincronizarRangoFacturacion(Wizard):
|
||||||
|
'Sincronizar Rango Facturacion'
|
||||||
|
__name__ = 'account_invoice_facho.sincronizar_rango_facturacion'
|
||||||
|
start = StateTransition()
|
||||||
|
|
||||||
|
# TODO aun no esta PROBADO!!!
|
||||||
|
def transition_start(self):
|
||||||
|
pool = Pool()
|
||||||
|
config = pool.get('account_invoice_facho.configuration')(1)
|
||||||
|
RangoFacturacion = pool.get('account_invoice_facho.dian_rango_facturacion')
|
||||||
|
|
||||||
|
from .exceptions import DianClientError
|
||||||
|
from facho.fe.client import dian
|
||||||
|
client = dian.DianClient(config.dian_fe_numeracion_username,
|
||||||
|
config.dian_fe_numeracion_password)
|
||||||
|
resp = client.request(
|
||||||
|
dian.GetNumberingRange(
|
||||||
|
config.dian_fe_NITObligadoFacturarElectronicamente,
|
||||||
|
config.dian_fe_NITProveedorTecnologico,
|
||||||
|
config.dian_fe_IdentificadorSoftware))
|
||||||
|
|
||||||
|
if resp.CodigoOperacion != 'OK':
|
||||||
|
raise DianClientError(resp.DescripcionOperacion)
|
||||||
|
|
||||||
|
to_insert = []
|
||||||
|
for rango_facturacion in resp.RangoFacturacion:
|
||||||
|
to_insert.append({
|
||||||
|
'NumeroResolucion': rango_facturacion.NumeroResolucion,
|
||||||
|
'FechaResolucion': rango_facturacion.FechaResolucion,
|
||||||
|
'Prefijo': rango_facturacion.Prefijo,
|
||||||
|
'RangoInicial': rango_facturacion.RangoInicial,
|
||||||
|
'RangoFinal': rango_facturacion.RangoFinal,
|
||||||
|
'FechaVigenciaDesde': rango_facturacion.FechaVigenciaDesde,
|
||||||
|
'FechaVigenciaHasta': rango_facturacion.FechaVigenciaHasta,
|
||||||
|
'ClaveTecnica': rango_facturacion.ClaveTecnica,
|
||||||
|
})
|
||||||
|
RangoFinal.create(to_insert)
|
||||||
|
return 'end'
|
28
dian.xml
Normal file
28
dian.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?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>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</data>
|
||||||
|
</tryton>
|
9
doc/index.rst
Normal file
9
doc/index.rst
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Account Invoice Facho Module
|
||||||
|
############################
|
||||||
|
|
||||||
|
Modulo para facturacion electronica colombia usando libreria facho.
|
||||||
|
|
||||||
|
Producto
|
||||||
|
########
|
||||||
|
|
||||||
|
Se asume que el codigo de producto sigue https://www.colombiacompra.gov.co/sites/cce_public/files/cce_documents/cce_guia_codificacion_bienes.pdf
|
4
exceptions.py
Normal file
4
exceptions.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from trytond.exceptions import UserError
|
||||||
|
|
||||||
|
class DianClientError(UserError):
|
||||||
|
pass
|
15
facho.py
Normal file
15
facho.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from trytond.model import fields, ModelSQL, ModelView
|
||||||
|
|
||||||
|
|
||||||
|
class FEGenericCode(ModelSQL, ModelView):
|
||||||
|
"FE GenericCode"
|
||||||
|
__name__ = 'account_invoice_facho.fe_generic_code'
|
||||||
|
|
||||||
|
resource = fields.Selection([
|
||||||
|
('tipo_responsabilidad', 'Tipo Responsabilidad'),
|
||||||
|
('tipo_organizacion', 'Tipo Organizacion')
|
||||||
|
], 'Resource')
|
||||||
|
name = fields.Char('Name')
|
||||||
|
code = fields.Char('Code')
|
||||||
|
|
||||||
|
|
6
facho.xml
Normal file
6
facho.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<tryton>
|
||||||
|
<data>
|
||||||
|
<menuitem name="Facho" id="menu_facho"/>
|
||||||
|
</data>
|
||||||
|
</tryton>
|
70
invoice.py
Normal file
70
invoice.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
from trytond.model import fields
|
||||||
|
from trytond.pool import PoolMeta
|
||||||
|
from trytond.pyson import Eval
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
from trytond.rpc import RPC
|
||||||
|
from trytond.exceptions import UserError
|
||||||
|
from facho.fe import form
|
||||||
|
|
||||||
|
class Invoice(metaclass=PoolMeta):
|
||||||
|
__name__ = 'account.invoice'
|
||||||
|
|
||||||
|
_states = {'invisible': ~Eval('is_fe_colombia', False),
|
||||||
|
'required': Eval('is_fe_colombia', False)}
|
||||||
|
_depends = ['is_fe_colombia']
|
||||||
|
|
||||||
|
is_fe_colombia = fields.Boolean('FE Colombia?',
|
||||||
|
states={'invisible': False})
|
||||||
|
del _states
|
||||||
|
del _depends
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_is_fe_colombia():
|
||||||
|
return Transaction().context.get('is_fe_colombia', False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate(cls, invoices):
|
||||||
|
super().validate(invoices)
|
||||||
|
|
||||||
|
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':
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
for line in self.lines:
|
||||||
|
tax_subtotals = []
|
||||||
|
for taxes, unit_price, quantity in line.taxable_lines:
|
||||||
|
for tax in taxes:
|
||||||
|
tax_subtotals.append(form.TaxSubTotal(
|
||||||
|
percent = tax.rate
|
||||||
|
))
|
||||||
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
|
quantity = line.quantity,
|
||||||
|
description = line.description,
|
||||||
|
price_amount = float(line.unit_price),
|
||||||
|
item_ident = line.product.code,
|
||||||
|
tax = form.TaxTotal(
|
||||||
|
subtotals = tax_subtotals
|
||||||
|
)
|
||||||
|
))
|
||||||
|
inv.calculate()
|
||||||
|
return inv
|
20
invoice.xml
Normal file
20
invoice.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?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>
|
||||||
|
<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>
|
||||||
|
</tryton>
|
24
party.py
Normal file
24
party.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from trytond.pool import PoolMeta
|
||||||
|
|
||||||
|
from facho.fe import form
|
||||||
|
|
||||||
|
class Party(metaclass=PoolMeta):
|
||||||
|
__name__ = 'party.party'
|
||||||
|
|
||||||
|
facho_tipo_responsabilidad = fields.Many2One('account_invoice_facho.fe_generic_code',
|
||||||
|
'Tipo Responsabilidad',
|
||||||
|
domain=[('resource', '=', 'tipo_responsabilidad')],
|
||||||
|
states=_states,
|
||||||
|
depends=_depends)
|
||||||
|
|
||||||
|
facho_tipo_organizacion = fields.Many2One('account_invoice_facho.fe_generic_code',
|
||||||
|
'Tipo Organizacion',
|
||||||
|
domain=[('resource', '=', 'tipo_organizacion')],
|
||||||
|
states=_states,
|
||||||
|
depends=_depends)
|
||||||
|
|
||||||
|
|
||||||
|
def tofacho(self):
|
||||||
|
return form.Party(
|
||||||
|
name = self.name
|
||||||
|
)
|
123
setup.py
Normal file
123
setup.py
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
MODULE2PREFIX = {}
|
||||||
|
|
||||||
|
|
||||||
|
def read(fname, slice=None):
|
||||||
|
content = io.open(
|
||||||
|
os.path.join(os.path.dirname(__file__), fname),
|
||||||
|
'r', encoding='utf-8').read()
|
||||||
|
if slice:
|
||||||
|
content = '\n'.join(content.splitlines()[slice])
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def get_require_version(name):
|
||||||
|
if minor_version % 2:
|
||||||
|
require = '%s >= %s.%s.dev0, < %s.%s'
|
||||||
|
else:
|
||||||
|
require = '%s >= %s.%s, < %s.%s'
|
||||||
|
require %= (name, major_version, minor_version,
|
||||||
|
major_version, minor_version + 1)
|
||||||
|
return require
|
||||||
|
|
||||||
|
|
||||||
|
config = ConfigParser()
|
||||||
|
config.read_file(open(os.path.join(os.path.dirname(__file__), 'tryton.cfg')))
|
||||||
|
info = dict(config.items('tryton'))
|
||||||
|
for key in ('depends', 'extras_depend', 'xml'):
|
||||||
|
if key in info:
|
||||||
|
info[key] = info[key].strip().splitlines()
|
||||||
|
version = info.get('version', '0.0.1')
|
||||||
|
major_version, minor_version, _ = version.split('.', 2)
|
||||||
|
major_version = int(major_version)
|
||||||
|
minor_version = int(minor_version)
|
||||||
|
name = 'etrivial_account_invoice_facho'
|
||||||
|
|
||||||
|
requires = []
|
||||||
|
for dep in info.get('depends', []):
|
||||||
|
if not re.match(r'(ir|res)(\W|$)', dep):
|
||||||
|
prefix = MODULE2PREFIX.get(dep, 'trytond')
|
||||||
|
requires.append(get_require_version('%s_%s' % (prefix, dep)))
|
||||||
|
requires.append(get_require_version('trytond'))
|
||||||
|
|
||||||
|
tests_require = []
|
||||||
|
dependency_links = []
|
||||||
|
if minor_version % 2:
|
||||||
|
dependency_links.append('https://trydevpi.tryton.org/?mirror=bitbucket')
|
||||||
|
|
||||||
|
setup(name=name,
|
||||||
|
version=version,
|
||||||
|
description='facturacion electronica colombia',
|
||||||
|
long_description=read('README.rst'),
|
||||||
|
author='Jovany Leandro G.C',
|
||||||
|
author_email='bit4bit@riseup.net',
|
||||||
|
url='http://www.etrivial.net',
|
||||||
|
keywords='tryton erp',
|
||||||
|
package_dir={'trytond.modules.account_invoice_facho': '.'},
|
||||||
|
packages=(
|
||||||
|
['trytond.modules.account_invoice_facho']
|
||||||
|
+ ['trytond.modules.account_invoice_facho.%s' % p
|
||||||
|
for p in find_packages()]
|
||||||
|
),
|
||||||
|
package_data={
|
||||||
|
'trytond.modules.account_invoice_facho': (info.get('xml', [])
|
||||||
|
+ ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.fodt',
|
||||||
|
'icons/*.svg', 'tests/*.rst']),
|
||||||
|
},
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
'Environment :: Plugins',
|
||||||
|
'Framework :: Tryton',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Financial and Insurance Industry',
|
||||||
|
'Intended Audience :: Legal Industry',
|
||||||
|
'License :: OSI Approved :: '
|
||||||
|
'GNU General Public License v3 or later (GPLv3+)',
|
||||||
|
'Natural Language :: Bulgarian',
|
||||||
|
'Natural Language :: Catalan',
|
||||||
|
'Natural Language :: Chinese (Simplified)',
|
||||||
|
'Natural Language :: Czech',
|
||||||
|
'Natural Language :: Dutch',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Natural Language :: Finnish',
|
||||||
|
'Natural Language :: French',
|
||||||
|
'Natural Language :: German',
|
||||||
|
'Natural Language :: Hungarian',
|
||||||
|
'Natural Language :: Indonesian',
|
||||||
|
'Natural Language :: Italian',
|
||||||
|
'Natural Language :: Persian',
|
||||||
|
'Natural Language :: Polish',
|
||||||
|
'Natural Language :: Portuguese (Brazilian)',
|
||||||
|
'Natural Language :: Russian',
|
||||||
|
'Natural Language :: Slovenian',
|
||||||
|
'Natural Language :: Spanish',
|
||||||
|
'Natural Language :: Turkish',
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
|
'Programming Language :: Python :: Implementation :: PyPy',
|
||||||
|
'Topic :: Office/Business',
|
||||||
|
],
|
||||||
|
license='GPL-3',
|
||||||
|
python_requires='>=3.5',
|
||||||
|
install_requires=requires,
|
||||||
|
dependency_links=dependency_links,
|
||||||
|
zip_safe=False,
|
||||||
|
entry_points="""
|
||||||
|
[trytond.modules]
|
||||||
|
account_invoice_facho = trytond.modules.account_invoice_facho
|
||||||
|
""", # noqa: E501
|
||||||
|
test_suite='tests',
|
||||||
|
test_loader='trytond.test_loader:Loader',
|
||||||
|
tests_require=tests_require,
|
||||||
|
)
|
6
tests/__init__.py
Normal file
6
tests/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
try:
|
||||||
|
from trytond.modules.account_invoice_facho.tests.test_account_invoice_facho import suite # noqa: E501
|
||||||
|
except ImportError:
|
||||||
|
from .test_account_invoice_facho import suite
|
||||||
|
|
||||||
|
__all__ = ['suite']
|
132
tests/scenario_account_invoice_facho.rst
Normal file
132
tests/scenario_account_invoice_facho.rst
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
==============================
|
||||||
|
Account Invoice Facho Scenario
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Imports::
|
||||||
|
>>> from decimal import Decimal
|
||||||
|
>>> from proteus import Model, Wizard
|
||||||
|
>>> from trytond.tests.tools import activate_modules
|
||||||
|
>>> from trytond.modules.company.tests.tools import create_company, \
|
||||||
|
... get_company
|
||||||
|
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
|
||||||
|
... create_chart, get_accounts, create_tax
|
||||||
|
>>> from trytond.modules.account_invoice.tests.tools import \
|
||||||
|
... set_fiscalyear_invoice_sequences, create_payment_term
|
||||||
|
|
||||||
|
Install account_invoice_facho::
|
||||||
|
|
||||||
|
>>> config = activate_modules('account_invoice_facho')
|
||||||
|
|
||||||
|
Create company::
|
||||||
|
|
||||||
|
>>> _ = create_company()
|
||||||
|
>>> company = get_company()
|
||||||
|
|
||||||
|
Create fiscal year::
|
||||||
|
|
||||||
|
>>> fiscalyear = create_fiscalyear(company)
|
||||||
|
|
||||||
|
Create chart of accounts::
|
||||||
|
|
||||||
|
>>> _ = create_chart(company)
|
||||||
|
>>> accounts = get_accounts(company)
|
||||||
|
>>> revenue = accounts['revenue']
|
||||||
|
>>> expense = accounts['expense']
|
||||||
|
>>> cash = accounts['cash']
|
||||||
|
|
||||||
|
>>> Journal = Model.get('account.journal')
|
||||||
|
>>> PaymentMethod = Model.get('account.invoice.payment.method')
|
||||||
|
>>> cash_journal, = Journal.find([('type', '=', 'cash')])
|
||||||
|
>>> cash_journal.save()
|
||||||
|
>>> payment_method = PaymentMethod()
|
||||||
|
>>> payment_method.name = 'Cash'
|
||||||
|
>>> payment_method.journal = cash_journal
|
||||||
|
>>> payment_method.credit_account = cash
|
||||||
|
>>> payment_method.debit_account = cash
|
||||||
|
>>> payment_method.save()
|
||||||
|
|
||||||
|
Create tax::
|
||||||
|
|
||||||
|
>>> tax = create_tax(Decimal('.10'))
|
||||||
|
>>> tax.save()
|
||||||
|
|
||||||
|
Create account category::
|
||||||
|
|
||||||
|
>>> ProductCategory = Model.get('product.category')
|
||||||
|
>>> account_category = ProductCategory(name="Account Category")
|
||||||
|
>>> account_category.accounting = True
|
||||||
|
>>> account_category.account_expense = expense
|
||||||
|
>>> account_category.account_revenue = revenue
|
||||||
|
>>> account_category.customer_taxes.append(tax)
|
||||||
|
>>> account_category.save()
|
||||||
|
|
||||||
|
|
||||||
|
Create parties::
|
||||||
|
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> supplier = Party(name='Supplier')
|
||||||
|
>>> supplier.save()
|
||||||
|
>>> customer = Party(name='Customer')
|
||||||
|
>>> customer.save()
|
||||||
|
|
||||||
|
Create payment term::
|
||||||
|
|
||||||
|
>>> payment_term = create_payment_term()
|
||||||
|
>>> payment_term.save()
|
||||||
|
|
||||||
|
Create product::
|
||||||
|
|
||||||
|
>>> ProductUom = Model.get('product.uom')
|
||||||
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||||
|
>>> ProductTemplate = Model.get('product.template')
|
||||||
|
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'product'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.type = 'goods'
|
||||||
|
>>> template.list_price = Decimal('10')
|
||||||
|
>>> template.account_category = account_category
|
||||||
|
>>> template.save()
|
||||||
|
>>> product, = template.products
|
||||||
|
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'service'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.type = 'service'
|
||||||
|
>>> template.list_price = Decimal('30')
|
||||||
|
>>> template.account_category = account_category
|
||||||
|
>>> template.save()
|
||||||
|
>>> service, = template.products
|
||||||
|
|
||||||
|
Create responsabilidades::
|
||||||
|
|
||||||
|
>>> GenericCode = Model.get('account_invoice_facho.fe_generic_code')
|
||||||
|
>>> tipo_responsabilidad = GenericCode()
|
||||||
|
>>> tipo_responsabilidad.resource = 'tipo_responsabilidad'
|
||||||
|
>>> tipo_responsabilidad.code = 'AA'
|
||||||
|
>>> tipo_responsabilidad.name = 'Aa'
|
||||||
|
>>> tipo_responsabilidad.save()
|
||||||
|
>>> tipo_organizacion = GenericCode()
|
||||||
|
>>> tipo_organizacion.resource = 'tipo_organizacion'
|
||||||
|
>>> tipo_organizacion.code = 'OO'
|
||||||
|
>>> tipo_organizacion.name = 'Oo'
|
||||||
|
>>> tipo_organizacion.save()
|
||||||
|
|
||||||
|
Create invoice::
|
||||||
|
|
||||||
|
>>> Invoice = Model.get('account.invoice')
|
||||||
|
>>> InvoiceLine = Model.get('account.invoice.line')
|
||||||
|
>>> invoice = Invoice()
|
||||||
|
>>> invoice.is_fe_colombia = True
|
||||||
|
>>> invoice.tipo_organizacion = tipo_organizacion
|
||||||
|
>>> invoice.tipo_responsabilidad = tipo_responsabilidad
|
||||||
|
>>> invoice.party = customer
|
||||||
|
>>> invoice.payment_term = payment_term
|
||||||
|
>>> line = InvoiceLine()
|
||||||
|
>>> invoice.lines.append(line)
|
||||||
|
>>> line.product = product
|
||||||
|
>>> line.quantity = 5
|
||||||
|
>>> line.unit_price = Decimal('40')
|
||||||
|
>>> invoice.untaxed_amount
|
||||||
|
Decimal('200.00')
|
||||||
|
>>> invoice.save()
|
19
tests/scenario_configuration.rst
Normal file
19
tests/scenario_configuration.rst
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
==============================
|
||||||
|
Account Invoice Facho Scenario
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Imports::
|
||||||
|
|
||||||
|
>>> from proteus import Model, Wizard
|
||||||
|
>>> from trytond.tests.tools import activate_modules
|
||||||
|
>>> from trytond.modules.company.tests.tools import create_company, \
|
||||||
|
... get_company
|
||||||
|
|
||||||
|
Install account_invoice_facho::
|
||||||
|
|
||||||
|
>>> config = activate_modules('account_invoice_facho')
|
||||||
|
|
||||||
|
Create company::
|
||||||
|
|
||||||
|
>>> _ = create_company()
|
||||||
|
>>> company = get_company()
|
33
tests/test_account_invoice_facho.py
Normal file
33
tests/test_account_invoice_facho.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import doctest
|
||||||
|
|
||||||
|
from trytond.tests.test_tryton import ModuleTestCase
|
||||||
|
from trytond.tests.test_tryton import suite as test_suite
|
||||||
|
from trytond.tests.test_tryton import doctest_teardown
|
||||||
|
from trytond.tests.test_tryton import doctest_checker
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
from trytond.pool import Pool
|
||||||
|
from trytond.modules.company.tests import create_company, set_company
|
||||||
|
from trytond.modules.account.tests import create_chart
|
||||||
|
|
||||||
|
class AccountInvoiceFachoTestCase(ModuleTestCase):
|
||||||
|
'Test Account Invoice Facho module'
|
||||||
|
module = 'account_invoice_facho'
|
||||||
|
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
suite = test_suite()
|
||||||
|
#suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
|
||||||
|
# AccountInvoiceFachoTestCase))
|
||||||
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_account_invoice_facho.rst',
|
||||||
|
tearDown=doctest_teardown, encoding='utf-8',
|
||||||
|
checker=doctest_checker,
|
||||||
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
suite.addTests(doctest.DocFileSuite(
|
||||||
|
'scenario_configuration.rst',
|
||||||
|
tearDown=doctest_teardown, encoding='utf-8',
|
||||||
|
checker=doctest_checker,
|
||||||
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
|
return suite
|
15
tox.ini
Normal file
15
tox.ini
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[tox]
|
||||||
|
envlist = {py35,py36,py37,py38}-{sqlite,postgresql},pypy3-{sqlite,postgresql}
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
commands = {envpython} setup.py test
|
||||||
|
deps =
|
||||||
|
{py35,py36,py37,py38}-postgresql: psycopg2 >= 2.5
|
||||||
|
pypy3-postgresql: psycopg2cffi >= 2.5
|
||||||
|
{py35,py36}-sqlite: sqlitebck
|
||||||
|
setenv =
|
||||||
|
sqlite: TRYTOND_DATABASE_URI={env:SQLITE_URI:sqlite://}
|
||||||
|
postgresql: TRYTOND_DATABASE_URI={env:POSTGRESQL_URI:postgresql://}
|
||||||
|
sqlite: DB_NAME={env:SQLITE_NAME::memory:}
|
||||||
|
postgresql: DB_NAME={env:POSTGRESQL_NAME:test}
|
||||||
|
install_command = pip install --pre --find-links https://trydevpi.tryton.org/?mirror=bitbucket {opts} {packages}
|
11
tryton.cfg
Normal file
11
tryton.cfg
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[tryton]
|
||||||
|
version=5.4.0
|
||||||
|
depends:
|
||||||
|
ir
|
||||||
|
company
|
||||||
|
account_invoice
|
||||||
|
xml:
|
||||||
|
facho.xml
|
||||||
|
configuration.xml
|
||||||
|
invoice.xml
|
||||||
|
dian.xml
|
20
view/configuration_form.xml
Normal file
20
view/configuration_form.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<form>
|
||||||
|
<label name="dian_fe_key"/>
|
||||||
|
<field name="dian_fe_key"/>
|
||||||
|
|
||||||
|
<label name="dian_fe_numeracion_username"/>
|
||||||
|
<field name="dian_fe_numeracion_username"/>
|
||||||
|
<label name="dian_fe_numeracion_password"/>
|
||||||
|
<field name="dian_fe_numeracion_password"/>
|
||||||
|
<label name="dian_fe_numeracion_key"/>
|
||||||
|
<field name="dian_fe_numeracion_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_certificado"/>
|
||||||
|
<field name="dian_fe_certificado"/>
|
||||||
|
</form>
|
10
view/invoice_fe_colombia_form.xml
Normal file
10
view/invoice_fe_colombia_form.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<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"/>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
Loading…
Reference in a new issue