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