Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b7553fa7d | ||
|
|
b9379390fb | ||
|
|
c80b4ce21b | ||
|
|
c7bacddd2d | ||
|
|
c7595022c4 | ||
|
|
8dee4b753c | ||
|
|
6f1f2519fe | ||
|
|
39505fff95 | ||
|
|
7b3edd3e51 | ||
|
|
c68efb499b | ||
|
|
7e62a9d430 | ||
|
|
62849f7945 |
+78
@@ -0,0 +1,78 @@
|
|||||||
|
clone:
|
||||||
|
hg:
|
||||||
|
image: plugins/hg
|
||||||
|
environment:
|
||||||
|
- HG_SHARE_POOL=/root/.cache/hg
|
||||||
|
volumes:
|
||||||
|
- cache:/root/.cache
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
tox:
|
||||||
|
image: ${IMAGE}
|
||||||
|
environment:
|
||||||
|
- CFLAGS=-O0
|
||||||
|
- DB_CACHE=/cache
|
||||||
|
- TOX_TESTENV_PASSENV=CFLAGS DB_CACHE CI_BUILD_NUMBER CI_JOB_NUMBER CI_JOB_ID
|
||||||
|
- POSTGRESQL_URI=postgresql://postgres@postgresql:5432/
|
||||||
|
commands:
|
||||||
|
- echo "[extensions]" >> /root/.hgrc
|
||||||
|
- echo "hgext.share =" >> /root/.hgrc
|
||||||
|
- echo "[share]" >> /root/.hgrc
|
||||||
|
- echo "pool = /root/.cache/hg" >> /root/.hgrc
|
||||||
|
- pip install tox
|
||||||
|
- tox -e "${TOXENV}-${DATABASE}"
|
||||||
|
volumes:
|
||||||
|
- cache:/root/.cache
|
||||||
|
check_dist:
|
||||||
|
image: ${IMAGE}
|
||||||
|
commands:
|
||||||
|
- pip install twine
|
||||||
|
- python setup.py sdist
|
||||||
|
- twine check dist/*
|
||||||
|
volumes:
|
||||||
|
- cache:/root/.cache
|
||||||
|
check_doc:
|
||||||
|
image: ${IMAGE}
|
||||||
|
commands:
|
||||||
|
- pip install sphinx
|
||||||
|
- python -m sphinx -T -E -W -n -b html doc _build/html
|
||||||
|
- python -m sphinx -T -E -W -n -b linkcheck doc _build
|
||||||
|
volumes:
|
||||||
|
- cache:/root/.cache
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: postgres
|
||||||
|
environment:
|
||||||
|
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||||
|
command: "-c fsync=off -c synchronous_commit=off -c full_page_writes=off"
|
||||||
|
when:
|
||||||
|
matrix:
|
||||||
|
DATABASE: postgresql
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- IMAGE: python:3.7
|
||||||
|
TOXENV: py37
|
||||||
|
DATABASE: sqlite
|
||||||
|
- IMAGE: python:3.7
|
||||||
|
TOXENV: py37
|
||||||
|
DATABASE: postgresql
|
||||||
|
- IMAGE: python:3.8
|
||||||
|
TOXENV: py38
|
||||||
|
DATABASE: sqlite
|
||||||
|
- IMAGE: python:3.8
|
||||||
|
TOXENV: py38
|
||||||
|
DATABASE: postgresql
|
||||||
|
- IMAGE: python:3.9
|
||||||
|
TOXENV: py39
|
||||||
|
DATABASE: sqlite
|
||||||
|
- IMAGE: python:3.9
|
||||||
|
TOXENV: py39
|
||||||
|
DATABASE: postgresql
|
||||||
|
- IMAGE: python:3.10
|
||||||
|
TOXENV: py310
|
||||||
|
DATABASE: sqlite
|
||||||
|
- IMAGE: python:3.10
|
||||||
|
TOXENV: py310
|
||||||
|
DATABASE: postgresql
|
||||||
@@ -2,7 +2,7 @@ name: Publicar paquete PyPI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["8.0"]
|
branches: ["7.0"]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
git init .
|
git init .
|
||||||
git remote add origin http://unpaismejor-gitea-app:3000/tryton-do/ncf_manager.git
|
git remote add origin http://unpaismejor-gitea-app:3000/tryton-do/ncf_manager.git
|
||||||
git -c http.extraHeader="Authorization: token $GITEA_TOKEN" \
|
git -c http.extraHeader="Authorization: token $GITEA_TOKEN" \
|
||||||
fetch --depth=1 origin 8.0
|
fetch --depth=1 origin 7.0
|
||||||
git checkout --detach FETCH_HEAD
|
git checkout --detach FETCH_HEAD
|
||||||
|
|
||||||
- name: Verificar Python
|
- name: Verificar Python
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python3 -m venv .ci-venv
|
python3 -m venv .ci-venv
|
||||||
.ci-venv/bin/python -m pip install --upgrade \
|
.ci-venv/bin/python -m pip install --upgrade \
|
||||||
"build>=1,<2" "twine>=6,<7"
|
"setuptools>=68,<81" "wheel>=0.41,<1" "twine>=6,<7"
|
||||||
|
|
||||||
- name: Comprobar credenciales
|
- name: Comprobar credenciales
|
||||||
env:
|
env:
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Fijar versión CI
|
- name: Fijar versión CI
|
||||||
env:
|
env:
|
||||||
PACKAGE_VERSION: 8.0.${{ gitea.run_number }}
|
PACKAGE_VERSION: 7.0.${{ gitea.run_number }}
|
||||||
run: |
|
run: |
|
||||||
.ci-venv/bin/python - <<'PY'
|
.ci-venv/bin/python - <<'PY'
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -53,9 +53,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Construir y validar
|
- name: Construir y validar
|
||||||
run: |
|
run: |
|
||||||
.ci-venv/bin/python -m build
|
.ci-venv/bin/python setup.py sdist bdist_wheel
|
||||||
.ci-venv/bin/python -m twine check dist/*
|
.ci-venv/bin/python -m twine check dist/*
|
||||||
.ci-venv/bin/python tools/check_wheel.py
|
|
||||||
|
|
||||||
- name: Publicar en Gitea PyPI
|
- name: Publicar en Gitea PyPI
|
||||||
env:
|
env:
|
||||||
|
|||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
/.coverage
|
|
||||||
/.eggs/
|
|
||||||
/.pytest_cache/
|
|
||||||
/.tox/
|
|
||||||
/build/
|
|
||||||
/dist/
|
|
||||||
/*.egg-info/
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
.DS_Store
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Version 7.0.3 - 2026-08-30
|
||||||
|
==========================
|
||||||
|
|
||||||
|
* Homologación funcional con la serie 8.0 manteniendo el registro y el
|
||||||
|
empaquetado propios de Tryton 7.0.
|
||||||
|
* Flujo protegido de autorizaciones y rangos NCF, importador DGII idempotente,
|
||||||
|
auditoría de activación y cierre, y restricciones por usuario.
|
||||||
|
* Validaciones de prefijo, rango, solapamiento por dirección, numeración,
|
||||||
|
notas de crédito/débito y cancelación fiscal.
|
||||||
|
* Corrección de búsquedas de montos por tipo de producto y compatibilidad con
|
||||||
|
nombres Unicode de secuencias electrónicas.
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2022-2026 Fundación Un País Mejor
|
Copyright (C) 2022 SOLUTEMA SRL
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
include CHANGELOG
|
||||||
|
include COPYRIGHT
|
||||||
|
include LICENSE
|
||||||
|
include README.rst
|
||||||
|
graft doc
|
||||||
-78
@@ -1,78 +0,0 @@
|
|||||||
NCF Manager Module
|
|
||||||
##################
|
|
||||||
|
|
||||||
The ncf_manager module manages Dominican Republic fiscal receipt numbers
|
|
||||||
for Tryton invoices.
|
|
||||||
|
|
||||||
It provides NCF/e-CF types, fiscal sequence management, invoice fiscal fields,
|
|
||||||
NCF assignment on posting, and fiscal preparation for debit and credit notes.
|
|
||||||
|
|
||||||
Installing
|
|
||||||
**********
|
|
||||||
|
|
||||||
Install the package and activate the module in the database::
|
|
||||||
|
|
||||||
pip install unpaismejor_ncf_manager
|
|
||||||
trytond-admin -d <database> -u ncf_manager
|
|
||||||
|
|
||||||
Publishing
|
|
||||||
**********
|
|
||||||
|
|
||||||
The included Gitea Actions workflow builds and publishes the package to the
|
|
||||||
Gitea PyPI registry from version-series branches such as ``8.0``.
|
|
||||||
|
|
||||||
Configure this repository secret:
|
|
||||||
|
|
||||||
* ``REGISTRY_PASSWORD``
|
|
||||||
|
|
||||||
The module assigns fiscal numbers transactionally from ``ir.sequence.strict``.
|
|
||||||
It does not sign or transmit e-CF documents; transmission remains the explicit
|
|
||||||
responsibility of an electronic invoicing connector.
|
|
||||||
|
|
||||||
Version compatibility
|
|
||||||
*********************
|
|
||||||
|
|
||||||
The 7.0 and 8.0 series share the same fiscal models, workflows, importer,
|
|
||||||
validations and tests. Only the module registration, packaging metadata and
|
|
||||||
report XML required by each Tryton series remain version-specific.
|
|
||||||
|
|
||||||
Authorization workflow
|
|
||||||
**********************
|
|
||||||
|
|
||||||
NCF authorizations follow the protected workflow ``Draft → Active →
|
|
||||||
Finished``. Create the authorization and its fiscal lines in draft, then use
|
|
||||||
the **Activate** button. A line can select an existing strict sequence or ask
|
|
||||||
the module to create one on activation from its authorized range. Activation
|
|
||||||
checks company, fiscal type, prefix, padding, validity, availability and range
|
|
||||||
overlap. Incoming supplier documents and outgoing customer documents use
|
|
||||||
independent numbering authorities, so overlap is enforced only within the
|
|
||||||
same document direction. The last issued number automatically finishes the
|
|
||||||
line. Finishing an authorization closes every remaining active line without
|
|
||||||
reusing numbers.
|
|
||||||
|
|
||||||
Legacy migration lines keep their original technical sequence immutable after
|
|
||||||
activation. Prefix selection is enforced while a line is in draft and fiscal
|
|
||||||
activation performs the same server-side validation; closing a protected
|
|
||||||
historical line therefore does not invalidate already-linked invoices.
|
|
||||||
|
|
||||||
Electronic fiscal numbers are only reserved by this module. Activating an
|
|
||||||
E-series authorization never signs or transmits an e-CF to DGII.
|
|
||||||
|
|
||||||
Importing DGII authorizations
|
|
||||||
*****************************
|
|
||||||
|
|
||||||
Use **NCF Manager → Import DGII Authorization** to load an authorization
|
|
||||||
downloaded from the DGII Virtual Office. XML, CSV and the HTML table exported
|
|
||||||
with an ``.xls`` extension are supported and detected from their content.
|
|
||||||
The importer creates an independent workflow record for every ``NUM_AUTOR``.
|
|
||||||
The same ``NUM_SOL`` may therefore appear in several records without modifying
|
|
||||||
an authorization that is already active; file names are not used as fiscal
|
|
||||||
identifiers. It validates
|
|
||||||
approval status, company name, NCF type, prefix, range and approved quantity,
|
|
||||||
and stores the original file, SHA-256, user and import date for audit.
|
|
||||||
|
|
||||||
Imports are idempotent. Reimporting an equivalent CSV, XML or XLS record does
|
|
||||||
not create another line, while different fiscal data for an existing
|
|
||||||
authorization is rejected. The safe default leaves the result in draft so
|
|
||||||
the first number can be reviewed. Immediate activation is explicit and still
|
|
||||||
does not transmit electronic documents.
|
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
doc/index.rst
|
||||||
+21
-9
@@ -1,3 +1,4 @@
|
|||||||
|
from trytond.pool import Pool
|
||||||
from . import invoice
|
from . import invoice
|
||||||
from . import importer
|
from . import importer
|
||||||
from . import ncf_manager
|
from . import ncf_manager
|
||||||
@@ -6,12 +7,23 @@ from . import configuration
|
|||||||
from . import party
|
from . import party
|
||||||
from . import user
|
from . import user
|
||||||
|
|
||||||
__all__ = [
|
def register():
|
||||||
'configuration',
|
Pool.register(
|
||||||
'invoice',
|
invoice.Invoice,
|
||||||
'importer',
|
ncf_manager.NCFManager,
|
||||||
'ncf_manager',
|
ncf_manager.NCFManagerSequences,
|
||||||
'party',
|
sequence.Sequence,
|
||||||
'sequence',
|
sequence.SequenceStrict,
|
||||||
'user',
|
configuration.Configuration,
|
||||||
]
|
configuration.DefaultNcfType,
|
||||||
|
party.PartyNcfType,
|
||||||
|
party.Party,
|
||||||
|
user.User,
|
||||||
|
importer.ImportNCFStart,
|
||||||
|
module='ncf_manager', type_='model')
|
||||||
|
Pool.register(
|
||||||
|
importer.ImportNCF,
|
||||||
|
module='ncf_manager', type_='wizard')
|
||||||
|
Pool.register(
|
||||||
|
invoice.InvoiceReport,
|
||||||
|
module='ncf_manager', type_='report')
|
||||||
|
|||||||
+55
-4
@@ -12,16 +12,67 @@ Installing
|
|||||||
|
|
||||||
Install the package and activate the module in the database::
|
Install the package and activate the module in the database::
|
||||||
|
|
||||||
pip install trytond_ncf_manager
|
pip install unpaismejor_ncf_manager
|
||||||
trytond-admin -d <database> -u ncf_manager
|
trytond-admin -d <database> -u ncf_manager
|
||||||
|
|
||||||
Publishing
|
Publishing
|
||||||
**********
|
**********
|
||||||
|
|
||||||
The included Gitea Actions workflow builds and publishes the package to the
|
The included Gitea Actions workflow builds and publishes the package to the
|
||||||
Gitea PyPI registry from version-series branches such as ``8.0``.
|
Gitea PyPI registry from version-series branches such as ``7.0``.
|
||||||
|
|
||||||
Configure these repository secrets:
|
Configure this repository secret:
|
||||||
|
|
||||||
* ``REGISTRY_USER``
|
|
||||||
* ``REGISTRY_PASSWORD``
|
* ``REGISTRY_PASSWORD``
|
||||||
|
|
||||||
|
The module assigns fiscal numbers transactionally from ``ir.sequence.strict``.
|
||||||
|
It does not sign or transmit e-CF documents; transmission remains the explicit
|
||||||
|
responsibility of an electronic invoicing connector.
|
||||||
|
|
||||||
|
Version compatibility
|
||||||
|
*********************
|
||||||
|
|
||||||
|
The 7.0 and 8.0 series share the same fiscal models, workflows, importer,
|
||||||
|
validations and tests. Only the module registration, packaging metadata and
|
||||||
|
report XML required by each Tryton series remain version-specific.
|
||||||
|
|
||||||
|
Authorization workflow
|
||||||
|
**********************
|
||||||
|
|
||||||
|
NCF authorizations follow the protected workflow ``Draft → Active →
|
||||||
|
Finished``. Create the authorization and its fiscal lines in draft, then use
|
||||||
|
the **Activate** button. A line can select an existing strict sequence or ask
|
||||||
|
the module to create one on activation from its authorized range. Activation
|
||||||
|
checks company, fiscal type, prefix, padding, validity, availability and range
|
||||||
|
overlap. Incoming supplier documents and outgoing customer documents use
|
||||||
|
independent numbering authorities, so overlap is enforced only within the
|
||||||
|
same document direction. The last issued number automatically finishes the
|
||||||
|
line. Finishing an authorization closes every remaining active line without
|
||||||
|
reusing numbers.
|
||||||
|
|
||||||
|
Legacy migration lines keep their original technical sequence immutable after
|
||||||
|
activation. Prefix selection is enforced while a line is in draft and fiscal
|
||||||
|
activation performs the same server-side validation; closing a protected
|
||||||
|
historical line therefore does not invalidate already-linked invoices.
|
||||||
|
|
||||||
|
Electronic fiscal numbers are only reserved by this module. Activating an
|
||||||
|
E-series authorization never signs or transmits an e-CF to DGII.
|
||||||
|
|
||||||
|
Importing DGII authorizations
|
||||||
|
*****************************
|
||||||
|
|
||||||
|
Use **NCF Manager → Import DGII Authorization** to load an authorization
|
||||||
|
downloaded from the DGII Virtual Office. XML, CSV and the HTML table exported
|
||||||
|
with an ``.xls`` extension are supported and detected from their content.
|
||||||
|
The importer creates an independent workflow record for every ``NUM_AUTOR``.
|
||||||
|
The same ``NUM_SOL`` may therefore appear in several records without modifying
|
||||||
|
an authorization that is already active; file names are not used as fiscal
|
||||||
|
identifiers. It validates
|
||||||
|
approval status, company name, NCF type, prefix, range and approved quantity,
|
||||||
|
and stores the original file, SHA-256, user and import date for audit.
|
||||||
|
|
||||||
|
Imports are idempotent. Reimporting an equivalent CSV, XML or XLS record does
|
||||||
|
not create another line, while different fiscal data for an existing
|
||||||
|
authorization is rejected. The safe default leaves the result in draft so
|
||||||
|
the first number can be reviewed. Immediate activation is explicit and still
|
||||||
|
does not transmit electronic documents.
|
||||||
|
|||||||
+5
-2
@@ -15,12 +15,15 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="inherit" ref="account_invoice.invoice_view_tree"/>
|
<field name="inherit" ref="account_invoice.invoice_view_tree"/>
|
||||||
<field name="name">invoice_tree</field>
|
<field name="name">invoice_tree</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.action.report" id="account_invoice.report_invoice">
|
<record model="ir.action.report" id="account_invoice.report_invoice">
|
||||||
<field name="name">Invoice</field>
|
<field name="name">Factura</field>
|
||||||
|
<field name="active" eval="True"/>
|
||||||
<field name="model">account.invoice</field>
|
<field name="model">account.invoice</field>
|
||||||
<field name="report_name">account.invoice</field>
|
<field name="report_name">account.invoice</field>
|
||||||
<field name="report">ncf_manager/invoice.fodt</field>
|
<field name="report">ncf_manager/invoice.fodt</field>
|
||||||
|
<field name="template_extension">odt</field>
|
||||||
|
<field name="extension">pdf</field>
|
||||||
<field name="single" eval="True"/>
|
<field name="single" eval="True"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -307,8 +307,14 @@ class NCFManagerSequences(Workflow, ModelSQL, ModelView):
|
|||||||
depends=_depends, sort=False)
|
depends=_depends, sort=False)
|
||||||
|
|
||||||
ncf_sequences = fields.Many2One('ir.sequence.strict', 'Fiscal Sequence',
|
ncf_sequences = fields.Many2One('ir.sequence.strict', 'Fiscal Sequence',
|
||||||
|
context={
|
||||||
|
'company': Eval('company', -1),
|
||||||
|
},
|
||||||
domain=[
|
domain=[
|
||||||
('company', '=', Eval('company', -1)),
|
['OR',
|
||||||
|
('company', '=', Eval('company', -1)),
|
||||||
|
('company', '=', None),
|
||||||
|
],
|
||||||
If(Eval('state') == 'draft',
|
If(Eval('state') == 'draft',
|
||||||
('prefix', '=', Eval('expected_prefix')),
|
('prefix', '=', Eval('expected_prefix')),
|
||||||
()),
|
()),
|
||||||
@@ -499,7 +505,7 @@ class NCFManagerSequences(Workflow, ModelSQL, ModelView):
|
|||||||
if self.ncf_type == '99':
|
if self.ncf_type == '99':
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'ncf_manager.msg_ncf_non_fiscal_sequence'))
|
'ncf_manager.msg_ncf_non_fiscal_sequence'))
|
||||||
if sequence.company != self.pos.company:
|
if sequence.company and sequence.company != self.pos.company:
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'ncf_manager.msg_ncf_sequence_company_mismatch'))
|
'ncf_manager.msg_ncf_sequence_company_mismatch'))
|
||||||
expected_prefix = ncf_prefix(self.ncf_type)
|
expected_prefix = ncf_prefix(self.ncf_type)
|
||||||
|
|||||||
+10
-7
@@ -41,7 +41,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
id="menu_ncf_manager" action="act_ncf_manager"/>
|
id="menu_ncf_manager" action="act_ncf_manager"/>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_ncf_manager">
|
<record model="ir.model.access" id="access_ncf_manager">
|
||||||
<field name="model">ncf.manager</field>
|
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="False"/>
|
<field name="perm_write" eval="False"/>
|
||||||
<field name="perm_create" eval="False"/>
|
<field name="perm_create" eval="False"/>
|
||||||
@@ -49,7 +49,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_ncf_manager_admin">
|
<record model="ir.model.access" id="access_ncf_manager_admin">
|
||||||
<field name="model">ncf.manager</field>
|
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||||
<field name="group" ref="account.group_account_admin"/>
|
<field name="group" ref="account.group_account_admin"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="True"/>
|
<field name="perm_write" eval="True"/>
|
||||||
@@ -60,7 +60,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<record model="ir.model.button" id="ncf_manager_activate_button">
|
<record model="ir.model.button" id="ncf_manager_activate_button">
|
||||||
<field name="name">activate</field>
|
<field name="name">activate</field>
|
||||||
<field name="string">Activate</field>
|
<field name="string">Activate</field>
|
||||||
<field name="model">ncf.manager</field>
|
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.model.button-res.group"
|
<record model="ir.model.button-res.group"
|
||||||
id="ncf_manager_activate_button_group">
|
id="ncf_manager_activate_button_group">
|
||||||
@@ -70,7 +70,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<record model="ir.model.button" id="ncf_manager_finish_button">
|
<record model="ir.model.button" id="ncf_manager_finish_button">
|
||||||
<field name="name">finish</field>
|
<field name="name">finish</field>
|
||||||
<field name="string">Finish</field>
|
<field name="string">Finish</field>
|
||||||
<field name="model">ncf.manager</field>
|
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.model.button-res.group"
|
<record model="ir.model.button-res.group"
|
||||||
id="ncf_manager_finish_button_group">
|
id="ncf_manager_finish_button_group">
|
||||||
@@ -91,7 +91,8 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_ncf_manager_sequences">
|
<record model="ir.model.access" id="access_ncf_manager_sequences">
|
||||||
<field name="model">ncf.manager.sequence</field>
|
<field name="model"
|
||||||
|
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="False"/>
|
<field name="perm_write" eval="False"/>
|
||||||
<field name="perm_create" eval="False"/>
|
<field name="perm_create" eval="False"/>
|
||||||
@@ -99,7 +100,8 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.model.access" id="access_ncf_manager_sequences_admin">
|
<record model="ir.model.access" id="access_ncf_manager_sequences_admin">
|
||||||
<field name="model">ncf.manager.sequence</field>
|
<field name="model"
|
||||||
|
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||||
<field name="group" ref="account.group_account_admin"/>
|
<field name="group" ref="account.group_account_admin"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="True"/>
|
<field name="perm_write" eval="True"/>
|
||||||
@@ -110,7 +112,8 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<record model="ir.model.button" id="ncf_sequence_finish_button">
|
<record model="ir.model.button" id="ncf_sequence_finish_button">
|
||||||
<field name="name">finish</field>
|
<field name="name">finish</field>
|
||||||
<field name="string">Finish Sequence</field>
|
<field name="string">Finish Sequence</field>
|
||||||
<field name="model">ncf.manager.sequence</field>
|
<field name="model"
|
||||||
|
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.model.button-res.group"
|
<record model="ir.model.button-res.group"
|
||||||
id="ncf_sequence_finish_button_group">
|
id="ncf_sequence_finish_button_group">
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ['hatchling >=1,<1.31', 'hatch-tryton']
|
|
||||||
build-backend = 'hatchling.build'
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = 'unpaismejor_ncf_manager'
|
|
||||||
dynamic = ['version', 'dependencies', 'optional-dependencies', 'authors', 'readme']
|
|
||||||
requires-python = '>=3.11'
|
|
||||||
maintainers = [
|
|
||||||
{name = "Fundación Un País Mejor"},
|
|
||||||
]
|
|
||||||
description = "NCF management for Tryton"
|
|
||||||
license = 'GPL-3.0-or-later'
|
|
||||||
license-files = ["LICENSE", "COPYRIGHT"]
|
|
||||||
keywords = ["tryton", "ncf", "dominican-republic"]
|
|
||||||
classifiers = [
|
|
||||||
"Development Status :: 5 - Production/Stable",
|
|
||||||
"Environment :: Plugins",
|
|
||||||
"Framework :: Tryton",
|
|
||||||
"Topic :: Office/Business",
|
|
||||||
"Topic :: Office/Business :: Financial :: Accounting",
|
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.entry-points.'trytond.modules']
|
|
||||||
ncf_manager = 'trytond.modules.ncf_manager'
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
homepage = "https://code.unpaismejor.org.do/tryton-do/ncf_manager"
|
|
||||||
repository = "https://code.unpaismejor.org.do/tryton-do/ncf_manager.git"
|
|
||||||
|
|
||||||
[tool.hatch.build]
|
|
||||||
include = [
|
|
||||||
'**/tryton.cfg',
|
|
||||||
'**/*.py',
|
|
||||||
'**/*.xml',
|
|
||||||
'view/**/*.xml',
|
|
||||||
'locale/**/*.po',
|
|
||||||
'doc/**/*.rst',
|
|
||||||
'**/*.fodt',
|
|
||||||
'icons/**/*.svg',
|
|
||||||
'tests/**/*.py',
|
|
||||||
'tests/**/*.rst',
|
|
||||||
'tests/**/*.json',
|
|
||||||
]
|
|
||||||
exclude = [
|
|
||||||
'**/.ci-venv/**',
|
|
||||||
'**/.test-venv/**',
|
|
||||||
'**/.venv/**',
|
|
||||||
'**/__pycache__/**',
|
|
||||||
'**/*.py[co]',
|
|
||||||
'build/**',
|
|
||||||
'dist/**',
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel.sources]
|
|
||||||
"" = "trytond/modules/ncf_manager"
|
|
||||||
|
|
||||||
[tool.hatch.metadata.hooks.tryton]
|
|
||||||
copyright = 'COPYRIGHT'
|
|
||||||
readme = 'README.rst'
|
|
||||||
prefixes = {account_do = 'unpaismejor', account_credit_note = 'unpaismejor', account_debit_note = 'unpaismejor', account_invoice_do = 'unpaismejor'}
|
|
||||||
|
|
||||||
[tool.hatch.metadata.hooks.tryton.tryton-optional-dependencies]
|
|
||||||
test = ['proteus']
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
MODULE2PREFIX = {
|
||||||
|
'account_do': 'unpaismejor',
|
||||||
|
'account_credit_note': 'unpaismejor',
|
||||||
|
'account_debit_note': 'unpaismejor',
|
||||||
|
'account_invoice_do': 'unpaismejor',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def read(fname):
|
||||||
|
content = io.open(
|
||||||
|
os.path.join(os.path.dirname(__file__), fname),
|
||||||
|
'r', encoding='utf-8').read()
|
||||||
|
content = re.sub(
|
||||||
|
r'(?m)^\.\. toctree::\r?\n((^$|^\s.*$)\r?\n)*', '', content)
|
||||||
|
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 = 'unpaismejor_ncf_manager'
|
||||||
|
|
||||||
|
local_version = []
|
||||||
|
if os.environ.get('CI_JOB_ID'):
|
||||||
|
local_version.append(os.environ['CI_JOB_ID'])
|
||||||
|
else:
|
||||||
|
for build in ['CI_BUILD_NUMBER', 'CI_JOB_NUMBER']:
|
||||||
|
if os.environ.get(build):
|
||||||
|
local_version.append(os.environ[build])
|
||||||
|
else:
|
||||||
|
local_version = []
|
||||||
|
break
|
||||||
|
if local_version:
|
||||||
|
version += '+' + '.'.join(local_version)
|
||||||
|
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/?local_version='
|
||||||
|
+ '.'.join(local_version)
|
||||||
|
+ '&mirror=github')
|
||||||
|
|
||||||
|
setup(name=name,
|
||||||
|
version=version,
|
||||||
|
description='This module implements the administration and management of tax receipt numbers.',
|
||||||
|
long_description=read('README.rst'),
|
||||||
|
long_description_content_type='text/x-rst',
|
||||||
|
author='Solutema SRL',
|
||||||
|
author_email='info@solutema.com',
|
||||||
|
url='https://www.solutema.com/',
|
||||||
|
keywords='tryton invoice',
|
||||||
|
package_dir={'trytond.modules.ncf_manager': '.'},
|
||||||
|
packages=(
|
||||||
|
['trytond.modules.ncf_manager']
|
||||||
|
+ ['trytond.modules.ncf_manager.%s' % p
|
||||||
|
for p in find_packages()]
|
||||||
|
),
|
||||||
|
package_data={
|
||||||
|
'trytond.modules.ncf_manager': (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 :: Romanian',
|
||||||
|
'Natural Language :: Russian',
|
||||||
|
'Natural Language :: Slovenian',
|
||||||
|
'Natural Language :: Spanish',
|
||||||
|
'Natural Language :: Turkish',
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
|
'Programming Language :: Python :: 3.10',
|
||||||
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
|
'Topic :: Office/Business',
|
||||||
|
],
|
||||||
|
license='GPL-3',
|
||||||
|
python_requires='>=3.7',
|
||||||
|
install_requires=requires,
|
||||||
|
extras_require={
|
||||||
|
'test': tests_require,
|
||||||
|
},
|
||||||
|
dependency_links=dependency_links,
|
||||||
|
zip_safe=False,
|
||||||
|
entry_points="""
|
||||||
|
[trytond.modules]
|
||||||
|
ncf_manager = trytond.modules.ncf_manager
|
||||||
|
""", # noqa: E501
|
||||||
|
)
|
||||||
@@ -332,6 +332,59 @@ class NcfManagerTestCase(ModuleTestCase):
|
|||||||
self.assertEqual(manager.ncf_sequences[0].state, 'finished')
|
self.assertEqual(manager.ncf_sequences[0].state, 'finished')
|
||||||
self.assertIsNotNone(manager.finished_at)
|
self.assertIsNotNone(manager.finished_at)
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_global_fiscal_sequence_can_be_assigned_to_manager(self):
|
||||||
|
'Global fiscal sequences can be attached to a company authorization'
|
||||||
|
pool = Pool()
|
||||||
|
Manager = pool.get('ncf.manager')
|
||||||
|
ManagerSequence = pool.get('ncf.manager.sequence')
|
||||||
|
ModelData = pool.get('ir.model.data')
|
||||||
|
StrictSequence = pool.get('ir.sequence.strict')
|
||||||
|
SequenceType = pool.get('ir.sequence.type')
|
||||||
|
today = datetime.date.today()
|
||||||
|
company = self._create_company()
|
||||||
|
|
||||||
|
sequence_type = SequenceType(ModelData.get_id(
|
||||||
|
'ncf_manager', 'sequence_type_out_invoice_01'))
|
||||||
|
strict_sequence, = StrictSequence.create([{
|
||||||
|
'name': 'Factura de Crédito Fiscal',
|
||||||
|
'sequence_type': sequence_type.id,
|
||||||
|
'prefix': 'B01',
|
||||||
|
'padding': 8,
|
||||||
|
'number_next': 1,
|
||||||
|
'number_increment': 1,
|
||||||
|
'from_number': 1,
|
||||||
|
'until_number': 100,
|
||||||
|
'expiration_date': datetime.date(today.year, 12, 31),
|
||||||
|
}])
|
||||||
|
manager, = Manager.create([{
|
||||||
|
'company': company.id,
|
||||||
|
'app_date': today,
|
||||||
|
'app_number': 'APP0000001',
|
||||||
|
'auth_number': 'AUT0000001',
|
||||||
|
}])
|
||||||
|
|
||||||
|
line, = ManagerSequence.create([{
|
||||||
|
'pos': manager.id,
|
||||||
|
'invoice_type': 'invoice_customer',
|
||||||
|
'ncf_type': '1',
|
||||||
|
'sequence_mode': 'existing',
|
||||||
|
'ncf_sequences': strict_sequence.id,
|
||||||
|
}])
|
||||||
|
|
||||||
|
self.assertEqual(line.ncf_sequences, strict_sequence)
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_manual_sequence_creation_defaults_to_current_company(self):
|
||||||
|
'Manual sequence creation uses the current company from context'
|
||||||
|
StrictSequence = Pool().get('ir.sequence.strict')
|
||||||
|
company = self._create_company()
|
||||||
|
|
||||||
|
with Transaction().set_context(company=company.id):
|
||||||
|
defaults = StrictSequence.default_get(['company'])
|
||||||
|
|
||||||
|
self.assertEqual(defaults['company'], company.id)
|
||||||
|
|
||||||
@with_transaction()
|
@with_transaction()
|
||||||
def test_overlap_is_independent_by_invoice_direction(self):
|
def test_overlap_is_independent_by_invoice_direction(self):
|
||||||
'A supplier range must not block the company outgoing authorization'
|
'A supplier range must not block the company outgoing authorization'
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Reject development artifacts accidentally bundled in a wheel."""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from zipfile import ZipFile
|
|
||||||
|
|
||||||
|
|
||||||
wheel = next(Path('dist').glob('*.whl'))
|
|
||||||
forbidden = {'.ci-venv', '.test-venv', '.venv', '__pycache__'}
|
|
||||||
with ZipFile(wheel) as archive:
|
|
||||||
invalid = [
|
|
||||||
name for name in archive.namelist()
|
|
||||||
if forbidden.intersection(Path(name).parts)
|
|
||||||
or name.endswith(('.pyc', '.pyo'))
|
|
||||||
]
|
|
||||||
if invalid:
|
|
||||||
raise SystemExit(f'Forbidden wheel content: {invalid[:10]}')
|
|
||||||
print(f'Validated clean wheel: {wheel}')
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = {py311,py312,py313,py314}-{sqlite,postgresql}
|
envlist = {py311,py312,py313}-{sqlite,postgresql}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
extras = test
|
extras = test
|
||||||
|
|||||||
+1
-19
@@ -1,5 +1,5 @@
|
|||||||
[tryton]
|
[tryton]
|
||||||
version=8.0.4
|
version=7.0.3
|
||||||
depends:
|
depends:
|
||||||
account_do
|
account_do
|
||||||
account_invoice_do
|
account_invoice_do
|
||||||
@@ -14,21 +14,3 @@ xml:
|
|||||||
party.xml
|
party.xml
|
||||||
user.xml
|
user.xml
|
||||||
message.xml
|
message.xml
|
||||||
|
|
||||||
[register]
|
|
||||||
model:
|
|
||||||
invoice.Invoice
|
|
||||||
ncf_manager.NCFManager
|
|
||||||
ncf_manager.NCFManagerSequences
|
|
||||||
sequence.Sequence
|
|
||||||
sequence.SequenceStrict
|
|
||||||
configuration.Configuration
|
|
||||||
configuration.DefaultNcfType
|
|
||||||
party.PartyNcfType
|
|
||||||
party.Party
|
|
||||||
user.User
|
|
||||||
importer.ImportNCFStart
|
|
||||||
wizard:
|
|
||||||
importer.ImportNCF
|
|
||||||
report:
|
|
||||||
invoice.InvoiceReport
|
|
||||||
|
|||||||
Reference in New Issue
Block a user