diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..897fc2e --- /dev/null +++ b/.drone.yml @@ -0,0 +1,57 @@ +clone: + hg: + image: plugins/hg + +pipeline: + tox: + image: ${IMAGE} + environment: + - CFLAGS=-O0 + - DB_CACHE=/cache + - TOX_TESTENV_PASSENV=CFLAGS DB_CACHE + - POSTGRESQL_URI=postgresql://postgres@postgresql:5432/ + commands: + - pip install tox + - tox -e "${TOXENV}-${DATABASE}" + notify: + image: drillster/drone-email + from: drone@localhost + host: smtp + port: 25 + skip_verify: true + when: + status: [ changed, failure ] + +services: + postgresql: + image: postgres + when: + matrix: + DATABASE: postgresql + +matrix: + include: + - IMAGE: python:2.7 + TOXENV: py27 + DATABASE: sqlite + - IMAGE: python:2.7 + TOXENV: py27 + DATABASE: postgresql + - IMAGE: python:3.4 + TOXENV: py34 + DATABASE: sqlite + - IMAGE: python:3.4 + TOXENV: py34 + DATABASE: postgresql + - IMAGE: python:3.5 + TOXENV: py35 + DATABASE: sqlite + - IMAGE: python:3.5 + TOXENV: py35 + DATABASE: postgresql + - IMAGE: python:3.6 + TOXENV: py36 + DATABASE: sqlite + - IMAGE: python:3.6 + TOXENV: py36 + DATABASE: postgresql diff --git a/__init__.py b/__init__.py index 52669f9..82afea9 100644 --- a/__init__.py +++ b/__init__.py @@ -4,6 +4,7 @@ from trytond.pool import Pool from . import operation from . import configuration + def register(): Pool.register( configuration.Configuration, diff --git a/configuration.py b/configuration.py index 280e8f6..ba80f21 100644 --- a/configuration.py +++ b/configuration.py @@ -11,7 +11,7 @@ class Configuration: (None, ''), ('user_warning', 'User Warning'), ('user_error', 'User Error'), - ], 'Check State Operation', + ], 'Check State Operation', help='Check state operation when done a production') @staticmethod diff --git a/operation.py b/operation.py index 8759bc7..9d2ee4f 100644 --- a/operation.py +++ b/operation.py @@ -1,5 +1,6 @@ from decimal import Decimal -from trytond.model import fields, ModelSQL, ModelView, Workflow +from trytond.model import (fields, ModelSQL, ModelView, Workflow, + sequence_ordered) from trytond.pool import Pool, PoolMeta from trytond.pyson import Eval, If, Id from trytond.transaction import Transaction @@ -12,13 +13,12 @@ STATES = { DEPENDS = ['state'] -class Operation(Workflow, ModelSQL, ModelView): +class Operation(sequence_ordered(), Workflow, ModelSQL, ModelView): 'Operation' __name__ = 'production.operation' production = fields.Many2One('production', 'Production', required=True, states=STATES, depends=DEPENDS, ondelete='CASCADE') - sequence = fields.Integer('Sequence', states=STATES, depends=DEPENDS) work_center_category = fields.Many2One('production.work_center.category', 'Work Center Category', states=STATES, depends=DEPENDS, required=True) work_center = fields.Many2One('production.work_center', 'Work Center', @@ -47,7 +47,6 @@ class Operation(Workflow, ModelSQL, ModelView): @classmethod def __setup__(cls): super(Operation, cls).__setup__() - cls._order.insert(0, ('sequence', 'ASC')) cls._invalid_production_states_on_create = ['done'] cls._error_messages.update({ 'invalid_production_state': ('You can not create an operation' @@ -120,11 +119,6 @@ class Operation(Workflow, ModelSQL, ModelView): default.setdefault('lines', []) return super(Operation, cls).copy(operations, default) - @staticmethod - def order_sequence(tables): - table, _ = tables[None] - return [table.sequence == None, table.sequence] - def get_cost(self, name): cost = Decimal('0.0') for line in self.lines: @@ -299,10 +293,11 @@ class Production: if pending_operations: operation, = pending_operations if config.check_state_operation == 'user_warning': - cls.raise_user_warning('pending_operation_%d' % operation.id, - 'pending_operations', warning_args={ - 'production': operation.production.rec_name, - 'operation': operation.rec_name, + cls.raise_user_warning( + 'pending_operation_%d' % operation.id, + 'pending_operations', warning_args={ + 'production': operation.production.rec_name, + 'operation': operation.rec_name, }) else: cls.raise_user_error('pending_operations', error_args={ diff --git a/operation.xml b/operation.xml index cfc4cbf..8588290 100644 --- a/operation.xml +++ b/operation.xml @@ -94,6 +94,22 @@ + + wait + Wait + + + + run + Run + + + + done + Done + + + production.operation.tracking diff --git a/setup.py b/setup.py index 07e827b..b76e97b 100644 --- a/setup.py +++ b/setup.py @@ -4,43 +4,74 @@ from setuptools import setup import re import os -import ConfigParser +import io +try: + from configparser import ConfigParser +except ImportError: + from ConfigParser import ConfigParser MODULE = 'production_operation' PREFIX = 'nantic' MODULE2PREFIX = { 'production_route': 'nantic', -} + } def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() + return io.open( + os.path.join(os.path.dirname(__file__), fname), + 'r', encoding='utf-8').read() -config = ConfigParser.ConfigParser() + +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.readfp(open('tryton.cfg')) info = dict(config.items('tryton')) for key in ('depends', 'extras_depend', 'xml'): if key in info: info[key] = info[key].strip().splitlines() -major_version, minor_version, _ = info.get('version', '0.0.1').split('.', 2) +version = info.get('version', '0.0.1') +major_version, minor_version, _ = version.split('.', 2) major_version = int(major_version) minor_version = int(minor_version) requires = [] for dep in info.get('depends', []): - if not re.match(r'(ir|res|webdav)(\W|$)', dep): + if not re.match(r'(ir|res)(\W|$)', dep): prefix = MODULE2PREFIX.get(dep, 'trytond') - requires.append('%s_%s >= %s.%s, < %s.%s' % - (prefix, dep, major_version, minor_version, - major_version, minor_version + 1)) -requires.append('trytond >= %s.%s, < %s.%s' % - (major_version, minor_version, major_version, minor_version + 1)) + requires.append(get_require_version('%s_%s' % (prefix, dep))) +requires.append(get_require_version('trytond')) + +tests_require = [get_require_version('proteus')] +series = '%s.%s' % (major_version, minor_version) +if minor_version % 2: + branch = 'default' +else: + branch = series +dependency_links = [ + ('hg+https://bitbucket.org/nantic/' + 'trytond-production_route@%(branch)s' + '#egg=nantic-production_route-%(series)s' % { + 'branch': branch, + 'series': series, + }), + ] +if minor_version % 2: + # Add development index for testing with proteus + dependency_links.append('https://trydevpi.tryton.org/') -tests_require = ['proteus >= %s.%s, < %s.%s' % - (major_version, minor_version, major_version, minor_version + 1)] setup(name='%s_%s' % (PREFIX, MODULE), - version=info.get('version', '0.0.1'), + version=version, description='', long_description=read('README'), author='NaN·tic', @@ -73,12 +104,17 @@ setup(name='%s_%s' % (PREFIX, MODULE), 'Natural Language :: Russian', 'Natural Language :: Spanish', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Office/Business', ], license='GPL-3', install_requires=requires, + dependency_links=dependency_links, zip_safe=False, entry_points=""" [trytond.modules] @@ -87,4 +123,8 @@ setup(name='%s_%s' % (PREFIX, MODULE), test_suite='tests', test_loader='trytond.test_loader:Loader', tests_require=tests_require, + use_2to3=True, + convert_2to3_doctests=[ + 'tests/scenario_production_operation.rst', + ] ) diff --git a/tests/__init__.py b/tests/__init__.py index 688bc7b..9882c42 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,8 @@ # The COPYRIGHT file at the top level of this repository contains the full # copyright notices and license terms. - -from .test_production_operation import suite +try: + from trytond.modules.production_operation.tests.test_production_operation import suite +except ImportError: + from .test_production_operation import suite __all__ = ['suite'] diff --git a/tests/scenario_production_operation.rst b/tests/scenario_production_operation.rst index f212f8f..daf9a0c 100644 --- a/tests/scenario_production_operation.rst +++ b/tests/scenario_production_operation.rst @@ -1,10 +1,6 @@ -=================== -Production Scenario -=================== - -============= -General Setup -============= +============================= +Production Operation Scenario +============================= Imports:: @@ -12,32 +8,20 @@ Imports:: >>> from dateutil.relativedelta import relativedelta >>> from decimal import Decimal >>> from proteus import config, Model, Wizard + >>> from trytond.tests.tools import activate_modules >>> from trytond.modules.company.tests.tools import create_company, \ ... get_company >>> today = datetime.date.today() -Create database:: - - >>> config = config.set_trytond() - >>> config.pool.test = True - Install production_operation Module:: - >>> Module = Model.get('ir.module') - >>> modules = Module.find([('name', '=', 'production_operation')]) - >>> Module.install([x.id for x in modules], config.context) - >>> Wizard('ir.module.install_upgrade').execute('upgrade') + >>> config = activate_modules('production_operation') Create company:: >>> _ = create_company() >>> company = get_company() -Reload the context:: - - >>> User = Model.get('res.user') - >>> config._context = User.get_preferences(True, config.context) - Configuration production location:: >>> Location = Model.get('stock.location') @@ -46,7 +30,7 @@ Configuration production location:: >>> warehouse.production_location = production_location >>> warehouse.save() -Create a route with two operations on diferent work center:: +Create a route with two operations on different work center:: >>> ProductUom = Model.get('product.uom') >>> Route = Model.get('production.route') @@ -113,10 +97,11 @@ Create product:: >>> template.name = 'product' >>> template.default_uom = unit >>> template.type = 'goods' + >>> template.producible = True >>> template.list_price = Decimal(30) - >>> template.cost_price = Decimal(20) >>> template.save() >>> product.template = template + >>> product.cost_price = Decimal(20) >>> product.save() Create Components:: @@ -127,9 +112,9 @@ Create Components:: >>> template1.default_uom = unit >>> template1.type = 'goods' >>> template1.list_price = Decimal(5) - >>> template1.cost_price = Decimal(1) >>> template1.save() >>> component1.template = template1 + >>> component1.cost_price = Decimal(1) >>> component1.save() >>> meter, = ProductUom.find([('name', '=', 'Meter')]) @@ -140,9 +125,9 @@ Create Components:: >>> template2.default_uom = meter >>> template2.type = 'goods' >>> template2.list_price = Decimal(7) - >>> template2.cost_price = Decimal(5) >>> template2.save() >>> component2.template = template2 + >>> component2.cost_price = Decimal(5) >>> component2.save() Create Bill of Material:: @@ -230,10 +215,10 @@ Make a production:: True >>> all(o.state == 'waiting' for o in production.operations) True - >>> Production.done([production.id], config.context) + >>> Production.done([production.id], config.context) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... - UserError: ('UserError', (u'Production "1" can not be done because their operation "Assembly" is not done.', '')) + UserError: ... >>> operation1, operation2 = production.operations >>> tracking = OperationTracking() >>> operation1.lines.append(tracking) @@ -255,5 +240,5 @@ Make a production:: >>> production.reload() >>> production.state u'done' - >>> production.cost == Decimal('100') - True + >>> production.cost + Decimal('100.0000') diff --git a/tests/test_production_operation.py b/tests/test_production_operation.py index 171f447..e56b439 100644 --- a/tests/test_production_operation.py +++ b/tests/test_production_operation.py @@ -5,7 +5,7 @@ import unittest import doctest import trytond.tests.test_tryton from trytond.tests.test_tryton import ModuleTestCase -from trytond.tests.test_tryton import doctest_setup, doctest_teardown +from trytond.tests.test_tryton import doctest_teardown from trytond.tests.test_tryton import doctest_checker @@ -19,7 +19,7 @@ def suite(): suite.addTests(unittest.TestLoader().loadTestsFromTestCase( ProductionOperationTestCase)) suite.addTests(doctest.DocFileSuite('scenario_production_operation.rst', - setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8', + tearDown=doctest_teardown, encoding='utf-8', checker=doctest_checker, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) return suite diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..ad44320 --- /dev/null +++ b/tox.ini @@ -0,0 +1,18 @@ +[tox] +envlist = {py27,py34,py35,py36}-{sqlite,postgresql,mysql},pypy-{sqlite,postgresql} + +[testenv] +commands = {envpython} setup.py test +deps = + {py27,py34,py35,py36}-postgresql: psycopg2 >= 2.5 + pypy-postgresql: psycopg2cffi >= 2.5 + mysql: MySQL-python + sqlite: sqlitebck +setenv = + sqlite: TRYTOND_DATABASE_URI={env:SQLITE_URI:sqlite://} + postgresql: TRYTOND_DATABASE_URI={env:POSTGRESQL_URI:postgresql://} + mysql: TRYTOND_DATABASE_URI={env:MYSQL_URI:mysql://} + sqlite: DB_NAME={env:SQLITE_NAME::memory:} + postgresql: DB_NAME={env:POSTGRESQL_NAME:test} + mysql: DB_NAME={env:MYSQL_NAME:test} +install_command = pip install --pre --find-links https://trydevpi.tryton.org/ --process-dependency-links {opts} {packages} diff --git a/tryton.cfg b/tryton.cfg index ab3e4db..985af17 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=4.1.0 +version=4.7.0 depends: production_route extras_depend: diff --git a/view/operation_form.xml b/view/operation_form.xml index 597f6d9..c7eb3ef 100644 --- a/view/operation_form.xml +++ b/view/operation_form.xml @@ -1,7 +1,7 @@ -
+