From c0b1f15c3d61a0588e110f7982c27e9ded805fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80ngel=20=C3=80lvarez=20Serra?= Date: Fri, 18 Dec 2020 07:32:05 +0100 Subject: [PATCH] Replace all trigger modules related with quality_control (#1) Replace all trigger modules related with quality_control --- __init__.py | 22 ++ party.xml | 12 + production.py | 27 +++ production.xml | 9 + quality.py | 16 +- setup.py | 7 +- stock.py | 74 ++++++ stock.xml | 16 ++ stock_lot.py | 125 ++++++++++ tests/__init__.py | 3 +- tests/scenario_quality_test.rst | 5 +- tests/scenario_quality_test_stock.rst | 217 +++++++++++++++++ tests/scenario_quality_test_stock_lot.rst | 222 ++++++++++++++++++ ...ario_quality_test_stock_lot_production.rst | 183 +++++++++++++++ tests/test_quality_control.py | 15 ++ tryton.cfg | 7 + view/lot_form.xml | 8 + view/party_form.xml | 14 ++ view/quality_template_form.xml | 2 - view/quality_template_tree.xml | 1 - view/stock_template_form.xml | 13 + view/template_production_form.xml | 9 + 22 files changed, 981 insertions(+), 26 deletions(-) create mode 100644 party.xml create mode 100644 production.py create mode 100644 production.xml create mode 100644 stock.py create mode 100644 stock.xml create mode 100644 stock_lot.py create mode 100644 tests/scenario_quality_test_stock.rst create mode 100644 tests/scenario_quality_test_stock_lot.rst create mode 100644 tests/scenario_quality_test_stock_lot_production.rst create mode 100644 view/lot_form.xml create mode 100644 view/party_form.xml create mode 100644 view/stock_template_form.xml create mode 100644 view/template_production_form.xml diff --git a/__init__.py b/__init__.py index 60b2e10..74ad5c9 100644 --- a/__init__.py +++ b/__init__.py @@ -3,6 +3,9 @@ from trytond.pool import Pool from . import configuration from . import quality +from . import stock +from . import stock_lot +from . import production def register(): @@ -22,3 +25,22 @@ def register(): quality.TestLine, quality.QualityTestQualityTemplate, module='quality_control', type_='model') + Pool.register( + stock_lot.Template, + stock_lot.ShipmentIn, + stock_lot.ShipmentOut, + stock_lot.Lot, + stock_lot.QualityTest, + depends=['stock_lot_deactivatable'], + module='quality_control', type_='model') + Pool.register( + stock.Party, + stock.ShipmentIn, + stock.ShipmentOut, + depends=['stock'], + module='quality_control', type_='model') + Pool.register( + production.Template, + production.Production, + depends=['production', 'stock_lot_deactivatable'], + module='quality_control', type_='model') diff --git a/party.xml b/party.xml new file mode 100644 index 0000000..bc375e0 --- /dev/null +++ b/party.xml @@ -0,0 +1,12 @@ + + + + + + party.party + + party_form + + + diff --git a/production.py b/production.py new file mode 100644 index 0000000..0763d41 --- /dev/null +++ b/production.py @@ -0,0 +1,27 @@ +# The COPYRIGHT file at the top level of this repository contains the full +# copyright notices and license terms. +from trytond.pool import PoolMeta +from trytond.model import fields +from .stock_lot import CreateQualityLotTestsMixin + + +class Template(metaclass=PoolMeta): + __name__ = 'product.template' + production_quality_template = fields.Many2One('quality.template', + 'Production Quality Template') + + +class Production(CreateQualityLotTestsMixin, metaclass=PoolMeta): + __name__ = 'production' + + @classmethod + def done(cls, productions): + super().done(productions) + cls.create_lot_quality_tests(productions, 'production') + + def lots_for_quality_tests(self): + return list(set(m.lot for m in self.outputs if m.lot and + m.state == 'done' and + m.product.template.production_quality_template and + not [x for x in m.lot.quality_tests if + m.product.template.production_quality_template in x])) diff --git a/production.xml b/production.xml new file mode 100644 index 0000000..eb0efec --- /dev/null +++ b/production.xml @@ -0,0 +1,9 @@ + + + + product.template + + template_production_form + + + diff --git a/quality.py b/quality.py index c50f631..9f466d2 100644 --- a/quality.py +++ b/quality.py @@ -100,7 +100,6 @@ class Template(ModelSQL, ModelView): active = fields.Boolean('Active', select=True) company = fields.Many2One('company.company', 'Company', required=True, select=True) - document = fields.Reference('Document', selection='get_model') internal_description = fields.Text('Internal Description') external_description = fields.Text('External Description') quantitative_lines = fields.One2Many('quality.quantitative.template.line', @@ -109,17 +108,6 @@ class Template(ModelSQL, ModelView): 'template', 'Qualitative Lines') lines = fields.One2Many('quality.template.line', 'template', 'Lines') - @classmethod - def get_model(cls): - pool = Pool() - ConfigLine = pool.get('quality.configuration.line') - - lines = ConfigLine.search([]) - res = [('', '')] - for line in lines: - res.append((line.document.model, line.document.name)) - return res - @staticmethod def default_active(): return True @@ -665,8 +653,8 @@ class QuantitativeTestLine(sequence_ordered(), ModelSQL, ModelView): res[line.id] = False value = line.value value = Uom.compute_qty(line.unit, value, line.unit_range) - if (value is not None - and value >= line.min_value and value <= line.max_value): + if (value is not None and + value >= line.min_value and value <= line.max_value): res[line.id] = True return res diff --git a/setup.py b/setup.py index e2cbcf6..cbfee6c 100644 --- a/setup.py +++ b/setup.py @@ -66,8 +66,8 @@ setup(name='%s_%s' % (PREFIX, MODULE), 'trytond.modules.%s.tests' % MODULE, ], package_data={ - 'trytond.modules.%s' % MODULE: (info.get('xml', []) - + ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.odt', + 'trytond.modules.%s' % MODULE: (info.get('xml', []) + + ['tryton.cfg', 'view/*.xml', 'locale/*.po', '*.odt', 'icons/*.svg', 'tests/*.rst']), }, classifiers=[ @@ -103,5 +103,4 @@ setup(name='%s_%s' % (PREFIX, MODULE), use_2to3=True, convert_2to3_doctests=[ 'tests/scenario_quality_control.rst', - ], - ) + ],) diff --git a/stock.py b/stock.py new file mode 100644 index 0000000..42d2551 --- /dev/null +++ b/stock.py @@ -0,0 +1,74 @@ +# The COPYRIGHT file at the top level of this repository contains the full +# copyright notices and license terms. +from trytond.pool import PoolMeta, Pool +from trytond.model import fields +from datetime import datetime +from trytond.transaction import Transaction + + +class Party(metaclass=PoolMeta): + __name__ = 'party.party' + + shipment_in_quality_template = fields.Many2One('quality.template', + 'Shipment In Quality Template') + shipment_out_quality_template = fields.Many2One('quality.template', + 'Shipment Out Quality Template') + + +class CreateQualityModelTestsMixin(object): + + @classmethod + def create_model_test(cls, shipments, type_, party_field): + QualityTest = Pool().get('quality.test') + if not shipments: + return + to_save = [] + with Transaction().set_context(_check_access=False): + for shipment in shipments: + party = getattr(shipment, party_field) + used_template = getattr(party, type_ + '_quality_template') + resource = str(shipment) + test = QualityTest( + test_date=datetime.now(), + templates=[used_template], + document=resource) + test.apply_template_values() + to_save.append(test) + + QualityTest.save(to_save) + + +class ShipmentIn(CreateQualityModelTestsMixin, metaclass=PoolMeta): + __name__ = 'stock.shipment.in' + + @classmethod + def shipments_for_quality_test(cls, shipments): + res = [] + for shipment in shipments: + if shipment.supplier.shipment_in_quality_template: + res.append(shipment) + return res + + @classmethod + def receive(cls, shipments): + super().receive(shipments) + to_test = cls.shipments_for_quality_test(shipments) + cls.create_model_test(to_test, 'shipment_in', 'supplier') + + +class ShipmentOut(CreateQualityModelTestsMixin, metaclass=PoolMeta): + __name__ = 'stock.shipment.out' + + @classmethod + def shipments_for_quality_test(cls, shipments): + res = [] + for shipment in shipments: + if shipment.customer.shipment_out_quality_template: + res.append(shipment) + return res + + @classmethod + def pack(cls, shipments): + super().pack(shipments) + to_test = cls.shipments_for_quality_test(shipments) + cls.create_model_test(to_test, 'shipment_out', 'customer') diff --git a/stock.xml b/stock.xml new file mode 100644 index 0000000..12bc2a4 --- /dev/null +++ b/stock.xml @@ -0,0 +1,16 @@ + + + + + stock.lot + + lot_form + + + + product.template + + stock_template_form + + + diff --git a/stock_lot.py b/stock_lot.py new file mode 100644 index 0000000..fdf1d56 --- /dev/null +++ b/stock_lot.py @@ -0,0 +1,125 @@ +# The COPYRIGHT file at the top level of this repository contains the full +# copyright notices and license terms. +from trytond.pool import PoolMeta, Pool +from trytond.model import fields, ModelView, Workflow +from datetime import datetime +from trytond.transaction import Transaction + + +class Template(metaclass=PoolMeta): + __name__ = 'product.template' + shipment_in_quality_template = fields.Many2One('quality.template', + 'Shipment In Quality Template') + shipment_out_quality_template = fields.Many2One('quality.template', + 'Shipment Out Quality Template') + + +class CreateQualityLotTestsMixin(object): + + @classmethod + def create_lot_quality_tests(cls, documents, template): + pool = Pool() + QualityTest = pool.get('quality.test') + StockLot = pool.get('stock.lot') + lot_to_save = [] + + for document in documents: + lots = document.lots_for_quality_tests() + if not lots: + continue + + test_to_save = [] + with Transaction().set_context(_check_access=False): + for lot in lots: + used_template = None + lot.active = False + lot_to_save.append(lot) + + if not template: + continue + used_template = getattr(lot.product.template, + template+'_quality_template') + test = QualityTest( + test_date=datetime.now(), + templates=[used_template], + document=str(lot)) + test.apply_template_values() + test_to_save.append(test) + QualityTest.save(test_to_save) + StockLot.save(lot_to_save) + + +class ShipmentIn(CreateQualityLotTestsMixin, metaclass=PoolMeta): + __name__ = 'stock.shipment.in' + + @classmethod + def receive(cls, shipments): + super().receive(shipments) + cls.create_lot_quality_tests(shipments, 'shipment_in') + + def lots_for_quality_tests(self): + return list(set(m.lot for m in self.incoming_moves if m.lot and + m.state == 'done' and + m.product.template.shipment_in_quality_template and + not [x for x in m.lot.quality_tests if + m.product.template.shipment_in_quality_template in x])) + + +class ShipmentOut(CreateQualityLotTestsMixin, metaclass=PoolMeta): + __name__ = 'stock.shipment.out' + + @classmethod + def pack(cls, shipments): + super().pack(shipments) + cls.create_lot_quality_tests(shipments, 'shipment_out') + + def lots_for_quality_tests(self): + return list(set(m.lot for m in self.outgoing_moves if m.lot and + m.state == 'draft' and + m.product.template.shipment_out_quality_template and + not [x for x in m.lot.quality_tests if + m.product.template.shipment_out_quality_template in x])) + + +class Lot(metaclass=PoolMeta): + __name__ = 'stock.lot' + quality_tests = fields.One2Many('quality.test', 'document', 'Tests', + readonly=True) + + @classmethod + def copy(cls, lots, default=None): + if default is None: + default = {} + default = default.copy() + default['quality_tests'] = None + return super().copy(lots, default) + + +class QualityTest(metaclass=PoolMeta): + __name__ = 'quality.test' + + @classmethod + @ModelView.button + def manager_validate(cls, tests): + super().manager_validate(tests) + cls.lot_active(tests) + + @classmethod + @ModelView.button + @Workflow.transition('draft') + def draft(cls, tests): + super().draft(tests) + cls.lot_active(tests) + + @staticmethod + def lot_active(tests): + StockLot = Pool().get('stock.lot') + to_save = [] + + for test in tests: + if isinstance(test.document, StockLot): + test.document.active = False + if test.state == 'successful': + test.document.active = True + to_save.append(test.document) + StockLot.save(to_save) diff --git a/tests/__init__.py b/tests/__init__.py index fa42daf..6844df5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,7 +1,8 @@ # The COPYRIGHT file at the top level of this repository contains the full # copyright notices and license terms. try: - from trytond.modules.quality_control.tests.test_quality_control import suite + from (trytond.modules.quality_control.tests.test_quality_control + import suite) except ImportError: from .test_quality_control import suite diff --git a/tests/scenario_quality_test.rst b/tests/scenario_quality_test.rst index 60260f6..21cddca 100644 --- a/tests/scenario_quality_test.rst +++ b/tests/scenario_quality_test.rst @@ -28,15 +28,13 @@ Create product:: >>> unit, = ProductUom.find([('name', '=', 'Unit')]) >>> ProductTemplate = Model.get('product.template') >>> Product = Model.get('product.product') - >>> product = Product() >>> template = ProductTemplate() >>> template.name = 'product' >>> template.default_uom = unit >>> template.type = 'service' >>> template.list_price = Decimal('40') >>> template.save() - >>> product.template = template - >>> product.save() + >>> product, = template.products Create Quality Configuration:: @@ -86,7 +84,6 @@ Create Template, Template1:: >>> Template = Model.get('quality.template') >>> template=Template() >>> template.name = 'Template 1' - >>> template.document = product >>> template.internal_description='Internal description' >>> template.external_description='External description' >>> QlTemplateLine = Model.get('quality.qualitative.template.line') diff --git a/tests/scenario_quality_test_stock.rst b/tests/scenario_quality_test_stock.rst new file mode 100644 index 0000000..57cf924 --- /dev/null +++ b/tests/scenario_quality_test_stock.rst @@ -0,0 +1,217 @@ +======================== +Quality Control Scenario +======================== + +Imports:: + >>> import datetime + >>> from dateutil.relativedelta import relativedelta + >>> from decimal import Decimal + >>> from operator import attrgetter + >>> 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() + +Install quality_test module:: + + >>> config = activate_modules(['stock', 'quality_control']) + +Create company:: + + >>> _ = create_company() + >>> company = get_company() + +Create supplier:: + + >>> Party = Model.get('party.party') + >>> supplier = Party(name='Supplier') + >>> supplier.save() + >>> customer = Party(name='Customer') + >>> customer.save() + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> unit, = ProductUom.find([('name', '=', 'Unit')]) + >>> ProductTemplate = Model.get('product.template') + >>> Product = Model.get('product.product') + >>> template = ProductTemplate() + >>> template.name = 'product' + >>> template.default_uom = unit + >>> template.type = 'goods' + >>> template.list_price = Decimal('40') + >>> template.save() + >>> product, = template.products + +Create Quality Configuration:: + + >>> Sequence = Model.get('ir.sequence') + >>> Configuration = Model.get('quality.configuration') + >>> IrModel = Model.get('ir.model') + >>> sequence, = Sequence.find([('code', '=', 'quality.test')]) + >>> configuration = Configuration(1) + >>> config_line = configuration.allowed_documents.new() + >>> config_line.quality_sequence = sequence + >>> allowed_doc, = IrModel.find([('model','=','stock.shipment.in')]) + >>> config_line.document = allowed_doc + >>> config_line = configuration.allowed_documents.new() + >>> config_line.quality_sequence = sequence + >>> allowed_doc2, = IrModel.find([('model','=','stock.shipment.out')]) + >>> config_line.document = allowed_doc2 + >>> configuration.save() + +Create Qualitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> QualityValue = Model.get('quality.qualitative.value') + >>> Method = Model.get('quality.proof.method') + >>> val1 = QualityValue(name='Val1') + >>> val2 = QualityValue(name='Val2') + >>> qlproof = Proof(name='Qualitative Proof', type='qualitative') + >>> method1 = Method(name='Method 1') + >>> qlproof.methods.append(method1) + >>> method1.possible_values.append(val1) + >>> method1.possible_values.append(val2) + >>> qlproof.save() + +Create Quantitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> Method = Model.get('quality.proof.method') + >>> qtproof = Proof(name='Quantitative Proof', type='quantitative') + >>> method2 = Method(name='Method 2') + >>> qtproof.methods.append(method2) + >>> qtproof.save() + +Look For Values:: + + >>> method1, = Method.find([('name', '=', 'Method 1')]) + >>> method2, = Method.find([('name', '=', 'Method 2')]) + >>> val1, = QualityValue.find([('name','=','Val1')]) + >>> val2, = QualityValue.find([('name','=','Val2')]) + +Create Template, Template1:: + + >>> Template = Model.get('quality.template') + >>> template=Template() + >>> template.name = 'Template 1' + >>> template.internal_description='Internal description' + >>> template.external_description='External description' + >>> QlTemplateLine = Model.get('quality.qualitative.template.line') + >>> ql_line = QlTemplateLine() + >>> template.qualitative_lines.append(ql_line) + >>> ql_line.name = 'Line1' + >>> ql_line.sequence = 1 + >>> ql_line.proof = qlproof + >>> ql_line.method = method1 + >>> ql_line.valid_value = val1 + >>> ql_line.internal_description = 'quality line intenal description' + >>> ql_line.external_description = 'quality line external description' + >>> QtTemplateLine = Model.get('quality.quantitative.template.line') + >>> qt_line = QtTemplateLine() + >>> qt_line.name = 'Quantitative Line' + >>> qt_line.sequence = 1 + >>> qt_line.proof = qtproof + >>> qt_line.method = method2 + >>> qt_line.unit = unit + >>> qt_line.internal_description = 'quality line intenal description' + >>> qt_line.external_description = 'quality line external description' + >>> qt_line.min_value = Decimal('1.00') + >>> qt_line.max_value = Decimal('2.00') + >>> template.quantitative_lines.append(qt_line) + >>> template.save() + >>> template.reload() + +Assign Template to Supplier:: + + >>> supplier.shipment_in_quality_template = template + >>> supplier.save() + >>> customer.shipment_out_quality_template = template + >>> customer.save() + + +Get stock locations and create new internal location:: + + >>> Location = Model.get('stock.location') + >>> warehouse_loc, = Location.find([('code', '=', 'WH')]) + >>> supplier_loc, = Location.find([('code', '=', 'SUP')]) + >>> customer_loc, = Location.find([('code', '=', 'CUS')]) + >>> input_loc, = Location.find([('code', '=', 'IN')]) + >>> output_loc, = Location.find([('code', '=', 'OUT')]) + >>> storage_loc, = Location.find([('code', '=', 'STO')]) + >>> internal_loc = Location() + >>> internal_loc.name = 'Internal Location' + >>> internal_loc.code = 'INT' + >>> internal_loc.type = 'storage' + >>> internal_loc.parent = storage_loc + >>> internal_loc.save() + +Create Shipment In:: + + >>> ShipmentIn = Model.get('stock.shipment.in') + >>> shipment_in = ShipmentIn() + >>> shipment_in.planned_date = today + >>> shipment_in.supplier = supplier + >>> shipment_in.warehouse = warehouse_loc + +Add three shipment lines of product 1:: + + >>> StockMove = Model.get('stock.move') + >>> move = shipment_in.incoming_moves.new() + >>> move.product = product + >>> move.uom = unit + >>> move.quantity = 1 + >>> move.from_location = supplier_loc + >>> move.to_location = input_loc + >>> move.unit_price = Decimal('1') + >>> shipment_in.save() + +Receive products:: + + >>> ShipmentIn.receive([shipment_in.id], config.context) + >>> shipment_in.reload() + >>> shipment_in.state + 'received' + +Check the created Quality Tests:: + + >>> QualityTest = Model.get('quality.test') + >>> tests_in, = QualityTest.find([]) + >>> tests_in.document == shipment_in + True + +Create Shipment out:: + + >>> ShipmentOut = Model.get('stock.shipment.out') + >>> shipment_out = ShipmentOut() + >>> shipment_out.planned_date = today + >>> shipment_out.customer = customer + >>> shipment_out.warehouse = warehouse_loc + +Add three shipment lines of product 1:: + + >>> StockMove = Model.get('stock.move') + >>> move = shipment_out.outgoing_moves.new() + >>> move.product = product + >>> move.uom = unit + >>> move.quantity = 1 + >>> move.from_location = supplier_loc + >>> move.to_location = input_loc + >>> move.unit_price = Decimal('1') + >>> shipment_out.save() + +Receive products:: + + >>> shipment_out.click('wait') + >>> a = shipment_out.click('assign_try') + >>> shipment_out.reload() + >>> shipment_out.click('pack') + + +Check the created Quality Tests:: + + >>> QualityTest = Model.get('quality.test') + >>> tests_in, test_out = QualityTest.find([]) + >>> test_out.document == shipment_out + True diff --git a/tests/scenario_quality_test_stock_lot.rst b/tests/scenario_quality_test_stock_lot.rst new file mode 100644 index 0000000..34d4375 --- /dev/null +++ b/tests/scenario_quality_test_stock_lot.rst @@ -0,0 +1,222 @@ +======================== +Quality Control Scenario +======================== + +Imports:: + >>> import datetime + >>> from dateutil.relativedelta import relativedelta + >>> from decimal import Decimal + >>> from operator import attrgetter + >>> 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() + +Install quality_test module:: + + >>> config = activate_modules(['stock_lot_deactivatable', 'quality_control']) + +Create company:: + + >>> _ = create_company() + >>> company = get_company() + + +Create supplier:: + + >>> Party = Model.get('party.party') + >>> supplier = Party(name='Supplier') + >>> supplier.save() + >>> customer = Party(name='Customer') + >>> customer.save() + + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> unit, = ProductUom.find([('name', '=', 'Unit')]) + >>> ProductTemplate = Model.get('product.template') + >>> product_template = ProductTemplate() + >>> product_template.name = 'product' + >>> product_template.default_uom = unit + >>> product_template.type = 'goods' + >>> product_template.list_price = Decimal('40') + >>> product_template.save() + >>> product, = product_template.products + +Create Quality Configuration:: + + >>> Sequence = Model.get('ir.sequence') + >>> Configuration = Model.get('quality.configuration') + >>> IrModel = Model.get('ir.model') + >>> sequence, = Sequence.find([('code', '=', 'quality.test')]) + >>> configuration = Configuration(1) + >>> config_line = configuration.allowed_documents.new() + >>> config_line.quality_sequence = sequence + >>> allowed_doc, = IrModel.find([('model','=','stock.lot')]) + >>> config_line.document = allowed_doc + >>> configuration.save() + +Create Qualitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> QualityValue = Model.get('quality.qualitative.value') + >>> Method = Model.get('quality.proof.method') + >>> val1 = QualityValue(name='Val1') + >>> val2 = QualityValue(name='Val2') + >>> qlproof = Proof(name='Qualitative Proof', type='qualitative') + >>> method1 = Method(name='Method 1') + >>> qlproof.methods.append(method1) + >>> method1.possible_values.append(val1) + >>> method1.possible_values.append(val2) + >>> qlproof.save() + +Create Quantitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> Method = Model.get('quality.proof.method') + >>> qtproof = Proof(name='Quantitative Proof', type='quantitative') + >>> method2 = Method(name='Method 2') + >>> qtproof.methods.append(method2) + >>> qtproof.save() + +Look For Values:: + + >>> method1, = Method.find([('name', '=', 'Method 1')]) + >>> method2, = Method.find([('name', '=', 'Method 2')]) + >>> val1, = QualityValue.find([('name','=','Val1')]) + >>> val2, = QualityValue.find([('name','=','Val2')]) + +Create Template, Template1:: + + >>> Template = Model.get('quality.template') + >>> template=Template() + >>> template.name = 'Template 1' + >>> template.internal_description='Internal description' + >>> template.external_description='External description' + >>> QlTemplateLine = Model.get('quality.qualitative.template.line') + >>> ql_line = QlTemplateLine() + >>> template.qualitative_lines.append(ql_line) + >>> ql_line.name = 'Line1' + >>> ql_line.sequence = 1 + >>> ql_line.proof = qlproof + >>> ql_line.method = method1 + >>> ql_line.valid_value = val1 + >>> ql_line.internal_description = 'quality line intenal description' + >>> ql_line.external_description = 'quality line external description' + >>> QtTemplateLine = Model.get('quality.quantitative.template.line') + >>> qt_line = QtTemplateLine() + >>> qt_line.name = 'Quantitative Line' + >>> qt_line.sequence = 1 + >>> qt_line.proof = qtproof + >>> qt_line.method = method2 + >>> qt_line.unit = unit + >>> qt_line.internal_description = 'quality line intenal description' + >>> qt_line.external_description = 'quality line external description' + >>> qt_line.min_value = Decimal('1.00') + >>> qt_line.max_value = Decimal('2.00') + >>> template.quantitative_lines.append(qt_line) + >>> template.save() + >>> template.reload() + +Assign Template to Product:: + + >>> product_template.shipment_in_quality_template = template + >>> product_template.shipment_out_quality_template = template + >>> product_template.save() + + +Get stock locations and create new internal location:: + + >>> Location = Model.get('stock.location') + >>> warehouse_loc, = Location.find([('code', '=', 'WH')]) + >>> supplier_loc, = Location.find([('code', '=', 'SUP')]) + >>> customer_loc, = Location.find([('code', '=', 'CUS')]) + >>> input_loc, = Location.find([('code', '=', 'IN')]) + >>> output_loc, = Location.find([('code', '=', 'OUT')]) + >>> storage_loc, = Location.find([('code', '=', 'STO')]) + >>> internal_loc = Location() + >>> internal_loc.name = 'Internal Location' + >>> internal_loc.code = 'INT' + >>> internal_loc.type = 'storage' + >>> internal_loc.parent = storage_loc + >>> internal_loc.save() + +Create Shipment In:: + + >>> ShipmentIn = Model.get('stock.shipment.in') + >>> shipment_in = ShipmentIn() + >>> shipment_in.planned_date = today + >>> shipment_in.supplier = supplier + >>> shipment_in.warehouse = warehouse_loc + +Add three shipment lines of product 1:: + + >>> StockMove = Model.get('stock.move') + >>> Lot = Model.get('stock.lot') + >>> lot = Lot() + >>> lot.number = '1' + >>> lot.product = product + >>> lot.save() + >>> move = shipment_in.incoming_moves.new() + >>> move.product = product + >>> move.uom = unit + >>> move.quantity = 1 + >>> move.lot = lot + >>> move.from_location = supplier_loc + >>> move.to_location = input_loc + >>> move.unit_price = Decimal('1') + >>> shipment_in.save() + +Receive products:: + + >>> shipment_in.click('receive') + >>> shipment_in.reload() + >>> shipment_in.state + 'received' + +Check the created Quality Tests:: + + >>> QualityTest = Model.get('quality.test') + >>> tests_in, = QualityTest.find([]) + >>> tests_in.document == lot + True + + +Create Shipment out:: + + >>> ShipmentOut = Model.get('stock.shipment.out') + >>> shipment_out = ShipmentOut() + >>> shipment_out.planned_date = today + >>> shipment_out.customer = customer + >>> shipment_out.warehouse = warehouse_loc + >>> shipment_out.company = company + +Add shipment lines of product 1:: + + >>> StockMove = Model.get('stock.move') + >>> shipment_out.outgoing_moves.extend([StockMove()]) + >>> for move in shipment_out.outgoing_moves: + ... move.product = product + ... move.lot = lot + ... move.uom = unit + ... move.quantity = 1 + ... move.from_location = output_loc + ... move.to_location = customer_loc + ... move.unit_price = Decimal('1') + ... move.currency = company.currency + >>> shipment_out.save() + +Receive products:: + + >>> a = shipment_out.click('assign_try') + >>> shipment_out.reload() + >>> shipment_out.click('pack') + +Check the created Quality Tests:: + + >>> QualityTest = Model.get('quality.test') + >>> tests_in,test_out = QualityTest.find([]) + >>> test_out.document == lot + True diff --git a/tests/scenario_quality_test_stock_lot_production.rst b/tests/scenario_quality_test_stock_lot_production.rst new file mode 100644 index 0000000..117e4f7 --- /dev/null +++ b/tests/scenario_quality_test_stock_lot_production.rst @@ -0,0 +1,183 @@ +======================== +Quality Control Scenario +======================== + +Imports:: + >>> import datetime + >>> from dateutil.relativedelta import relativedelta + >>> from decimal import Decimal + >>> from operator import attrgetter + >>> 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() + +Install quality_test module:: + + >>> config = activate_modules(['production', 'stock_lot_deactivatable', + ... 'quality_control']) + +Create company:: + + >>> _ = create_company() + >>> company = get_company() + + +Create supplier:: + + >>> Party = Model.get('party.party') + >>> supplier = Party(name='Supplier') + >>> supplier.save() + >>> customer = Party(name='Customer') + >>> customer.save() + + +Create product:: + + >>> ProductUom = Model.get('product.uom') + >>> unit, = ProductUom.find([('name', '=', 'Unit')]) + >>> ProductTemplate = Model.get('product.template') + >>> product_template = ProductTemplate() + >>> product_template.name = 'product' + >>> product_template.default_uom = unit + >>> product_template.type = 'goods' + >>> product_template.producible = True + >>> product_template.list_price = Decimal('40') + >>> product_template.save() + >>> product, = product_template.products + +Create Quality Configuration:: + + >>> Sequence = Model.get('ir.sequence') + >>> Configuration = Model.get('quality.configuration') + >>> IrModel = Model.get('ir.model') + >>> sequence, = Sequence.find([('code', '=', 'quality.test')]) + >>> configuration = Configuration(1) + >>> config_line = configuration.allowed_documents.new() + >>> config_line.quality_sequence = sequence + >>> allowed_doc, = IrModel.find([('model','=','stock.lot')]) + >>> config_line.document = allowed_doc + >>> configuration.save() + +Create Qualitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> QualityValue = Model.get('quality.qualitative.value') + >>> Method = Model.get('quality.proof.method') + >>> val1 = QualityValue(name='Val1') + >>> val2 = QualityValue(name='Val2') + >>> qlproof = Proof(name='Qualitative Proof', type='qualitative') + >>> method1 = Method(name='Method 1') + >>> qlproof.methods.append(method1) + >>> method1.possible_values.append(val1) + >>> method1.possible_values.append(val2) + >>> qlproof.save() + +Create Quantitative Proof:: + + >>> Proof = Model.get('quality.proof') + >>> Method = Model.get('quality.proof.method') + >>> qtproof = Proof(name='Quantitative Proof', type='quantitative') + >>> method2 = Method(name='Method 2') + >>> qtproof.methods.append(method2) + >>> qtproof.save() + +Look For Values:: + + >>> method1, = Method.find([('name', '=', 'Method 1')]) + >>> method2, = Method.find([('name', '=', 'Method 2')]) + >>> val1, = QualityValue.find([('name','=','Val1')]) + >>> val2, = QualityValue.find([('name','=','Val2')]) + +Create Template, Template1:: + + >>> Template = Model.get('quality.template') + >>> template=Template() + >>> template.name = 'Template 1' + >>> template.internal_description='Internal description' + >>> template.external_description='External description' + >>> QlTemplateLine = Model.get('quality.qualitative.template.line') + >>> ql_line = QlTemplateLine() + >>> template.qualitative_lines.append(ql_line) + >>> ql_line.name = 'Line1' + >>> ql_line.sequence = 1 + >>> ql_line.proof = qlproof + >>> ql_line.method = method1 + >>> ql_line.valid_value = val1 + >>> ql_line.internal_description = 'quality line intenal description' + >>> ql_line.external_description = 'quality line external description' + >>> QtTemplateLine = Model.get('quality.quantitative.template.line') + >>> qt_line = QtTemplateLine() + >>> qt_line.name = 'Quantitative Line' + >>> qt_line.sequence = 1 + >>> qt_line.proof = qtproof + >>> qt_line.method = method2 + >>> qt_line.unit = unit + >>> qt_line.internal_description = 'quality line intenal description' + >>> qt_line.external_description = 'quality line external description' + >>> qt_line.min_value = Decimal('1.00') + >>> qt_line.max_value = Decimal('2.00') + >>> template.quantitative_lines.append(qt_line) + >>> template.save() + >>> template.reload() + +Assign Template to Product:: + + >>> product_template.production_quality_template = template + >>> product_template.save() + + +Get stock locations and create new internal location:: + + >>> Location = Model.get('stock.location') + >>> warehouse_loc, = Location.find([('code', '=', 'WH')]) + >>> supplier_loc, = Location.find([('code', '=', 'SUP')]) + >>> customer_loc, = Location.find([('code', '=', 'CUS')]) + >>> input_loc, = Location.find([('code', '=', 'IN')]) + >>> output_loc, = Location.find([('code', '=', 'OUT')]) + >>> storage_loc, = Location.find([('code', '=', 'STO')]) + >>> production_loc, = Location.find([('code', '=', 'PROD')]) + >>> internal_loc = Location() + >>> internal_loc.name = 'Internal Location' + >>> internal_loc.code = 'INT' + >>> internal_loc.type = 'storage' + >>> internal_loc.parent = storage_loc + >>> internal_loc.save() + + +Make a production:: + + >>> Lot = Model.get('stock.lot') + >>> lot = Lot() + >>> lot.number = '1' + >>> lot.product = product + >>> lot.save() + >>> StockMove = Model.get('stock.move') + >>> Production = Model.get('production') + >>> production = Production() + >>> production.planned_date = today + >>> production.product = product + >>> production.quantity = 2 + >>> production.outputs.extend([StockMove()]) + >>> for move in production.outputs: + ... move.product = product + ... move.lot = lot + ... move.uom = unit + ... move.quantity = 1 + ... move.from_location = production_loc + ... move.to_location = storage_loc + ... move.unit_price = Decimal('1') + ... move.currency = company.currency + >>> production.save() + >>> production.click('wait') + >>> a = production.click('assign_try') + >>> production.click('run') + >>> production.click('done') + +Check the created Quality Tests:: + + >>> QualityTest = Model.get('quality.test') + >>> test, = QualityTest.find([]) + >>> test.document == lot + True diff --git a/tests/test_quality_control.py b/tests/test_quality_control.py index 3bc1136..8190e3c 100644 --- a/tests/test_quality_control.py +++ b/tests/test_quality_control.py @@ -17,6 +17,21 @@ class TestCase(ModuleTestCase): def suite(): suite = trytond.tests.test_tryton.suite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase)) + suite.addTests(doctest.DocFileSuite( + 'scenario_quality_test_stock_lot_production.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) + suite.addTests(doctest.DocFileSuite( + 'scenario_quality_test_stock_lot.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) + suite.addTests(doctest.DocFileSuite( + 'scenario_quality_test_stock.rst', + tearDown=doctest_teardown, encoding='utf-8', + checker=doctest_checker, + optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)) suite.addTests(doctest.DocFileSuite( 'scenario_quality_test.rst', tearDown=doctest_teardown, encoding='utf-8', diff --git a/tryton.cfg b/tryton.cfg index e186f9b..ff260af 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -7,6 +7,13 @@ depends: product ir res +extras_depend: + stock + stock_lot_deactivatable + production xml: quality.xml + stock.xml + production.xml configuration.xml + party.xml diff --git a/view/lot_form.xml b/view/lot_form.xml new file mode 100644 index 0000000..6de45c3 --- /dev/null +++ b/view/lot_form.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/view/party_form.xml b/view/party_form.xml new file mode 100644 index 0000000..18a743b --- /dev/null +++ b/view/party_form.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/view/quality_template_form.xml b/view/quality_template_form.xml index 4f948f5..186227c 100644 --- a/view/quality_template_form.xml +++ b/view/quality_template_form.xml @@ -8,8 +8,6 @@ contains the full copyright notices and license terms. -->