Cost distribution (#5)

* Add feauture of Cost distribution #045169
This commit is contained in:
Raimon Esteve 2021-10-19 08:19:06 +02:00 committed by Àngel Àlvarez
parent a3bd48ccd4
commit 6231a6153b
14 changed files with 862 additions and 39 deletions

View File

@ -1,4 +1,4 @@
# This file is part carviresa module for Tryton.
# This file is part agronomics module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
from trytond.pool import Pool
@ -44,8 +44,13 @@ def register():
production.Production,
production.OutputDistribution,
production.ProductionEnologyProduct,
production.ProductionCostPriceDistribution,
# production.ProductionProductionCostPriceDistribution,
production.ProductionCostPriceDistributionTemplate,
production.ProductionCostPriceDistributionTemplateProductionTemplateAsk,
module='agronomics', type_='model')
Pool.register(
production.ProductionCostPriceDistributionTemplateProductionTemplate,
module='agronomics', type_='wizard')
Pool.register(
module='agronomics', type_='report')

View File

@ -372,7 +372,7 @@ msgstr "Necesita mostres"
msgctxt "field:product.product,production_quality_template:"
msgid "Production Quality Template"
msgstr ""
msgstr "Plantilla Qualitat de producció"
msgctxt "field:product.product,quality_sample:"
msgid "Quality Sample"
@ -838,6 +838,18 @@ msgctxt "field:production,allowed_output_products:"
msgid "Allowed Output Products"
msgstr "Productes permesos a la sortida"
msgctxt "field:production,cost_distribution_template:"
msgid "Cost Distribution Template"
msgstr "Plantilla distribució de costos"
msgctxt "field:production,cost_distribution_templates:"
msgid "Cost Product Templates"
msgstr "Plantilla cost del producte"
msgctxt "field:production,cost_distributions:"
msgid "Cost Distributions"
msgstr "Distribució de costos"
msgctxt "field:production,enology_products:"
msgid "Enology Products"
msgstr "Productes Vinícules"
@ -850,6 +862,45 @@ msgctxt "field:production,production_template:"
msgid "Production Template"
msgstr "Plantilla de producció"
msgctxt "field:production,production_template_cost_distribution_templates:"
msgid "Cost Distribution Templates"
msgstr "Plantilla distribució costos"
msgctxt "field:production.cost_price.distribution,origin:"
msgid "Origin"
msgstr "Origen"
msgctxt "field:production.cost_price.distribution,percentatge:"
msgid "Percentatge"
msgstr "Percentatge"
msgctxt "field:production.cost_price.distribution,template:"
msgid "Template"
msgstr "Plantilla"
msgctxt ""
"field:production.cost_price.distribution.template,cost_distribution_templates:"
msgid "Cost Distribution"
msgstr "Distribució de costos"
msgctxt "field:production.cost_price.distribution.template,name:"
msgid "Name"
msgstr "Nom"
msgctxt ""
"field:production.cost_price.distribution.template,production_template:"
msgid "Production Template"
msgstr "Plantilla de producció"
msgctxt ""
"field:production.cost_price.distribution.template.ask,cost_distribution_templates:"
msgid "Cost Distributions"
msgstr "Distribució de costos"
msgctxt "field:production.cost_price.distribution.template.ask,name:"
msgid "Name"
msgstr "Nom"
msgctxt "field:production.enology.product,product:"
msgid "Product"
msgstr "Productes"
@ -878,6 +929,10 @@ msgctxt "field:production.output.distribution,initial_quantity:"
msgid "Initial Quantity"
msgstr "Quantitat inicial"
msgctxt "field:production.output.distribution,initial_quantity_readonly:"
msgid "Initial Quantity"
msgstr "Quantitat inicial"
msgctxt "field:production.output.distribution,location:"
msgid "Location"
msgstr "Ubicació"
@ -894,6 +949,10 @@ msgctxt "field:production.output.distribution,production:"
msgid "Production"
msgstr "Producció"
msgctxt "field:production.output.distribution,production_state:"
msgid "State"
msgstr "Estat"
msgctxt "field:production.output.distribution,unit_digits:"
msgid "Unit Digits"
msgstr "Dígits de la unitat"
@ -902,8 +961,16 @@ msgctxt "field:production.output.distribution,uom:"
msgid "Uom"
msgstr "UdM"
msgctxt "field:production.template,cost_distribution_template:"
msgid "Default cost distribution template"
msgstr "Plantilla distribució de cost per defecte"
msgctxt "field:production.template,cost_distribution_templates:"
msgid "Cost Distribution Templates"
msgstr "Plantilla de distribucció de costos"
msgctxt "field:production.template,enology_products:"
msgid "Production Template"
msgid "Complementary Products"
msgstr "Plantilla de producció"
msgctxt "field:production.template,inputs:"
@ -1100,13 +1167,21 @@ msgctxt "model:ir.action,name:act_product_quantitative_test_lines"
msgid "Quantitative Lines"
msgstr "Línia quantitativa"
msgctxt "model:ir.action,name:act_production_cost_distribution_template_tree"
msgid "Templates Cost Price Distribution"
msgstr "Plantilles Distribució de cost"
msgctxt "model:ir.action,name:act_production_cost_price_distribution_tree"
msgid "Cost Price Distribution"
msgstr "Preus de la Distribució de costos"
msgctxt "model:ir.action,name:act_production_enology_product_tree"
msgid "Production Enology Product"
msgstr "Productes Vinícules"
msgctxt "model:ir.action,name:act_production_output_distribution_tree"
msgid "Production Output Distribution"
msgstr ""
msgstr "Distribució sortida de producció"
msgctxt "model:ir.action,name:act_production_template_line_tree"
msgid "Production Template Line"
@ -1124,6 +1199,11 @@ msgctxt "model:ir.action,name:act_weighing_center_action"
msgid "Weighing Center"
msgstr "Centre de pesada"
msgctxt ""
"model:ir.action,name:wizard_create_cost_price_distribution_from_production"
msgid "Create Cost Price Distribution"
msgstr "Crear Distribució de costos"
msgctxt "model:ir.action.act_window.domain,name:act_weighing_domain_all"
msgid "All"
msgstr "Tots"
@ -1149,10 +1229,41 @@ msgstr ""
"Els Beneficiares de les collites \"%(crop)s\" i la plantació "
"\"%(plantation)s\" han de sumar 100."
msgctxt "model:ir.message,text:msg_check_cost_distribution"
msgid "The production \"%(production)s\" has same products in cost distribution."
msgstr ""
"La producció \"%(producció)s\" té els mateixos productes en distribució de "
"costos."
msgctxt "model:ir.message,text:msg_check_cost_distribution_template"
msgid ""
"There are some products in cost distribution that has not in outputs in the "
"production \"%(production)s\"."
msgstr ""
"Hi ha alguns productes en distribució de costos que no tenen resultats en la"
" producció \"% (producció) s\"."
msgctxt ""
"model:ir.message,text:msg_check_cost_distribution_template_percentatge"
msgid "Invalid percentatge \"%(percentatge)s\" in \"%(distribution)s\"."
msgstr "Percentatge \"%(percentatge)s\" no vàlid a \"%(distribució)s\"."
msgctxt "model:ir.message,text:msg_check_cost_templates"
msgid ""
"Cost \"%(cost)s\" has template \"%(template)s\" not present in Production "
"Template Outputs\"."
msgstr ""
"Cost \"%(cost)s\" té una \"%(producte)s\" que no està present en les "
"sortides de la plantilla de producció."
msgctxt "model:ir.message,text:msg_check_production_percentatge"
msgid "Invalid percentatge \"%(percentatge)s\" in \"%(production)s\"."
msgstr "Percentatge \"%(percentatge)s\" no vàlid a \"%(producció)s\"."
msgctxt "model:ir.message,text:msg_uom_not_fit"
msgid ""
"Inputs from Production template \"%(producttion)s\" must be of uom "
"\"%(uom)s\" and we have \"%(uoms)s\" ."
"Inputs from Production template \"%(production)s\" must be of uom "
"\"%(uom)s\" and we have \"%(uoms)s\"."
msgstr ""
"Les entrades de la plantilla de producció \"%(production)s\" ha de tenir la "
"uom \"%(uom)s\" i ens trobem \"%(uoms)\"."
@ -1201,6 +1312,10 @@ msgctxt "model:ir.sequence.type,name:sequence_type_weighing"
msgid "Weighing"
msgstr "Pesada"
msgctxt "model:ir.ui.menu,name:menu_act_production_cost_distribution_template"
msgid "Templates Cost Price Distribution"
msgstr "Plantilla distribució de preus de cost"
msgctxt "model:ir.ui.menu,name:menu_agronomics"
msgid "Agronomics"
msgstr "Agronomics"
@ -1281,6 +1396,19 @@ msgctxt "model:product.variety,name:"
msgid "Product Variety"
msgstr "Varietat"
msgctxt "model:production.cost_price.distribution,name:"
msgid "Production Distribution Cost Price"
msgstr "Distribució preu de cost producció"
msgctxt "model:production.cost_price.distribution.template,name:"
msgid "Production Cost Price Distribution Template"
msgstr "Plantilla de distribució de preus de costos de la producció"
msgctxt "model:production.cost_price.distribution.template.ask,name:"
msgid ""
"Production Cost Price Distribution Template from Production Template Ask"
msgstr ""
msgctxt "model:production.enology.product,name:"
msgid "Production Enology Product"
msgstr "Productes Vinícules"
@ -1589,6 +1717,44 @@ msgctxt "selection:product.template,agronomic_type:"
msgid "Wine"
msgstr "Vi"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Assigned"
msgstr "Reservat"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Cancelled"
msgstr "Cancel·lat"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Done"
msgstr "Realitzat"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Draft"
msgstr "Esborrany"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Request"
msgstr "Sol·licitud"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Running"
msgstr "En execució"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Waiting"
msgstr "En espera"
msgctxt "view:product.product:"
msgid "Agronomics"
msgstr "Agronomics"
msgctxt ""
"wizard_button:production.cost_price.distribution.template.from.production.template,ask,create_cost_distributions:"
msgid "Create"
msgstr "Crea"
msgctxt ""
"wizard_button:production.cost_price.distribution.template.from.production.template,ask,end:"
msgid "Cancel"
msgstr "Cancel·lat"

