Compare commits
-78
@@ -1,78 +0,0 @@
|
||||
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:
|
||||
push:
|
||||
branches: ["7.0"]
|
||||
branches: ["8.0"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
git init .
|
||||
git remote add origin http://unpaismejor-gitea-app:3000/tryton-do/ncf_manager.git
|
||||
git -c http.extraHeader="Authorization: token $GITEA_TOKEN" \
|
||||
fetch --depth=1 origin 7.0
|
||||
fetch --depth=1 origin 8.0
|
||||
git checkout --detach FETCH_HEAD
|
||||
|
||||
- name: Verificar Python
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: |
|
||||
python3 -m venv .ci-venv
|
||||
.ci-venv/bin/python -m pip install --upgrade \
|
||||
"setuptools>=68,<81" "wheel>=0.41,<1" "twine>=6,<7"
|
||||
"build>=1,<2" "twine>=6,<7"
|
||||
|
||||
- name: Comprobar credenciales
|
||||
env:
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
- name: Fijar versión CI
|
||||
env:
|
||||
PACKAGE_VERSION: 7.0.${{ gitea.run_number }}
|
||||
PACKAGE_VERSION: 8.0.${{ gitea.run_number }}
|
||||
run: |
|
||||
.ci-venv/bin/python - <<'PY'
|
||||
from pathlib import Path
|
||||
@@ -53,8 +53,9 @@ jobs:
|
||||
|
||||
- name: Construir y validar
|
||||
run: |
|
||||
.ci-venv/bin/python setup.py sdist bdist_wheel
|
||||
.ci-venv/bin/python -m build
|
||||
.ci-venv/bin/python -m twine check dist/*
|
||||
.ci-venv/bin/python tools/check_wheel.py
|
||||
|
||||
- name: Publicar en Gitea PyPI
|
||||
env:
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/.coverage
|
||||
/.eggs/
|
||||
/.pytest_cache/
|
||||
/.tox/
|
||||
/build/
|
||||
/dist/
|
||||
/*.egg-info/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
.DS_Store
|
||||
@@ -1,12 +0,0 @@
|
||||
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 SOLUTEMA SRL
|
||||
Copyright (C) 2022-2026 Fundación Un País Mejor
|
||||
|
||||
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
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
include CHANGELOG
|
||||
include COPYRIGHT
|
||||
include LICENSE
|
||||
include README.rst
|
||||
graft doc
|
||||
@@ -1 +0,0 @@
|
||||
doc/index.rst
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
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.
|
||||
+9
-21
@@ -1,4 +1,3 @@
|
||||
from trytond.pool import Pool
|
||||
from . import invoice
|
||||
from . import importer
|
||||
from . import ncf_manager
|
||||
@@ -7,23 +6,12 @@ from . import configuration
|
||||
from . import party
|
||||
from . import user
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
invoice.Invoice,
|
||||
ncf_manager.NCFManager,
|
||||
ncf_manager.NCFManagerSequences,
|
||||
sequence.Sequence,
|
||||
sequence.SequenceStrict,
|
||||
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')
|
||||
__all__ = [
|
||||
'configuration',
|
||||
'invoice',
|
||||
'importer',
|
||||
'ncf_manager',
|
||||
'party',
|
||||
'sequence',
|
||||
'user',
|
||||
]
|
||||
|
||||
+4
-55
@@ -12,67 +12,16 @@ Installing
|
||||
|
||||
Install the package and activate the module in the database::
|
||||
|
||||
pip install unpaismejor_ncf_manager
|
||||
pip install trytond_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 ``7.0``.
|
||||
Gitea PyPI registry from version-series branches such as ``8.0``.
|
||||
|
||||
Configure this repository secret:
|
||||
Configure these repository secrets:
|
||||
|
||||
* ``REGISTRY_USER``
|
||||
* ``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.
|
||||
|
||||
+1
-4
@@ -17,13 +17,10 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
|
||||
<record model="ir.action.report" id="account_invoice.report_invoice">
|
||||
<field name="name">Factura</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="name">Invoice</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="report_name">account.invoice</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"/>
|
||||
</record>
|
||||
|
||||
|
||||
+2
-8
@@ -307,14 +307,8 @@ class NCFManagerSequences(Workflow, ModelSQL, ModelView):
|
||||
depends=_depends, sort=False)
|
||||
|
||||
ncf_sequences = fields.Many2One('ir.sequence.strict', 'Fiscal Sequence',
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
},
|
||||
domain=[
|
||||
['OR',
|
||||
('company', '=', Eval('company', -1)),
|
||||
('company', '=', None),
|
||||
],
|
||||
('company', '=', Eval('company', -1)),
|
||||
If(Eval('state') == 'draft',
|
||||
('prefix', '=', Eval('expected_prefix')),
|
||||
()),
|
||||
@@ -505,7 +499,7 @@ class NCFManagerSequences(Workflow, ModelSQL, ModelView):
|
||||
if self.ncf_type == '99':
|
||||
raise UserError(gettext(
|
||||
'ncf_manager.msg_ncf_non_fiscal_sequence'))
|
||||
if sequence.company and sequence.company != self.pos.company:
|
||||
if sequence.company != self.pos.company:
|
||||
raise UserError(gettext(
|
||||
'ncf_manager.msg_ncf_sequence_company_mismatch'))
|
||||
expected_prefix = ncf_prefix(self.ncf_type)
|
||||
|
||||
+7
-10
@@ -41,7 +41,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
id="menu_ncf_manager" action="act_ncf_manager"/>
|
||||
|
||||
<record model="ir.model.access" id="access_ncf_manager">
|
||||
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||
<field name="model">ncf.manager</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
@@ -49,7 +49,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_ncf_manager_admin">
|
||||
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||
<field name="model">ncf.manager</field>
|
||||
<field name="group" ref="account.group_account_admin"/>
|
||||
<field name="perm_read" 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">
|
||||
<field name="name">activate</field>
|
||||
<field name="string">Activate</field>
|
||||
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||
<field name="model">ncf.manager</field>
|
||||
</record>
|
||||
<record model="ir.model.button-res.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">
|
||||
<field name="name">finish</field>
|
||||
<field name="string">Finish</field>
|
||||
<field name="model" search="[('model', '=', 'ncf.manager')]"/>
|
||||
<field name="model">ncf.manager</field>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group"
|
||||
id="ncf_manager_finish_button_group">
|
||||
@@ -91,8 +91,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_ncf_manager_sequences">
|
||||
<field name="model"
|
||||
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||
<field name="model">ncf.manager.sequence</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
@@ -100,8 +99,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_ncf_manager_sequences_admin">
|
||||
<field name="model"
|
||||
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||
<field name="model">ncf.manager.sequence</field>
|
||||
<field name="group" ref="account.group_account_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
@@ -112,8 +110,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.model.button" id="ncf_sequence_finish_button">
|
||||
<field name="name">finish</field>
|
||||
<field name="string">Finish Sequence</field>
|
||||
<field name="model"
|
||||
search="[('model', '=', 'ncf.manager.sequence')]"/>
|
||||
<field name="model">ncf.manager.sequence</field>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group"
|
||||
id="ncf_sequence_finish_button_group">
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
[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']
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/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,59 +332,6 @@ class NcfManagerTestCase(ModuleTestCase):
|
||||
self.assertEqual(manager.ncf_sequences[0].state, 'finished')
|
||||
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()
|
||||
def test_overlap_is_independent_by_invoice_direction(self):
|
||||
'A supplier range must not block the company outgoing authorization'
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/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]
|
||||
envlist = {py311,py312,py313}-{sqlite,postgresql}
|
||||
envlist = {py311,py312,py313,py314}-{sqlite,postgresql}
|
||||
|
||||
[testenv]
|
||||
extras = test
|
||||
|
||||
+19
-1
@@ -1,5 +1,5 @@
|
||||
[tryton]
|
||||
version=7.0.3
|
||||
version=8.0.4
|
||||
depends:
|
||||
account_do
|
||||
account_invoice_do
|
||||
@@ -14,3 +14,21 @@ xml:
|
||||
party.xml
|
||||
user.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