From a922fcbd5de7c153f77de8d5dfd4843f6dd5ab34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80ngel=20=C3=80lvarez=20Serra?= Date: Fri, 17 Jun 2022 08:59:30 +0200 Subject: [PATCH 1/5] add functional field and make uom required by states #048292 --- production.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/production.py b/production.py index ec3d177..b631a7e 100644 --- a/production.py +++ b/production.py @@ -17,7 +17,10 @@ class ProductionTemplate(ModelSQL, ModelView): __name__ = 'production.template' name = fields.Char('Name', required=True) - uom = fields.Many2One('product.uom', 'Uom', required=True) + uom = fields.Many2One('product.uom', 'Uom', + states = { + 'required': True + }) unit_digits = fields.Function(fields.Integer('Unit Digits'), 'on_change_with_unit_digits') quantity = fields.Float('Quantity', @@ -42,6 +45,21 @@ class ProductionTemplate(ModelSQL, ModelView): cost_distribution_templates = fields.One2Many( 'production.cost_price.distribution.template', 'production_template', "Cost Distribution Templates") + inputs_products = fields.Function(fields.One2Many('product.product', None, + 'Products'), 'get_products', searcher='search_input_products') + + def get_products(self, name=None): + products = [] + for template in self.inputs: + products += template.products + return [x.id for x in products] + + @classmethod + def search_input_products(cls, name, clause): + Inputs = Pool().get('production.template.inputs-product.template') + product = clause[-1] + inputs = Inputs.search([('template.products', '=', product)]) + return [('id', 'in', [x.production_template.id for x in inputs])] @fields.depends('uom') def on_change_with_unit_digits(self, name=None): @@ -57,6 +75,8 @@ class ProductionTemplate(ModelSQL, ModelView): record.check_cost_distribution() def check_input_uoms(self): + if not self.uom: + return category_uom = self.uom.category uoms = [i.default_uom.category for i in self.inputs] uoms.append(category_uom) From b27ed16c2db8368cef06f5259ffb23774fad103d Mon Sep 17 00:00:00 2001 From: Jared Esparza Date: Tue, 5 Jul 2022 12:12:00 +0200 Subject: [PATCH 2/5] Modify get_parcel to get the parcel of the current crop and Add check if all the plantations has a parcel in the current crop | #059962 --- locale/ca.po | 8 ++++++++ locale/es.po | 8 ++++++++ message.xml | 3 +++ weighing.py | 19 ++++++++++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/locale/ca.po b/locale/ca.po index 264eabe..8e2d9ff 100644 --- a/locale/ca.po +++ b/locale/ca.po @@ -1544,6 +1544,14 @@ msgstr "" "El pes en \"%(weighing)s\" no està totalment distibuit i no s'ha forçat " "l'anàlisi" +msgctxt "model:ir.message,text:msg_parcel_without_current_crop" +msgid "" +"The plantation \"%(plantation)s\" in the weighing \"%(weighing)s\" has no " +"parcel of the weighing's crop." +msgstr "" +"La plantació \"%(plantation)s\" en la pesada \"%(weighing)s\" no te una " +"parcel·la amb la collita de la pesada" + msgctxt "model:ir.message,text:msg_uom_not_fit" msgid "" "Inputs from Production template \"%(production)s\" must be of uom " diff --git a/locale/es.po b/locale/es.po index 981d356..2c62a45 100644 --- a/locale/es.po +++ b/locale/es.po @@ -1545,6 +1545,14 @@ msgstr "" "El peso en \"%(weighin)s\" no está totalmente distribuido i no se ha forzado" " el anàlisis" +msgctxt "model:ir.message,text:msg_parcel_without_current_crop" +msgid "" +"The plantation \"%(plantation)s\" in the weighing \"%(weighing)s\" has no " +"parcel of the weighing's crop." +msgstr "" +"La plantación \"%(plantation)s\" en la pesada \"%(weighing)s\" no tiene una " +"parcela con la cosecha de la pesada" + msgctxt "model:ir.message,text:msg_uom_not_fit" msgid "" "Inputs from Production template \"%(production)s\" must be of uom " diff --git a/message.xml b/message.xml index 69771d1..e005b29 100644 --- a/message.xml +++ b/message.xml @@ -45,5 +45,8 @@ this repository contains the full copyright notices and license terms. --> The weighing center "%(center)s" dont have a to location configured. + + The plantation "%(plantation)s" in the weighing "%(weighing)s" has no parcel of the weighing's crop. + diff --git a/weighing.py b/weighing.py index 0129578..4957fed 100644 --- a/weighing.py +++ b/weighing.py @@ -206,12 +206,18 @@ class Weighing(Workflow, ModelSQL, ModelView): return crop[0].id def get_parcel(self): + crop = self.on_change_with_crop() if not self.plantations: return plantation = self.plantations[0].plantation if not plantation or not plantation.parcels: return - return plantation.parcels[0] + res = None + for parcel in plantation.parcels: + if parcel.crop.id == crop: + res = parcel + break + return res @fields.depends('plantations') def on_change_with_variety(self): @@ -529,6 +535,17 @@ class Weighing(Workflow, ModelSQL, ModelView): Beneficiary.delete([x for x in weighing.beneficiaries]) parcel = weighing.get_parcel() + + # Check if all plantations has a parcel in the weighing's crop + for plantation in weighing.plantations: + plantation = plantation.plantation + for parcel in plantation.parcels: + if parcel.crop == weighing.crop: + break + else: + raise UserError(gettext('agronomics.msg_parcel_without_current_crop', + weighing=weighing.rec_name, plantation=plantation.code)) + if not parcel: continue From fea88a11983a89d6f746eba8e7b2e6830d3b684d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80ngel=20=C3=80lvarez?= Date: Wed, 6 Jul 2022 10:52:16 +0200 Subject: [PATCH 3/5] do not round if not value #060149 --- quality.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quality.py b/quality.py index 820817b..a404fd5 100644 --- a/quality.py +++ b/quality.py @@ -162,7 +162,8 @@ class QualityTest(metaclass=PoolMeta): if not key: continue - values[key] = round(line.value, _WINE_DIGITS) + if line.value: + values[key] = round(line.value, _WINE_DIGITS) values[key + '_comment'] = line.internal_description values[key + '_confirm'] = today values[key + '_success'] = line.success From 44fb95661ad43db3cbef3389ab2caf3fd2e56e1c Mon Sep 17 00:00:00 2001 From: jared-nan <60256728+jared-nan@users.noreply.github.com> Date: Wed, 20 Jul 2022 09:09:35 +0200 Subject: [PATCH 4/5] Add product agronomics importer | #059877 (#17) --- __init__.py | 3 + importer.py | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tryton.cfg | 1 + 3 files changed, 235 insertions(+) create mode 100644 importer.py diff --git a/__init__.py b/__init__.py index e282cbe..13930a1 100644 --- a/__init__.py +++ b/__init__.py @@ -12,6 +12,7 @@ from . import production from . import location from . import move from . import price_list +from . import importer def register(): Pool.register( @@ -69,6 +70,8 @@ def register(): location.Location, move.Move, price_list.PriceList, + importer.Importer, + importer.ImporterProductAgronomics, module='agronomics', type_='model') Pool.register( production.ProductionCostPriceDistributionTemplateProductionTemplate, diff --git a/importer.py b/importer.py new file mode 100644 index 0000000..7b33cf1 --- /dev/null +++ b/importer.py @@ -0,0 +1,231 @@ +from decimal import Decimal +from trytond.model import ModelView, fields +from trytond.pool import PoolMeta, Pool + + +class ImporterProductAgronomics(ModelView): + 'Importer Product Agronomics' + __name__ = 'importer.product.agronomics' + + template_code = fields.Char('Template Code') + variant_code = fields.Char('Variant Code') + variant_suffix_code = fields.Char('Variant Suffix Code') + name = fields.Char('Name') + description = fields.Char('Description') + uom = fields.Char('UoM') + sale_price = fields.Numeric('Sale Price') + cost_price = fields.Numeric('Cost Price') + type_ = fields.Char('Type') + cost_price_method = fields.Char('Cost Price Method') + supplier = fields.Char('Supplier') + supplier_code = fields.Char('Supplier Code') + categories = fields.Char('Categories') + account_category = fields.Char('Account Category') + weight = fields.Numeric('Weight (kg)') + volume = fields.Numeric('Volume (m3)') + aranzel = fields.Char('Aranzel') + purchasable = fields.Boolean('Purchasable') + salable = fields.Boolean('Salable') + alcohol_content = fields.Char('Alcohol Content') + brand = fields.Char('Brand') + + +class Importer(metaclass=PoolMeta): + __name__ = 'importer' + + @classmethod + def _get_methods(cls): + methods = super()._get_methods() + methods.update({ + 'product_agronomics': { + 'string': 'Product Agronomics', + 'model': 'importer.product.agronomics', + 'chunked': True, + }, + }) + return methods + + @classmethod + def import_product_agronomics(cls, records): + pool = Pool() + Product = pool.get('product.product') + Template = pool.get('product.template') + ProductCategory = pool.get('product.category') + Template = pool.get('product.template') + Uom = pool.get('product.uom') + ProductCostPriceMethod = pool.get('product.cost_price_method') + + try: + ProductSupplier = pool.get('purchase.product_supplier') + Party = pool.get('party.party') + parties = dict((x.code, x) for x in Party.search([])) + except: + parties = {} + + try: + TariffCodeRel = pool.get('product-customs.tariff.code') + TariffCode = pool.get('customs.tariff.code') + customs = dict((x.code, x) for x in TariffCode.search([])) + except: + customs = {} + + try: + Brand = pool.get('product.brand') + brands = dict((x.name, x) for x in Brand.search([])) + except: + brands = {} + + categories = dict((x.name, x) for x in ProductCategory.search([])) + uoms = {} + for uom in Uom.search([]): + uoms[uom.name] = uom + uoms[uom.symbol] = uom + + products = dict((x.code, x) for x in Product.search([ + ('code', '!=', None), + ('code', '!=', ''), + ])) + templates = dict((x.code, x) for x in Template.search([ + ('code', '!=', None), + ('code', '!=', ''), + ])) + + template_default_values = Template.default_get(Template._fields.keys(), + with_rec_name=False) + product_default_values = Product.default_get(Product._fields.keys(), + with_rec_name=False) + cost_price_methods = ProductCostPriceMethod.get_cost_price_methods() + + to_save = [] + products_to_save = [] + for record in records: + product = None + template = None + if record.variant_code: + code = record.variant_code + else: + code = ((record.template_code or '') + + (record.variant_suffix_code or '')) + product = products.get(code) + if product: + template = product.template + elif record.template_code in templates: + template = templates.get(record.template_code) + + if not template: + template = Template(**template_default_values) + template.products = [] + + if not product: + product = Product(**product_default_values) + template.products += (product,) + else: + products_to_save.append(product) + to_save.append(template) + + if record.name: + template.name = record.name + if record.template_code: + template.code = record.template_code + if record.sale_price: + template.list_price = record.sale_price or Decimal(0) + uom = None + if record.uom: + uom = uoms.get(record.uom and record.uom.capitalize() or 'u') + else: + uom = uoms.get('u') + # If we update a product, we dont need to change the uom + if hasattr(product, 'default_uom') and product.default_uom: + uom = None + + if uom: + template.default_uom = uom + if record.cost_price_method: + cost_price_method = record.cost_price_method + for cpm in cost_price_methods: + if cpm[1] == record.cost_price_method: + cost_price_method = cpm[0] + + template.cost_price_method = cost_price_method + + if ('account_category' in template._fields and + record.account_category): + acc_category = categories.get(record.account_category) + if not acc_category: + acc_category = ProductCategory() + acc_category.name = record.account_category + categories[record.account_category] = acc_category + acc_category.accounting = True + template.account_category = acc_category + + if 'weight' in template._fields and record.weight: + template.weight = record.weight + template.weight_uom = uoms.get('kg') + + if 'volume' in template._fields and record.volume: + template.volume = record.volume + template.volume_uom = uoms.get('l') + + if 'tariff_codes' in template._fields and record.aranzel: + custom = customs.get(record.aranzel) + if not customs: + custom = TariffCode() + custom.code = record.aranzel + customs[record.aranzel] = customs + + rel = TariffCodeRel() + rel.tariff_code = custom + template.tariff_codes = [rel] + + # If product exist the categories are set all new, not updated. + if record.categories: + cats = [] + for cat in record.categories.split('|'): + category = categories.get(cat) + if not category and cat: + category = ProductCategory() + category.name = cat + if category: + cats += [category] + categories[cat] = category + template.categories = cats + + if 'product_suppliers' in template._fields and record.purchasable: + template.purchasable = record.purchasable + template.purchase_uom = uom + + if 'salable' in template._fields and record.salable: + template.salable = record.salable + template.sale_uom = uom + + if parties and record.supplier: + party = parties.get(record.supplier) + supplier = ProductSupplier() + supplier.party = party + supplier.code = record.supplier_code + template.product_suppliers = [supplier] + + templates[record.template_code] = template + + if 'brand' in template._fields and record.brand: + brand = brands.get(record.brand) + if not brand: + brand = Brand() + brand.name = record.brand + brands[record.brand] = brand + template.brand = brand + + if record.variant_suffix_code: + product.suffix_code = record.variant_suffix_code + if record.cost_price: + product.cost_price = record.cost_price + if record.description: + product.description = record.description + if ('wine_likely_alcohol_content' in product._fields and + record.alcohol_content): + product.wine_likely_alcohol_content = record.alcohol_content + + ProductCategory.save(categories.values()) + Template.save(to_save) + Product.save(products_to_save) + return to_save diff --git a/tryton.cfg b/tryton.cfg index 9b34b27..415da26 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -12,6 +12,7 @@ depends: production stock account_invoice_line_standalone + importer xml: plot.xml party.xml From dd341b2e99b952082ec56be7ef94eaa1a8e602e0 Mon Sep 17 00:00:00 2001 From: Jared Esparza Date: Wed, 20 Jul 2022 14:28:26 +0200 Subject: [PATCH 5/5] Revert "Add product agronomics importer | #059877 (#17)" This reverts commit 44fb95661ad43db3cbef3389ab2caf3fd2e56e1c. --- __init__.py | 3 - importer.py | 231 ---------------------------------------------------- tryton.cfg | 1 - 3 files changed, 235 deletions(-) delete mode 100644 importer.py diff --git a/__init__.py b/__init__.py index 13930a1..e282cbe 100644 --- a/__init__.py +++ b/__init__.py @@ -12,7 +12,6 @@ from . import production from . import location from . import move from . import price_list -from . import importer def register(): Pool.register( @@ -70,8 +69,6 @@ def register(): location.Location, move.Move, price_list.PriceList, - importer.Importer, - importer.ImporterProductAgronomics, module='agronomics', type_='model') Pool.register( production.ProductionCostPriceDistributionTemplateProductionTemplate, diff --git a/importer.py b/importer.py deleted file mode 100644 index 7b33cf1..0000000 --- a/importer.py +++ /dev/null @@ -1,231 +0,0 @@ -from decimal import Decimal -from trytond.model import ModelView, fields -from trytond.pool import PoolMeta, Pool - - -class ImporterProductAgronomics(ModelView): - 'Importer Product Agronomics' - __name__ = 'importer.product.agronomics' - - template_code = fields.Char('Template Code') - variant_code = fields.Char('Variant Code') - variant_suffix_code = fields.Char('Variant Suffix Code') - name = fields.Char('Name') - description = fields.Char('Description') - uom = fields.Char('UoM') - sale_price = fields.Numeric('Sale Price') - cost_price = fields.Numeric('Cost Price') - type_ = fields.Char('Type') - cost_price_method = fields.Char('Cost Price Method') - supplier = fields.Char('Supplier') - supplier_code = fields.Char('Supplier Code') - categories = fields.Char('Categories') - account_category = fields.Char('Account Category') - weight = fields.Numeric('Weight (kg)') - volume = fields.Numeric('Volume (m3)') - aranzel = fields.Char('Aranzel') - purchasable = fields.Boolean('Purchasable') - salable = fields.Boolean('Salable') - alcohol_content = fields.Char('Alcohol Content') - brand = fields.Char('Brand') - - -class Importer(metaclass=PoolMeta): - __name__ = 'importer' - - @classmethod - def _get_methods(cls): - methods = super()._get_methods() - methods.update({ - 'product_agronomics': { - 'string': 'Product Agronomics', - 'model': 'importer.product.agronomics', - 'chunked': True, - }, - }) - return methods - - @classmethod - def import_product_agronomics(cls, records): - pool = Pool() - Product = pool.get('product.product') - Template = pool.get('product.template') - ProductCategory = pool.get('product.category') - Template = pool.get('product.template') - Uom = pool.get('product.uom') - ProductCostPriceMethod = pool.get('product.cost_price_method') - - try: - ProductSupplier = pool.get('purchase.product_supplier') - Party = pool.get('party.party') - parties = dict((x.code, x) for x in Party.search([])) - except: - parties = {} - - try: - TariffCodeRel = pool.get('product-customs.tariff.code') - TariffCode = pool.get('customs.tariff.code') - customs = dict((x.code, x) for x in TariffCode.search([])) - except: - customs = {} - - try: - Brand = pool.get('product.brand') - brands = dict((x.name, x) for x in Brand.search([])) - except: - brands = {} - - categories = dict((x.name, x) for x in ProductCategory.search([])) - uoms = {} - for uom in Uom.search([]): - uoms[uom.name] = uom - uoms[uom.symbol] = uom - - products = dict((x.code, x) for x in Product.search([ - ('code', '!=', None), - ('code', '!=', ''), - ])) - templates = dict((x.code, x) for x in Template.search([ - ('code', '!=', None), - ('code', '!=', ''), - ])) - - template_default_values = Template.default_get(Template._fields.keys(), - with_rec_name=False) - product_default_values = Product.default_get(Product._fields.keys(), - with_rec_name=False) - cost_price_methods = ProductCostPriceMethod.get_cost_price_methods() - - to_save = [] - products_to_save = [] - for record in records: - product = None - template = None - if record.variant_code: - code = record.variant_code - else: - code = ((record.template_code or '') - + (record.variant_suffix_code or '')) - product = products.get(code) - if product: - template = product.template - elif record.template_code in templates: - template = templates.get(record.template_code) - - if not template: - template = Template(**template_default_values) - template.products = [] - - if not product: - product = Product(**product_default_values) - template.products += (product,) - else: - products_to_save.append(product) - to_save.append(template) - - if record.name: - template.name = record.name - if record.template_code: - template.code = record.template_code - if record.sale_price: - template.list_price = record.sale_price or Decimal(0) - uom = None - if record.uom: - uom = uoms.get(record.uom and record.uom.capitalize() or 'u') - else: - uom = uoms.get('u') - # If we update a product, we dont need to change the uom - if hasattr(product, 'default_uom') and product.default_uom: - uom = None - - if uom: - template.default_uom = uom - if record.cost_price_method: - cost_price_method = record.cost_price_method - for cpm in cost_price_methods: - if cpm[1] == record.cost_price_method: - cost_price_method = cpm[0] - - template.cost_price_method = cost_price_method - - if ('account_category' in template._fields and - record.account_category): - acc_category = categories.get(record.account_category) - if not acc_category: - acc_category = ProductCategory() - acc_category.name = record.account_category - categories[record.account_category] = acc_category - acc_category.accounting = True - template.account_category = acc_category - - if 'weight' in template._fields and record.weight: - template.weight = record.weight - template.weight_uom = uoms.get('kg') - - if 'volume' in template._fields and record.volume: - template.volume = record.volume - template.volume_uom = uoms.get('l') - - if 'tariff_codes' in template._fields and record.aranzel: - custom = customs.get(record.aranzel) - if not customs: - custom = TariffCode() - custom.code = record.aranzel - customs[record.aranzel] = customs - - rel = TariffCodeRel() - rel.tariff_code = custom - template.tariff_codes = [rel] - - # If product exist the categories are set all new, not updated. - if record.categories: - cats = [] - for cat in record.categories.split('|'): - category = categories.get(cat) - if not category and cat: - category = ProductCategory() - category.name = cat - if category: - cats += [category] - categories[cat] = category - template.categories = cats - - if 'product_suppliers' in template._fields and record.purchasable: - template.purchasable = record.purchasable - template.purchase_uom = uom - - if 'salable' in template._fields and record.salable: - template.salable = record.salable - template.sale_uom = uom - - if parties and record.supplier: - party = parties.get(record.supplier) - supplier = ProductSupplier() - supplier.party = party - supplier.code = record.supplier_code - template.product_suppliers = [supplier] - - templates[record.template_code] = template - - if 'brand' in template._fields and record.brand: - brand = brands.get(record.brand) - if not brand: - brand = Brand() - brand.name = record.brand - brands[record.brand] = brand - template.brand = brand - - if record.variant_suffix_code: - product.suffix_code = record.variant_suffix_code - if record.cost_price: - product.cost_price = record.cost_price - if record.description: - product.description = record.description - if ('wine_likely_alcohol_content' in product._fields and - record.alcohol_content): - product.wine_likely_alcohol_content = record.alcohol_content - - ProductCategory.save(categories.values()) - Template.save(to_save) - Product.save(products_to_save) - return to_save diff --git a/tryton.cfg b/tryton.cfg index 415da26..9b34b27 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -12,7 +12,6 @@ depends: production stock account_invoice_line_standalone - importer xml: plot.xml party.xml