View File

@ -256,7 +256,7 @@ msgstr "Productos"
msgctxt "field:agronomics.weighing,product_created:"
msgid "Product Created"
msgstr ""
msgstr "Producto creado"
msgctxt "field:agronomics.weighing,purchase_contract:"
msgid "Purchase Contract"
@ -287,7 +287,7 @@ msgid "Weighing Center"
msgstr "Centro de pesada"
msgctxt "field:agronomics.weighing,weighing_date:"
msgid "Sale Date"
msgid "Date"
msgstr "Fecha"
msgctxt "field:agronomics.weighing,weight:"
@ -372,7 +372,7 @@ msgstr "Requiere muestras"
msgctxt "field:product.product,production_quality_template:"
msgid "Production Quality Template"
msgstr ""
msgstr "Plantilla calidad producción"
msgctxt "field:product.product,quality_sample:"
msgid "Quality Sample"
@ -838,6 +838,18 @@ msgctxt "field:production,allowed_output_products:"
msgid "Allowed Output Products"
msgstr "Productos de salida permitidos"
msgctxt "field:production,cost_distribution_template:"
msgid "Cost Distribution Template"
msgstr "Plantilla de distribución de costos"
msgctxt "field:production,cost_distribution_templates:"
msgid "Cost Product Templates"
msgstr "Plantillas de productos de coste"
msgctxt "field:production,cost_distributions:"
msgid "Cost Distributions"
msgstr "Distribución de costos"
msgctxt "field:production,enology_products:"
msgid "Enology Products"
msgstr "Productos vinícolas"
@ -850,6 +862,45 @@ msgctxt "field:production,production_template:"
msgid "Production Template"
msgstr "Plantilla producción"
msgctxt "field:production,production_template_cost_distribution_templates:"
msgid "Cost Distribution Templates"
msgstr "Plantilla de distribución de costos"
msgctxt "field:production.cost_price.distribution,origin:"
msgid "Origin"
msgstr "Origen"
msgctxt "field:production.cost_price.distribution,percentatge:"
msgid "Percentatge"
msgstr ""
msgctxt "field:production.cost_price.distribution,template:"
msgid "Template"
msgstr "Plantilla"
msgctxt ""
"field:production.cost_price.distribution.template,cost_distribution_templates:"
msgid "Cost Distribution"
msgstr "Distribución de costos"
msgctxt "field:production.cost_price.distribution.template,name:"
msgid "Name"
msgstr "Nombre"
msgctxt ""
"field:production.cost_price.distribution.template,production_template:"
msgid "Production Template"
msgstr "Plantilla producción"
msgctxt ""
"field:production.cost_price.distribution.template.ask,cost_distribution_templates:"
msgid "Cost Distributions"
msgstr "Distribución de costos"
msgctxt "field:production.cost_price.distribution.template.ask,name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:production.enology.product,product:"
msgid "Product"
msgstr "Productos"
@ -878,6 +929,10 @@ msgctxt "field:production.output.distribution,initial_quantity:"
msgid "Initial Quantity"
msgstr "Cantidad Inicial"
msgctxt "field:production.output.distribution,initial_quantity_readonly:"
msgid "Initial Quantity"
msgstr "Cantidad Inicial"
msgctxt "field:production.output.distribution,location:"
msgid "Location"
msgstr "Ubicación"
@ -894,6 +949,10 @@ msgctxt "field:production.output.distribution,production:"
msgid "Production"
msgstr "Producciones"
msgctxt "field:production.output.distribution,production_state:"
msgid "State"
msgstr "Estado"
msgctxt "field:production.output.distribution,unit_digits:"
msgid "Unit Digits"
msgstr "Dígitos unidad"
@ -902,6 +961,14 @@ msgctxt "field:production.output.distribution,uom:"
msgid "Uom"
msgstr "UdM"
msgctxt "field:production.template,cost_distribution_template:"
msgid "Default cost distribution templatea"
msgstr "Plantilla de distribución de costos predeterminada"
msgctxt "field:production.template,cost_distribution_templates:"
msgid "Cost Distribution Templates"
msgstr "Plantilla de distribución de costos"
msgctxt "field:production.template,enology_products:"
msgid "Complementary Products"
msgstr "Productos complementarios"
@ -1100,13 +1167,21 @@ msgctxt "model:ir.action,name:act_product_quantitative_test_lines"
msgid "Quantitative Lines"
msgstr "Líneas cuantitativas"
msgctxt "model:ir.action,name:act_production_cost_distribution_template_tree"
msgid "Templates Cost Price Distribution"
msgstr ""
msgctxt "model:ir.action,name:act_production_cost_price_distribution_tree"
msgid "Cost Price Distribution"
msgstr "Distribución de costos"
msgctxt "model:ir.action,name:act_production_enology_product_tree"
msgid "Production Enology Product"
msgstr "Productos Vinícolas"
msgctxt "model:ir.action,name:act_production_output_distribution_tree"
msgid "Production Output Distribution"
msgstr ""
msgstr "Distribución salidas de producción"
msgctxt "model:ir.action,name:act_production_template_line_tree"
msgid "Production Template Line"
@ -1124,6 +1199,11 @@ msgctxt "model:ir.action,name:act_weighing_center_action"
msgid "Weighing Center"
msgstr "Centro de pesada"
msgctxt ""
"model:ir.action,name:wizard_create_cost_price_distribution_from_production"
msgid "Create Cost Price Distribution"
msgstr "Crear distribución de precio de costo"
msgctxt "model:ir.action.act_window.domain,name:act_weighing_domain_all"
msgid "All"
msgstr "Todos"
@ -1149,10 +1229,41 @@ msgstr ""
"Los beneficiarios de la cosecha \"%(crop)s\" y de la plantación "
"\"%(plantation)s\" han de sumar 100."
msgctxt "model:ir.message,text:msg_check_cost_distribution"
msgid "The production \"%(production)s\" has same products in cost distribution."
msgstr ""
"La producción \"%(producción)s\" tiene los mismos productos en la "
"distribución de costos."
msgctxt "model:ir.message,text:msg_check_cost_distribution_template"
msgid ""
"There are some products in cost distribution that has not in outputs in the "
"production \"%(production)s\"."
msgstr ""
"Hay algunos productos en distribución de costos que no tienen salidas en la "
"producción \"%(producción)s\"."
msgctxt ""
"model:ir.message,text:msg_check_cost_distribution_template_percentatge"
msgid "Invalid percentatge \"%(percentatge)s\" in \"%(distribution)s\"."
msgstr "Porcentaje no válido \"%(porcentaje)s\" en \"%(distribución)s\"."
msgctxt "model:ir.message,text:msg_check_cost_templates"
msgid ""
"Cost \"%(cost)s\" has template \"%(template)s\" not present in Production "
"Template Outputs\"."
msgstr ""
"l costo \"%(costo)s\" tiene la plantilla \"%(plantilla)s\" que no está "
"presente en las salidas de la plantilla de producción \". "
msgctxt "model:ir.message,text:msg_check_production_percentatge"
msgid "Invalid percentatge \"%(percentatge)s\" in \"%(production)s\"."
msgstr "Porcentaje no válido \"%(porcentaje)s\" en \"% (distribución) s\"."
msgctxt "model:ir.message,text:msg_uom_not_fit"
msgid ""
"Inputs from Production template \"%(producttion)s\" must be of uom "
"\"%(uom)s\" and we have \"%(uoms)s\" ."
"Inputs from Production template \"%(production)s\" must be of uom "
"\"%(uom)s\" and we have \"%(uoms)s\"."
msgstr ""
"Las entradas de la plantilla de producción solo puede contener productos con"
" uom \"%(uom)s\" i nos encontramos \"%(uoms)s\"."
@ -1201,6 +1312,10 @@ msgctxt "model:ir.sequence.type,name:sequence_type_weighing"
msgid "Weighing"
msgstr "Pesada"
msgctxt "model:ir.ui.menu,name:menu_act_production_cost_distribution_template"
msgid "Templates Cost Price Distribution"
msgstr "Distribución de precios de costes de plantillas"
msgctxt "model:ir.ui.menu,name:menu_agronomics"
msgid "Agronomics"
msgstr "Agronomics"
@ -1279,6 +1394,19 @@ msgstr "Producto - Variedad"
msgctxt "model:product.variety,name:"
msgid "Product Variety"
msgstr "Variedad de producto"
msgctxt "model:production.cost_price.distribution,name:"
msgid "Production Distribution Cost Price"
msgstr ""
msgctxt "model:production.cost_price.distribution.template,name:"
msgid "Production Cost Price Distribution Template"
msgstr "Plantilla de distribución de precios de costos de producción"
msgctxt "model:production.cost_price.distribution.template.ask,name:"
msgid ""
"Production Cost Price Distribution Template from Production Template Ask"
msgstr ""
msgctxt "model:production.enology.product,name:"
@ -1347,7 +1475,7 @@ msgstr ""
msgctxt "model:quality.proof,name:wine_notes"
msgid "Observacions"
msgstr ""
msgstr "Observaciones"
msgctxt "model:quality.proof,name:wine_observing_phase"
msgid "Fase visual"
@ -1443,7 +1571,7 @@ msgstr ""
msgctxt "model:quality.proof.method,name:wine_notes_method"
msgid "Observacions"
msgstr ""
msgstr "Observaciones"
msgctxt "model:quality.proof.method,name:wine_observing_phase_method"
msgid "Fase visual"
@ -1589,10 +1717,48 @@ msgctxt "selection:product.template,agronomic_type:"
msgid "Wine"
msgstr "Vino"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Assigned"
msgstr "Reservado"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Cancelled"
msgstr "Cancelado"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Done"
msgstr "Realizado"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Draft"
msgstr "Esborany"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Request"
msgstr "Solicitud"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Running"
msgstr "En ejecución"
msgctxt "selection:production.output.distribution,production_state:"
msgid "Waiting"
msgstr "En espera"
msgctxt "view:product.product:"
msgid "Agronomics"
msgstr "Agronomics"
msgctxt "view:product.product:"
msgid "Quality"
msgstr ""
msgstr "Calidad"
msgctxt ""
"wizard_button:production.cost_price.distribution.template.from.production.template,ask,create_cost_distributions:"
msgid "Create"
msgstr "Crear"
msgctxt ""
"wizard_button:production.cost_price.distribution.template.from.production.template,ask,end:"
msgid "Cancel"
msgstr "Cancel·lar"

