diff --git a/.dev/Procfile b/.dev/Procfile new file mode 100755 index 0000000..4fdb8f4 --- /dev/null +++ b/.dev/Procfile @@ -0,0 +1,2 @@ +trytond: while true; do trytond -d ${DB_NAME} --dev -v -c $SCRIPT_DIR/trytond.cfg; done +monitor: python3 $SCRIPT_DIR/dev.py \ No newline at end of file diff --git a/.dev/dev.py b/.dev/dev.py new file mode 100755 index 0000000..de7108c --- /dev/null +++ b/.dev/dev.py @@ -0,0 +1,52 @@ +# script para refrescar cambios de xml del modulo de tryton +import sys +import os +import logging +import time + +import inotify.adapters + +logging.basicConfig(level=logging.INFO, stream=sys.stderr) + +SRC = os.environ['SRC'] + '/modules/' +MODULES = os.environ['MODULES'].split(':') +DB_NAME = os.environ['DB_NAME'] + + +def _main(): + i = inotify.adapters.Inotify() + logging.info("MONITOREANDO ARCHIVOS EN %s", SRC) + + for module in MODULES: + logging.info('NOMBRE DEL MODULO A MONITOREAR%s', module) + i.add_watch( + SRC + module) + + for event in i.event_gen(yield_nones=False): + (_, type_names, path, filename) = event + (_, ext) = os.path.splitext(filename) + + if 'IN_CLOSE_WRITE' not in type_names: + continue + + module_name = path.split('/')[-1] + logging.info('NOMBRE DEL MODULO %s', module_name) + + if ext in ['.py', '.xml', '.cfg']: + for _ in range(0, 10): + command = "trytond-admin -d {} -u {} --act -vv".format( + DB_NAME, module_name) + logging.debug("Ejecutando comando: %s", command) + update_module = os.system(command) + if update_module != 0: + time.sleep(2) + logging.error("fallo trytond-admin") + else: + logging.info( + "ACTUALIZADO TRYTOND POR CAMBIO DE ARCHIVO %s", + filename) + break + + +if __name__ == '__main__': + _main() diff --git a/.dev/install_module.sh b/.dev/install_module.sh new file mode 100644 index 0000000..f678f2d --- /dev/null +++ b/.dev/install_module.sh @@ -0,0 +1,66 @@ +# este script fuerza que los cambios se vean reflejados +# directamente en trytond. +# +# variables exportadas: +# - module_name + +[ ! -d "$SRC" ] && die "no se ubica ruta en SRC" + +if [ -z "${DEVELOP}" ]; then + DEVELOP="False" +fi + +if [ ${DEVELOP} = "True" ]; then + pip3 install --break-system-packages -r .dev/requirements_dev.txt +fi + +# dependencias minimas +pip3 install --break-system-packages -r requirements.txt + +pip3 install --break-system-packages trytond==${TRYTOND_VERSION} +official_modules=".dev/official_modules.txt" + +while IFS= read -r module; do + pip3 index versions "trytond-$module" | grep -oP '\d+\.\d+\.\d+' | grep "^${TRYTOND_VERSION}" | while read version; do + pip3 install --break-system-packages "trytond-$module==${version}" + echo "Versión instalada: $module==$version" + break + done + +done <"$official_modules" + +if [ -d "modules" ] && [ "$(ls -A modules)" ]; then + + module_names=() + for module in modules/*/; do + + pushd "$module" + + # instalar dependencias de tryton desde paquete + python3 setup.py install + + # usamos enlace al paquete + python3 setup.py develop + + # instalar modulo + trytond_modules_path=$(pip3 show trytond | grep Location | sed -nr 's/Location: +//gp')/trytond/modules + module_name=$(cat "setup.py" | fgrep -A 1 [trytond.modules] | sed 1d | cut -d '=' -f 1 | tr -d ' \n') + + # Añadir el nombre del módulo al arreglo + module_names+=("$module_name") + + [ ! -d "$trytond_modules_path" ] && die "fallo al ubicar ruta de modulos de trytond" + ln -sf "$SRC/$module" "$trytond_modules_path/$module_name" + rm -rf "$SRC/$module/$module_name" + + popd + + done + + trytond_path=$(pip3 show trytond | grep Location | sed -nr 's/Location: +//gp')/trytond + + module_names=$( + IFS=: + echo "${module_names[*]}" + ) +fi diff --git a/.dev/official_modules.txt b/.dev/official_modules.txt new file mode 100644 index 0000000..251fb6a --- /dev/null +++ b/.dev/official_modules.txt @@ -0,0 +1,2 @@ +country +company diff --git a/.dev/requirements_dev.txt b/.dev/requirements_dev.txt new file mode 100644 index 0000000..f14fa59 --- /dev/null +++ b/.dev/requirements_dev.txt @@ -0,0 +1,6 @@ +inotify==0.2.10 +honcho==2.0.0 +pudb==2025.1 +urwid==3.0.2 +freezegun==1.5.1 +psycopg2==2.9.10 diff --git a/.dev/run.sh b/.dev/run.sh new file mode 100755 index 0000000..13f3f5f --- /dev/null +++ b/.dev/run.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# script para iniciar entorno vivo + + +SCRIPT_DIR=$(dirname `realpath $0`) + +die() { + echo $1 + exit 1 +} + +[ ! -d "$SRC" ] && die "no se ubica ruta en SRC" +[ -z "$DB_NAME" ] && die "se requiere variable DB_NAME" + +set -e + +# instalar modulo +source ${SCRIPT_DIR}/install_module.sh + +# inicializar base de datos +# https://docs.tryton.org/projects/server/en/latest/tutorial/module/setup_database.html +yes admin | trytond-admin -d ${DB_NAME} --all --act + + +# ejecutar servidor +export SCRIPT_DIR +export MODULES=$module_names +export DB_NAME +export SRC + +honcho -d ${SCRIPT_DIR} start diff --git a/.dev/trytond.cfg b/.dev/trytond.cfg new file mode 100755 index 0000000..4453ac2 --- /dev/null +++ b/.dev/trytond.cfg @@ -0,0 +1,3 @@ +[web] +listen = 0.0.0.0:8000 +root=/var/lib/trytond/www diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..a850fa5 --- /dev/null +++ b/.env_example @@ -0,0 +1,8 @@ +# TRYTOND operation mode +DEVELOP=False + +# Develop mode +PUDB_PORT=8025 + +# TRYTOND information +TRYTOND_VERSION=7.6 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..2beef91 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +ignore=E123,E124,E126,E128,E741,W503 +exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,.dev \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9db73e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,228 @@ +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +*.bk + +/.vscode + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +bin/ +include/ +wheels/ +__pycache__ +trytond_miac.egg-info/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script fkrom a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# ---> Emacs +# -*- mode: gitignore; -*- +*~ +.~* +*# +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +# ---> Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# ---> VirtualEnv +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +.Python +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +.venv +pip-selfcheck.json + +.tdd_cache +app \ No newline at end of file diff --git a/Dockerfile_Test b/Dockerfile_Test new file mode 100755 index 0000000..cd83991 --- /dev/null +++ b/Dockerfile_Test @@ -0,0 +1,5 @@ +# TOMADO DE: https://hg.tryton.org/tryton-docker/file/tip/6.6/Dockerfile +FROM python:3.11-bullseye + +# trytond DB_CACHE requiere commandos `pg_dump` y `pg_restore` +RUN apt-get update && apt-get install -y postgresql-client diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e5b0251 --- /dev/null +++ b/Rakefile @@ -0,0 +1,45 @@ +require 'yaml' +require 'digest' + +DOCKER_COMPOSE='compose.test.yml' + +desc 'iniciar entorno' +task :up do + compose('up', '--build', '-d') +end + +desc 'poblar entorno' +task :init => [:up] do + compose('exec', 'test.dev', 'pip3 install psycopg2 flake8') + compose('exec', 'test.dev', "bash .dev/install_module.sh") +end + +desc 'terminal' +task :sh do + compose('exec', 'test.dev', 'bash') +end + +desc 'iterar' +task :tdd, [:name] do |_, args| + + refresh_cache + test_dir = '' + if args.name + test_dir = "modules/#{args.name}" + compose('exec', 'test.dev', "bash -c 'cd #{test_dir} && flake8'") + compose('exec', 'test.dev', "bash -c 'cd #{test_dir}/tests && python3 -m unittest'") + else + compose('exec', 'test.dev', "bash -c 'cd modules && flake8 *'") + compose('exec', 'test.dev', "bash -c 'python -m unittest discover -s modules'") + end + +end + +desc 'detener entorno' +task :down do + compose('down', '-vv') +end + +def compose(*arg, compose: DOCKER_COMPOSE) + sh "docker-compose -f #{compose} #{arg.join(' ')}" +end diff --git a/compose.test.yml b/compose.test.yml new file mode 100755 index 0000000..1c78bae --- /dev/null +++ b/compose.test.yml @@ -0,0 +1,20 @@ +services: + test.dev: + build: + context: . + dockerfile: Dockerfile_Test + args: + TRYTOND_VERSION: ${TRYTOND_VERSION} + environment: + SRC: /app + DB_CACHE: /tmp + DB_NAME: ":memory:" + TRYTOND_DATABASE_URI: sqlite:// + command: sleep 10h + volumes: + - .:/app + ports: + - "${PUDB_PORT:-8025}:8025" + working_dir: /app + env_file: + - .env diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a613053 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +qrcode==6.1 +pydot==3.0.0 +tqdm==4.67.1