View File

@ -13,7 +13,24 @@ this repository contains the full copyright notices and license terms. -->
<field name="text">Product "%(product)s" cannot have more than one Variety because of its agronomic type.</field>
</record>
<record model="ir.message" id="msg_uom_not_fit">
<field name="text">Inputs from Production template "%(producttion)s" must be of uom "%(uom)s" and we have "%(uoms)s".</field>
<field name="text">Inputs from Production template "%(production)s" must be of uom "%(uom)s" and we have "%(uoms)s".</field>
</record>
<record model="ir.message" id="msg_check_cost_distribution">
<field name="text">The production "%(production)s" has same products in cost distribution.</field>
</record>
<record model="ir.message" id="msg_check_cost_distribution_template">
<field name="text">There are some products in cost distribution that has not in outputs in the production "%(production)s".</field>
</record>
<record model="ir.message" id="msg_check_cost_distribution_template_percentatge">
<field name="text">Invalid percentatge "%(percentatge)s" in "%(distribution)s".</field>
</record>
<record model="ir.message" id="msg_check_production_percentatge">
<field name="text">Invalid percentatge "%(percentatge)s" in "%(production)s".</field>
</record>
<record model="ir.message" id="msg_check_cost_templates">
<field name="text">Cost "%(cost)s" has template "%(template)s" not present in Production Template Outputs".</field>
</record>
</data>
</tryton>

View File

@ -88,7 +88,7 @@ class Parcel(ModelSQL, ModelView):
plantation = fields.Many2One('agronomics.plantation', 'Plantation',
required=True)
crop = fields.Many2One('agronomics.crop', 'Crop', required=True)
product = fields.Many2One('product.template', 'Product', required=True)
product = fields.Many2One('product.template', 'Product') #, required=True)
species = fields.Many2One('product.taxon', 'Spices',
domain=[('rank', '=', 'species')], required=True,
depends=['species'])

View File

@ -5,8 +5,11 @@ from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Bool, If
from trytond.exceptions import UserError
from trytond.i18n import gettext
from decimal import Decimal
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.modules.product import round_price
from trytond.model.exceptions import ValidationError
from decimal import Decimal
class ProductionTemplate(ModelSQL, ModelView):
@ -27,6 +30,15 @@ class ProductionTemplate(ModelSQL, ModelView):
enology_products = fields.One2Many('production.template.line',
'production_template', 'Complementary Products')
pass_feature = fields.Boolean('Pass on Feature')
cost_distribution_template = fields.Many2One(
'production.cost_price.distribution.template',
"Default cost distribution template",
domain=[
('production_template', '=', Eval('id', 0)),
], depends=['id'])
cost_distribution_templates = fields.One2Many(
'production.cost_price.distribution.template',
'production_template', "Cost Distribution Templates")
@fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
@ -34,22 +46,33 @@ class ProductionTemplate(ModelSQL, ModelView):
return self.uom.digits
return 2
@classmethod
def check_input_uoms(cls, records):
for record in records:
category_uom = record.uom.category
uoms = [i.default_uom.category for i in record.inputs]
uoms.append(category_uom)
if len(list(set(uoms))) > 1:
raise UserError(gettext('agronomics.msg_uom_not_fit',
production=record.rec_name,
uom=record.uom.rec_name,
uoms=",".join([x.rec_name for x in set(uoms)])))
@classmethod
def validate(cls, records):
super().validate(records)
cls.check_input_uoms(records)
for record in records:
record.check_input_uoms()
record.check_cost_distribution()
def check_input_uoms(self):
category_uom = self.uom.category
uoms = [i.default_uom.category for i in self.inputs]
uoms.append(category_uom)
if len(list(set(uoms))) > 1:
raise UserError(gettext('agronomics.msg_uom_not_fit',
production=self.rec_name,
uom=self.uom.rec_name,
uoms=",".join([x.rec_name for x in set(uoms)])))
def check_cost_distribution(self):
if not self.cost_distribution_template:
return
output_templates = set([o for o in self.outputs])
for c in self.cost_distribution_template.cost_distribution_templates:
if c.template not in output_templates:
raise ValidationError(
gettext('agronomics.msg_check_cost_distribution_template',
production=self.rec_name))
class ProductionTemplateInputsProductTemplate(ModelSQL):
@ -101,21 +124,31 @@ class Production(metaclass=PoolMeta):
__name__ = 'production'
production_template = fields.Many2One('production.template',
'Production Template')
"Production Template",
states={
'readonly': ~Eval('state').in_(['request', 'draft']),
},
depends=['state'])
production_template_cost_distribution_templates = fields.Function(
fields.Many2Many('production.cost_price.distribution.template',
None, None, "Cost Distribution Templates"),
'on_change_with_production_template_cost_distribution_templates')
enology_products = fields.One2Many('production.enology.product',
'production', "Enology Products",
domain=[('product', 'in', Eval('allowed_enology_products')),
If((Eval('state').in_(['waiting', 'draft'])),
('product.quantity', '>', 0), ())],
states={
'invisible': ~Bool(Eval('production_template'))
'invisible': ~Bool(Eval('production_template')),
'readonly': ~Eval('state').in_(['request', 'draft']),
}, depends=['allowed_enology_products', 'state'])
output_distribution = fields.One2Many('production.output.distribution',
'production', 'Output Distribution',
'production', "Output Distribution",
# domain=[('product', 'in', Eval('allowed_ouput_products'))],
states={
'invisible': ~Bool(Eval('production_template'))
}, depends=['allowed_output_products'])
'invisible': ~Bool(Eval('production_template')),
'readonly': Eval('state').in_(['cancelled', 'done']),
}, depends=['allowed_output_products', 'state'])
allowed_enology_products = fields.Function(fields.One2Many(
'product.product', None, 'Allowed Enology Products', readonly=True),
'on_change_with_allowed_enology_products',
@ -124,11 +157,39 @@ class Production(metaclass=PoolMeta):
'product.template', None, 'Allowed Output Products', readonly=True),
'on_change_with_allowed_output_products',
setter='set_allowed_products')
cost_distributions = fields.One2Many(
'production.cost_price.distribution',
'origin', "Cost Distributions",
states={
'readonly': Eval('state').in_(['cancelled', 'done']),
}, domain=[
('template', 'in', Eval('cost_distribution_templates')),
], depends=['state', 'cost_distribution_template',
'cost_distribution_templates'])
cost_distribution_template = fields.Many2One(
'production.cost_price.distribution.template',
"Cost Distribution Template",
domain=[
('id', 'in', Eval('production_template_cost_distribution_templates'))
], states={
'readonly': Eval('state').in_(['cancelled', 'done']),
}, depends=['state', 'production_template_cost_distribution_templates'])
cost_distribution_templates = fields.Function(
fields.Many2Many('product.template',
None, None, "Cost Product Templates"),
'on_change_with_cost_distribution_templates')
@classmethod
def set_allowed_products(cls, productions, name, value):
pass
@fields.depends('production_template')
def on_change_production_template(self):
if (self.production_template and
self.production_template.cost_distribution_template):
self.cost_distribution_template = \
self.production_template.cost_distribution_template
@fields.depends('production_template')
def on_change_with_allowed_enology_products(self, name=None):
products = []
@ -144,14 +205,65 @@ class Production(metaclass=PoolMeta):
return []
return [x.id for x in self.production_template.outputs]
@fields.depends('production_template',
'_parent_production_template.cost_distribution_templates')
def on_change_with_production_template_cost_distribution_templates(self,
name=None):
if self.production_template:
return [s.id for s in
self.production_template.cost_distribution_templates]
@fields.depends('cost_distribution_template',
'_parent_cost_distribution_template.cost_distribution_templates')
def on_change_with_cost_distribution_templates(self, name=None):
if self.production_template:
return [s.id for s in self.production_template.outputs]
@classmethod
def validate(cls, productions):
super(Production, cls).validate(productions)
for production in productions:
production.check_cost_distribution()
production.check_percentatge()
def check_cost_distribution(self):
if (self.state in ('cancelled', 'done')
or not self.cost_distribution_template
or not self.cost_distributions):
return
distribution_templates = set([c.template
for c in self.cost_distribution_template.cost_distribution_templates])
for c in self.cost_distributions:
if c.template not in distribution_templates:
raise ValidationError(
gettext('agronomics.msg_check_cost_distribution',
production=self.rec_name))
def check_percentatge(self):
if not self.cost_distributions:
return
percentatge = sum(template.percentatge
for template in self.cost_distributions)
if percentatge != 1:
raise ValidationError(
gettext('agronomics.msg_check_production_percentatge',
production=self.rec_name,
percentatge=percentatge * 100,
))
@classmethod
def wait(cls, productions):
Move = Pool().get('stock.move')
Uom = Pool().get('product.uom')
OutputDistribution = Pool().get('production.output.distribution')
pool = Pool()
Move = pool.get('stock.move')
Uom = pool.get('product.uom')
OutputDistribution = pool.get('production.output.distribution')
CostDistribution = pool.get('production.cost_price.distribution')
moves = []
delete = []
outputs = []
costs = []
delete_outputs = []
for production in productions:
@ -196,10 +308,27 @@ class Production(metaclass=PoolMeta):
od.production = production
outputs.append(od)
if not production.cost_distributions:
if production.cost_distribution_template:
cost_distribution_template = production.cost_distribution_template
elif production.production_template:
cost_distribution_template = production.production_template.cost_distribution_template
else:
cost_distribution_template = None
if cost_distribution_template:
for c in cost_distribution_template.cost_distribution_templates:
cost = CostDistribution()
cost.template = c.template
cost.percentatge = c.percentatge
cost.origin = str(production)
costs.append(cost)
CostDistribution.save(costs)
OutputDistribution.delete(delete_outputs)
OutputDistribution.save(outputs)
Move.save(moves)
Move.delete(delete)
super().wait(productions)
def create_variant(self, template, pass_feature):
@ -264,6 +393,46 @@ class Production(metaclass=PoolMeta):
Move.save(moves)
super().done(productions)
@classmethod
def set_cost(cls, productions):
pool = Pool()
Move = pool.get('stock.move')
Uom = pool.get('product.uom')
not_cost_distribution = []
moves = []
for production in productions:
if not production.cost_distributions:
not_cost_distribution.append(production)
continue
production_cost = production.cost
for output in production.outputs:
has_product = False
output_cost = Decimal(0)
total_output = sum([Uom.compute_qty(x.uom, x.quantity,
x.product.default_uom) for x in production.outputs
if x.product.template == output.product.template])
for cdist in production.cost_distributions:
products = cdist.template.products
if output.product not in products:
continue
has_product = True
cost = production_cost * (1 + cdist.percentatge) - production_cost
output_cost += round_price(cost / Decimal(total_output))
output_cost = output_cost if has_product else Decimal(0)
if output.unit_price != output_cost:
output.unit_price = output_cost
moves.append(output)
if moves:
Move.save(moves)
if not_cost_distribution:
super(Production, cls).set_cost(not_cost_distribution)
class OutputDistribution(ModelSQL, ModelView):
'Output Distribution'
@ -352,6 +521,7 @@ class OutputDistribution(ModelSQL, ModelView):
return ((self.final_quantity or 0) -
(self.initial_quantity or 0))
class ProductionEnologyProduct(ModelSQL, ModelView):
'Production Enology Product'
__name__ = 'production.enology.product'
@ -382,3 +552,131 @@ class ProductionEnologyProduct(ModelSQL, ModelView):
if not self.product:
return
self.quantity = self.product.quantity
class ProductionCostPriceDistribution(ModelSQL, ModelView):
"Production Distribution Cost Price"
__name__ = 'production.cost_price.distribution'
template = fields.Many2One('product.template', "Template", required=True,
ondelete='RESTRICT')
origin = fields.Reference('Origin', selection='_get_models', required=True,)
percentatge = fields.Numeric("Percentatge", digits=(16, 4), required=True)
@classmethod
def __setup__(cls):
BOMInput = Pool().get('production.bom.input')
super(ProductionCostPriceDistribution, cls).__setup__()
cls.template.domain = [('type', 'in', BOMInput.get_product_types())]
@staticmethod
def _get_models():
return [
('production', 'Production'),
('production.cost_price.distribution.template', 'Templates'),
]
class ProductionCostPriceDistributionTemplate(ModelSQL, ModelView):
"Production Cost Price Distribution Template"
__name__ = 'production.cost_price.distribution.template'
name = fields.Char("Name", required=True)
production_template = fields.Many2One('production.template',
"Production Template", required=True)
cost_distribution_templates = fields.One2Many(
'production.cost_price.distribution',
'origin', "Cost Distribution")
@classmethod
def validate(cls, templates):
super(ProductionCostPriceDistributionTemplate, cls).validate(templates)
for template in templates:
template.check_percentatge()
template.check_product_templates()
def check_product_templates(self):
for cost in self.cost_distribution_templates:
if cost.template not in self.production_template.outputs:
raise ValidationError(gettext(
'agronomics.msg_check_cost_templates',
cost=cost.rec_name,
template=cost.template.rec_name,
))
def check_percentatge(self):
percentatge = sum(t.percentatge
for t in self.cost_distribution_templates)
if percentatge != 1:
raise ValidationError(
gettext(
'agronomics.msg_check_cost_distribution_template_percentatge',
distribution=self.rec_name,
percentatge=percentatge * 100,
))
class ProductionCostPriceDistributionTemplateProductionTemplateAsk(ModelView):
'Production Cost Price Distribution Template from Production Template Ask'
__name__ = 'production.cost_price.distribution.template.ask'
name = fields.Char("Name", required=True)
cost_distribution_templates = fields.One2Many(
'production.cost_price.distribution',
None, "Cost Distributions")
class ProductionCostPriceDistributionTemplateProductionTemplate(Wizard):
"Production Cost Price Distribution Template from Production Template"
__name__ = 'production.cost_price.distribution.template.from.production.template'
start_state = 'ask'
ask = StateView('production.cost_price.distribution.template.ask',
'agronomics.create_cost_price_distribution_from_production_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Create', 'create_cost_distributions', 'tryton-ok', True),
])
create_cost_distributions = StateAction(
'agronomics.act_production_cost_distribution_template_tree')
def do_create_cost_distributions(self, action):
pool = Pool()
Template = pool.get('production.cost_price.distribution.template')
Distribution = pool.get('production.cost_price.distribution')
to_create = []
for record in self.records:
tpl = Template()
tpl.name = self.ask.name
tpl.production_template = record
cost_distributions = []
for cost_distribution in self.ask.cost_distribution_templates:
dt = Distribution()
dt.template = cost_distribution.template
dt.percentatge = cost_distribution.percentatge
cost_distributions.append(dt)
if cost_distributions:
tpl.cost_distribution_templates = cost_distributions
to_create.append(tpl._save_values)
tpls = Template.create(to_create)
data = {'res_id': [tpl.id for tpl in tpls]}
if len(tpls) == 1:
action['views'].reverse()
return action, data
def default_ask(self, fields):
pool = Pool()
ProductionTemplate = pool.get('production.template')
default = {}
context = Transaction().context
active_id = context.get('active_id')
if active_id:
ptpl = ProductionTemplate(active_id)
cost_distributions = []
for output in ptpl.outputs:
cost_distributions.append({
'template': output.id,
'template.': {'rec_name': output.rec_name},
})
default['cost_distribution_templates'] = cost_distributions
return default

View File

@ -97,6 +97,7 @@
<field name="res_model">production.enology.product</field>
</record>
<!-- production -->
<record model="ir.ui.view" id="production_view_form">
<field name="model">production</field>
<field name="inherit" ref="production.production_view_form"/>
@ -109,5 +110,118 @@
<field name="name">production_list</field>
</record>
<!-- production.cost_price.distribution.template -->
<record model="ir.ui.view" id="production_cost_distribution_template_view_form">
<field name="model">production.cost_price.distribution.template</field>
<field name="type">form</field>
<field name="name">production_cost_distribution_template_form</field>
</record>
<record model="ir.ui.view" id="production_cost_distribution_template_view_tree">
<field name="model">production.cost_price.distribution.template</field>
<field name="type">tree</field>
<field name="name">production_cost_distribution_template_tree</field>
</record>
<record model="ir.action.act_window" id="act_production_cost_distribution_template_tree">
<field name="name">Templates Cost Price Distribution</field>
<field name="res_model">production.cost_price.distribution.template</field>
</record>
<record model="ir.action.act_window.view" id="act_production_cost_distribution_template_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="production_cost_distribution_template_view_tree"/>
<field name="act_window" ref="act_production_cost_distribution_template_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_production_cost_distribution_template_tree_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="production_cost_distribution_template_view_form"/>
<field name="act_window" ref="act_production_cost_distribution_template_tree"/>
</record>
<menuitem
parent="production.menu_configuration"
action="act_production_cost_distribution_template_tree"
sequence="50"
id="menu_act_production_cost_distribution_template"/>
<record model="ir.model.access" id="access_production_cost_distribution_template">
<field name="model" search="[('model', '=', 'production.cost_price.distribution.template')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_production_cost_distribution_template_admin">
<field name="model" search="[('model', '=', 'production.cost_price.distribution.template')]"/>
<field name="group" ref="production.group_production_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- production cost price distribution -->
<record model="ir.ui.view" id="production_cost_price_distribution_view_form">
<field name="model">production.cost_price.distribution</field>
<field name="type">form</field>
<field name="name">production_cost_price_distribution_form</field>
</record>
<record model="ir.ui.view" id="production_cost_price_distribution_view_tree">
<field name="model">production.cost_price.distribution</field>
<field name="type">tree</field>
<field name="name">production_cost_price_distribution_tree</field>
</record>
<record model="ir.action.act_window" id="act_production_cost_price_distribution_tree">
<field name="name">Cost Price Distribution</field>
<field name="res_model">production.cost_price.distribution</field>
</record>
<record model="ir.action.act_window.view" id="act_production_cost_price_distribution_tree_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="production_cost_price_distribution_view_tree"/>
<field name="act_window" ref="act_production_cost_price_distribution_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_production_cost_price_distribution_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="production_cost_price_distribution_view_form"/>
<field name="act_window" ref="act_production_cost_price_distribution_tree"/>
</record>
<record model="ir.model.access" id="access_production_cost_price_distribution">
<field name="model" search="[('model', '=', 'production.cost_price.distribution')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_production_cost_price_distribution_admin">
<field name="model" search="[('model', '=', 'production.cost_price.distribution')]"/>
<field name="group" ref="production.group_production_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- create cost price distribution template from production template -->
<record model="ir.ui.view" id="create_cost_price_distribution_from_production_start_view_form">
<field name="model">production.cost_price.distribution.template.ask</field>
<field name="type">form</field>
<field name="name">create_cost_price_distribution_from_production_start_form</field>
</record>
<record model="ir.action.wizard" id="wizard_create_cost_price_distribution_from_production">
<field name="name">Create Cost Price Distribution</field>
<field name="wiz_name">production.cost_price.distribution.template.from.production.template</field>
<field name="model">production.template</field>
</record>
<record model="ir.action-res.group" id="wizard_create_cost_price_distribution-group_production">
<field name="action" ref="wizard_create_cost_price_distribution_from_production"/>
<field name="group" ref="production.group_production"/>
</record>
<record model="ir.action.keyword" id="wizard_create_cost_price_distribution_from_production_keyword1">
<field name="keyword">form_action</field>
<field name="model">production.template,-1</field>
<field name="action" ref="wizard_create_cost_price_distribution_from_production"/>
</record>
</data>
</tryton>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="name"/>
<field name="name"/>
<separator name="cost_distribution_templates" colspan="4"/>
<field name="cost_distribution_templates" colspan="4"/>
</form>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="name"/>
<field name="name"/>
<label name="production_template"/>
<field name="production_template"/>
<newline/>
<field name="cost_distribution_templates" colspan="4"/>
</form>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="name" expand="1"/>
<field name="production_template" expand="1"/>
</tree>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="template"/>
<field name="template"/>
<label name="percentatge"/>
<field name="percentatge" factor="100"/>
<label name="origin"/>
<field name="origin"/>
</form>

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree editable="1">
<field name="template" expand="1"/>
<field name="percentatge" factor="100">
<suffix name="percentatge" string="%"/>
</field>
</tree>

View File

@ -15,5 +15,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="output_distribution" colspan="4"/>
<field name="allowed_output_products" colspan="4" invisible="1"/>
</page>
<page string="Cost Distribution" id="cost-distribution">
<label name="cost_distribution_template"/>
<field name="cost_distribution_template"/>
<newline/>
<field name="cost_distributions" colspan="4"/>
<field name="cost_distribution_templates" invisible="1"/>
</page>
</xpath>
</data>

View File

@ -13,4 +13,7 @@ this repository contains the full copyright notices and license terms. -->
<field name="inputs" colspan="2"/>
<field name="outputs" colspan="2"/>
<field name="enology_products" colspan="4"/>
<label name="cost_distribution_template"/>
<field name="cost_distribution_template"/>
<field name="cost_distribution_templates" colspan="4"/>
</form>