production template #045158

This commit is contained in:
Àngel Àlvarez 2021-09-03 11:35:21 +02:00
parent e813e592eb
commit da0e5ee7a6
19 changed files with 928 additions and 14 deletions

View File

@ -7,7 +7,7 @@ from . import plot
from . import product
from . import weighing
from . import quality
from . import production
def register():
Pool.register(
@ -37,6 +37,13 @@ def register():
quality.QualityTest,
quality.QuantitativeTestLine,
quality.QualitativeTestLine,
production.ProductionTemplate,
production.ProductionTemplateLine,
production.ProductionTemplateInputsProductTemplate,
production.ProductionTemplateOutputsProductTemplate,
production.Production,
production.OutputDistribution,
production.ProductionEnologyProduct,
module='agronomics', type_='model')
Pool.register(
module='agronomics', type_='wizard')

View File

@ -64,13 +64,21 @@ class Template(metaclass=PoolMeta):
return [('container.capacity',) + tuple(clause[1:])]
class ProductVariety(ModelSQL, ModelView):
'Product Variety'
__name__ = 'product.variety'
variety = fields.Many2One('product.taxon', 'Variety', required=True)
percent = fields.Float('Percent', digits=(16, 4), required=True)
product = fields.Many2One('product.product', 'Product', required=True)
class Product(WineMixin, metaclass=PoolMeta):
__name__ = 'product.product'
vintages = fields.Many2Many('product.product-agronomics.crop', 'product',
'crop', 'Vintages')
varieties = fields.Many2Many('product.product-product.taxon', 'product',
'variety', 'Varieties')
varieties = fields.One2Many('product.variety', 'product', 'Varieties')
denominations_of_origin = fields.Many2Many(
'product.product-agronomics.denomination_of_origin', 'product',
'do', 'DOs',
@ -131,15 +139,6 @@ class ProductCrop(ModelSQL):
ondelete='CASCADE', select=True, required=True)
class ProductVariety(ModelSQL):
"Product - Variety"
__name__ = 'product.product-product.taxon'
product = fields.Many2One('product.product', 'Product',
ondelete='CASCADE', select=True, required=True)
variety = fields.Many2One('product.taxon', 'Variety',
ondelete='CASCADE', select=True, required=True)
class ProductDO(ModelSQL):
"Product - DO"
__name__ = 'product.product-agronomics.denomination_of_origin'

339
production.py Normal file
View File

@ -0,0 +1,339 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Bool
from trytond.exceptions import UserError
from trytond.i18n import gettext
from decimal import Decimal
from trytond.transaction import Transaction
class ProductionTemplate(ModelSQL, ModelView):
"Produciton Template"
__name__ = 'production.template'
name = fields.Char('Name', required=True)
uom = fields.Many2One('product.uom', 'Uom', required=True)
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits')
quantity = fields.Float('Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'])
inputs = fields.Many2Many('production.template.inputs-product.template',
'production_template', 'template', "Inputs")
outputs = fields.Many2Many('production.template.outputs-product.template',
'production_template', 'template', "Outputs")
enology_products = fields.One2Many('production.template.line',
'production_template', 'Production Template')
pass_feature = fields.Boolean('Pass on Feature')
@fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
if self.uom:
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]
if not all(uoms+[category_uom]):
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)
class ProductionTemplateInputsProductTemplate(ModelSQL):
'Production Template Inputs- Product Template'
__name__ = 'production.template.inputs-product.template'
production_template = fields.Many2One('production.template',
'Production Template', ondelete='CASCADE', required=True, select=True)
template = fields.Many2One('product.template', 'Template',
ondelete='CASCADE', required=True, select=True)
class ProductionTemplateOutputsProductTemplate(ModelSQL):
'Production Template Inputs- Product Template'
__name__ = 'production.template.outputs-product.template'
production_template = fields.Many2One('production.template',
'Production Template', ondelete='CASCADE', required=True, select=True)
template = fields.Many2One('product.template', 'Product',
ondelete='CASCADE', required=True, select=True)
class ProductionTemplateLine(ModelSQL, ModelView):
"Production Template Line"
__name__ = 'production.template.line'
product = fields.Many2One('product.product', 'Producte', required=True)
uom = fields.Many2One('product.uom', 'Uom')
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits')
quantity = fields.Float('Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'])
production_template = fields.Many2One('production.template',
'Production Template')
@fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
if self.uom:
return self.uom.digits
return 2
@fields.depends('product')
def on_change_with_uom(self):
if not self.product:
return
return self.product.default_uom and self.product.default_uom.id
class Production(metaclass=PoolMeta):
__name__ = 'production'
production_template = fields.Many2One('production.template',
'Production Template')
enology_products = fields.One2Many('production.enology.product',
'production', "Enology Products",
domain=[('product', 'in', Eval('allowed_enology_products')),
('product.quantity', '>', 0)],
states={
'invisible': ~Bool(Eval('production_template'))
}, depends=['allowed_enology_products'])
output_distribution = fields.One2Many('production.output.distribution',
'production', 'Output Distribution',
# domain=[('product', 'in', Eval('allowed_ouput_products'))],
states={
'invisible': ~Bool(Eval('production_template'))
}, depends=['allowed_output_products'])
allowed_enology_products = fields.Function(fields.One2Many(
'product.product', None, 'Allowed Enology Products', readonly=True),
'on_change_with_allowed_enology_products',
setter='set_allowed_products')
allowed_output_products = fields.Function(fields.One2Many(
'product.template', None, 'Allowed Output Products', readonly=True),
'on_change_with_allowed_output_products',
setter='set_allowed_products')
@classmethod
def set_allowed_products(cls, productions, name, value):
pass
@fields.depends('production_template')
def on_change_with_allowed_enology_products(self, name=None):
products = []
if not self.production_template:
return []
for template in self.production_template.inputs:
products += template.products
return [x.id for x in products]
@fields.depends('production_template')
def on_change_with_allowed_output_products(self, name=None):
if not self.production_template:
return []
return [x.id for x in self.production_template.outputs]
@classmethod
def wait(cls, productions):
Move = Pool().get('stock.move')
Uom = Pool().get('product.uom')
moves = []
delete = []
for production in productions:
delete = [x for x in production.inputs]
input_quantity = 0
for enology in production.enology_products:
move = production._move(production.picking_location,
production.location,
production.company,
enology.product,
enology.uom.id,
enology.quantity)
move.production_input = production
moves.append(move)
input_quantity += Uom.compute_qty(enology.uom, enology.quantity,
production.production_template.uom)
enology_products = (production.production_template and
production.production_template.enology_products or [])
for enology in enology_products:
quantity = Uom.compute_qty(enology.uom, enology.quantity,
production.production_template.uom)
ratio = quantity / (input_quantity or 1)
qty = Decimal(str(input_quantity*ratio))
move = production._move(production.picking_location,
production.location,
production.company,
enology.product,
enology.uom.id,
float(qty))
move.production_input = production
moves.append(move)
Move.save(moves)
Move.delete(delete)
super().wait(productions)
def create_variant(self, template, pass_feature):
Product = Pool().get('product.product')
product = Product()
product.template = template
return product
def pass_feature(self, product):
Variety = Pool().get('product.variety')
Uom = Pool().get('product.uom')
total_output = sum([Uom.compute_qty(x.uom, x.quantity,
x.product.default_uom)
for x in self.inputs])
vintages = []
do = []
ecologicals = []
for input in self.inputs:
vintages += input.product.vintages
do += input.product.denominations_of_origin
ecologicals = input.product.ecologicals
product.denominations_of_origin = list(set(do))
product.ecologicals = list(set(ecologicals))
product.vintages = list(set(vintages))
varieties = {}
for input in self.inputs:
percent = round(input.quantity/total_output, 2)
for variety in input.product.varieties:
new_variety = varieties.get(variety.variety)
if not new_variety:
new_variety = Variety()
new_variety.percent = 0
new_variety.variety = variety.variety
new_variety.percent += variety.percent/100*percent
varieties[new_variety.variety] = new_variety
for key, variety in varieties.items():
variety.percent = "%.4f" % round(100*variety.percent, 4)
product.varieties = varieties.values()
return product
@classmethod
def done(cls, productions):
Move = Pool().get('stock.move')
moves = []
for production in productions:
for distrib in production.output_distribution:
product = production.create_variant(distrib.product,
production.production_template.pass_feature)
product = production.pass_feature(product)
move = production._move(production.location,
distrib.location,
production.company,
product,
distrib.uom,
distrib.produced_quantity)
move.production_output = production
move.unit_price = Decimal(0)
moves.append(move)
Move.save(moves)
super().done(productions)
class OutputDistribution(ModelSQL, ModelView):
'Output Distribution'
__name__ = 'production.output.distribution'
production = fields.Many2One('production', 'Production',
required=True)
product = fields.Many2One('product.template', 'Template', required=True)
location = fields.Many2One('stock.location', 'Location', required=True)
uom = fields.Many2One('product.uom', 'Uom')
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits')
initial_quantity = fields.Float('Initial Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'], readonly=True)
final_quantity = fields.Float('Final Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'], readonly=True)
produced_quantity = fields.Float('Produced Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'])
@fields.depends('product')
def on_change_with_uom(self):
if not self.product:
return
return self.product.default_uom and self.product.default_uom.id
@fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
if self.uom:
return self.uom.digits
return 2
@fields.depends('initial_quantity', 'final_quantity', 'produced_quantity',
'location', 'product')
def on_change_product(self):
Product = Pool().get('product.product')
if not self.product:
self.initial_quantity = 0
self.final_quantity = self.produced_quantity
return
if not self.location:
return
context = Transaction().context
context['locations'] = [self.location.id]
with Transaction().set_context(context):
quantities = Product.get_quantity(self.product.products, 'quantity')
self.initial_quantity = sum(quantities.values())
self.final_quantity = self.initial_quantity + (self.produced_quantity
or 0)
@fields.depends('location', methods=['on_change_product'])
def on_change_location(self):
if not self.location:
return
self.on_change_product()
@fields.depends('produced_quantity', 'final_quantity', 'initial_quantity')
def on_change_produced_quantity(self):
self.final_quantity = ((self.initial_quantity or 0) +
(self.produced_quantity or 0))
class ProductionEnologyProduct(ModelSQL, ModelView):
'Production Enology Product'
__name__ = 'production.enology.product'
production = fields.Many2One('production', 'Production',
select=True)
product = fields.Many2One('product.product', 'Product', required=True)
uom = fields.Many2One('product.uom', 'Uom')
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits')
quantity = fields.Float('Quantity',
digits=(16, Eval('unit_digits', 2)),
depends=['unit_digits'])
@fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
if self.uom:
return self.uom.digits
return 2
@fields.depends('product')
def on_change_with_uom(self):
if not self.product:
return
return self.product.default_uom and self.product.default_uom.id
@fields.depends('product')
def on_change_product(self):
if not self.product:
return
self.quantity = self.product.quantity

114
production.xml Normal file
View File

@ -0,0 +1,114 @@
<tryton>
<data>
<!-- Production Template -->
<record model="ir.ui.view" id="production_template_view_form">
<field name="model">production.template</field>
<field name="type">form</field>
<field name="name">production_template_form</field>
</record>
<record model="ir.ui.view" id="production_template_view_tree">
<field name="model">production.template</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">production_template_list</field>
</record>
<record model="ir.action.act_window" id="act_production_template_tree">
<field name="name">Production Template</field>
<field name="res_model">production.template</field>
</record>
<record model="ir.action.act_window.view" id="act_production_template_tree_view">
<field name="sequence" eval="10"/>
<field name="view" ref="production_template_view_tree"/>
<field name="act_window" ref="act_production_template_tree"/>
</record>
<record model="ir.action.act_window.view" id="act_production_template_form_view">
<field name="sequence" eval="20"/>
<field name="view" ref="production_template_view_form"/>
<field name="act_window" ref="act_production_template_tree"/>
</record>
<menuitem parent="production.menu_configuration" sequence="1"
action="act_production_template_tree" id="menu_production_template_list"/>
<record model="ir.ui.menu-res.group"
id="menu_production_template_list_group_productions">
<field name="menu" ref="menu_production_template_list"/>
<field name="group" ref="production.group_production"/>
</record>
<record model="ir.ui.menu-res.group"
id="menu_production_template_list_group_productions_admin">
<field name="menu" ref="menu_production_template_list"/>
<field name="group" ref="production.group_production_admin"/>
</record>
<!-- Production Template Line -->
<record model="ir.ui.view" id="production_template_line_view_form">
<field name="model">production.template.line</field>
<field name="type">form</field>
<field name="name">production_template_line_form</field>
</record>
<record model="ir.ui.view" id="production_template_line_view_tree">
<field name="model">production.template.line</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">production_template_line_list</field>
</record>
<record model="ir.action.act_window" id="act_production_template_line_tree">
<field name="name">Production Template Line</field>
<field name="res_model">production.template.line</field>
</record>
<!-- Production Output Distribution -->
<record model="ir.ui.view" id="production_output_distribution_view_form">
<field name="model">production.output.distribution</field>
<field name="type">form</field>
<field name="name">production_output_distribution_form</field>
</record>
<record model="ir.ui.view" id="production_output_distribution_view_tree">
<field name="model">production.output.distribution</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">production_output_distribution_list</field>
</record>
<record model="ir.action.act_window" id="act_production_output_distribution_tree">
<field name="name">Production Output Distribution</field>
<field name="res_model">production.output.distribution</field>
</record>
<!-- Production Enology -->
<record model="ir.ui.view" id="production_enology_product_view_form">
<field name="model">production.enology.product</field>
<field name="type">form</field>
<field name="name">production_enology_product_form</field>
</record>
<record model="ir.ui.view" id="production_enology_product_view_tree">
<field name="model">production.enology.product</field>
<field name="type">tree</field>
<field name="priority" eval="20"/>
<field name="name">production_enology_product_list</field>
</record>
<record model="ir.action.act_window" id="act_production_enology_product_tree">
<field name="name">Production Enology Product</field>
<field name="res_model">production.enology.product</field>
</record>
<record model="ir.ui.view" id="production_view_form">
<field name="model">production</field>
<field name="inherit" ref="production.production_view_form"/>
<field name="name">production_form</field>
</record>
<record model="ir.ui.view" id="production_view_list">
<field name="model">production</field>
<field name="inherit" ref="production.production_view_list"/>
<field name="name">production_list</field>
</record>
</data>
</tryton>

View File

@ -0,0 +1,329 @@
===================
Production Scenario
===================
Imports::
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.production.production import BOM_CHANGES
>>> today = datetime.date.today()
>>> yesterday = today - relativedelta(days=1)
>>> before_yesterday = yesterday - relativedelta(days=1)
Activate modules::
>>> config = activate_modules('agronomics')
Create company::
>>> _ = create_company()
>>> company = get_company()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> liter, = ProductUom.find([('name', '=', 'Liter')])
>>> kg, = ProductUom.find([('name', '=', 'Kilogram')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> Taxon = Model.get('product.taxon')
>>> DO = Model.get('agronomics.denomination_of_origin')
>>> Ecological = Model.get('agronomics.ecological')
Create Denomination Of Origin::
>>> catalunya = DO()
>>> catalunya.name = 'Catalunya'
>>> catalunya.save()
>>> barcelona = DO()
>>> barcelona.name = 'Barcelona'
>>> barcelona.save()
Create Taxon::
>>> macabeu = Taxon()
>>> macabeu.rank = 'variety'
>>> macabeu.name = 'Macabeu'
>>> macabeu.save()
>>> parellada = Taxon()
>>> parellada.rank = 'variety'
>>> parellada.name = 'Parellada'
>>> parellada.save()
Create Ecological::
>>> ecological = Ecological()
>>> ecological.name = 'Ecological'
>>> ecological.save()
# Raim Blanc
>>> template = ProductTemplate()
>>> template.name = 'Raim Blanc'
>>> template.default_uom = kg
>>> template.type = 'goods'
>>> template.producible = True
>>> template.list_price = Decimal(0)
>>> product, = template.products
>>> product.cost_price = Decimal(10)
>>> template.save()
>>> product, = template.products
>>> productA = Product()
>>> productA.code = "A"
>>> productA.template = template
>>> productA.denominations_of_origin.append(catalunya)
>>> productA.save()
>>> catalunya, = DO.find([('name', '=', 'Catalunya')])
>>> productB = Product()
>>> productB.code = "B"
>>> productB.template = template
>>> productB.denominations_of_origin.append(catalunya)
>>> productB.save()
>>> catalunya, = DO.find([('name', '=' , 'Catalunya')])
>>> productC = Product()
>>> productC.code = "C"
>>> productC.template = template
>>> productC.denominations_of_origin.append(catalunya)
>>> productC.save()
Create Variety::
>>> Variety = Model.get('product.variety')
>>> AM = Variety()
>>> AM.variety = macabeu
>>> AM.percent = 100.0
>>> AM.product = productA
>>> AM.save()
>>> BM = Variety()
>>> BM.variety = macabeu
>>> BM.percent = 100.0
>>> BM.product = productB
>>> BM.save()
>>> CP = Variety()
>>> CP.variety = parellada
>>> CP.percent = 100.0
>>> CP.product = productC
>>> CP.save()
# Sulforos
>>> template = ProductTemplate()
>>> template.name = 'Sulforos'
>>> template.default_uom = kg
>>> template.type = 'goods'
>>> template.producible = True
>>> template.list_price = Decimal(0)
>>> product2, = template.products
>>> product2.cost_price = Decimal(10)
>>> template.save()
>>> product2, = template.products
# Encims
>>> template = ProductTemplate()
>>> template.name = 'Encims'
>>> template.default_uom = kg
>>> template.type = 'goods'
>>> template.producible = True
>>> template.list_price = Decimal(0)
>>> product3, = template.products
>>> product3.cost_price = Decimal(10)
>>> template.save()
>>> product3, = template.products
# Carbo actiu
>>> template = ProductTemplate()
>>> template.name = 'Carbo actiu'
>>> template.default_uom = kg
>>> template.type = 'goods'
>>> template.producible = True
>>> template.list_price = Decimal(0)
>>> product4, = template.products
>>> product4.cost_price = Decimal(10)
>>> template.save()
>>> product4, = template.products
# Most flor
>>> mostflor = ProductTemplate()
>>> mostflor.name = 'Most Flor'
>>> mostflor.default_uom = liter
>>> mostflor.type = 'goods'
>>> mostflor.producible = True
>>> mostflor.list_price = Decimal(0)
>>> mostflor.save()
>>> product5, = mostflor.products
>>> product5.cost_price = Decimal(0)
>>> product5.save()
# Most Primeres
>>> mostprimeres = ProductTemplate()
>>> mostprimeres.name = 'Most Primeres'
>>> mostprimeres.default_uom = liter
>>> mostprimeres.type = 'goods'
>>> mostprimeres.producible = True
>>> mostprimeres.list_price = Decimal(0)
>>> mostprimeres.save()
>>> product6, = mostprimeres.products
>>> product6.cost_price = Decimal(0)
>>> product6.save()
Create Production Template::
>>> ProductionTemplate = Model.get('production.template')
>>> ProductionTemplateLine = Model.get("production.template.line")
>>> production_template = ProductionTemplate()
>>> production_template.name = 'Premsat i desfangat de raim blanc'
>>> production_template.uom = kg
>>> production_template.quantity = 10000
>>> production_template.pass_feature = True
>>> production_template.inputs.append(product.template)
>>> production_template.outputs.append(mostflor)
>>> production_template.outputs.append(mostprimeres)
>>> line = ProductionTemplateLine()
>>> line.product = product2
>>> line.quantity = 100
>>> production_template.enology_products.append(line)
>>> line = ProductionTemplateLine()
>>> line.product = product3
>>> line.quantity = 50
>>> production_template.enology_products.append(line)
>>> line = ProductionTemplateLine()
>>> line.product = product4
>>> line.quantity =150
>>> production_template.enology_products.append(line)
>>> production_template.save()
Create an Inventory::
>>> Inventory = Model.get('stock.inventory')
>>> InventoryLine = Model.get('stock.inventory.line')
>>> Location = Model.get('stock.location')
>>> storage, = Location.find([
... ('code', '=', 'STO'),
... ])
>>> inventory = Inventory()
>>> inventory.location = storage
>>> inventory_line1 = InventoryLine()
>>> inventory.lines.append(inventory_line1)
>>> inventory_line1.product = productA
>>> inventory_line1.quantity = 5000
>>> inventory_line2 = InventoryLine()
>>> inventory.lines.append(inventory_line2)
>>> inventory_line2.product = productB
>>> inventory_line2.quantity = 10000
>>> inventory_line3 = InventoryLine()
>>> inventory.lines.append(inventory_line3)
>>> inventory_line3.product = productC
>>> inventory_line3.quantity = 3000
>>> inventory_line3 = InventoryLine()
>>> inventory.lines.append(inventory_line3)
>>> inventory_line3.product = product2
>>> inventory_line3.quantity = 1000
>>> inventory_line3 = InventoryLine()
>>> inventory.lines.append(inventory_line3)
>>> inventory_line3.product = product3
>>> inventory_line3.quantity = 1000
>>> inventory_line3 = InventoryLine()
>>> inventory.lines.append(inventory_line3)
>>> inventory_line3.product = product4
>>> inventory_line3.quantity = 1000
>>> inventory.click('confirm')
>>> inventory.state
'done'
Create Production
>>> Production = Model.get('production')
>>> EnologyProduct = Model.get('production.enology.product')
>>> production = Production()
>>> production.production_template = production_template
>>> production.save()
>>> line = EnologyProduct()
>>> line.product = productA
>>> line.production = production
>>> line.quantity = 5000
>>> line.save()
>>> # production.enology_products.append(productA)
>>> line = EnologyProduct()
>>> line.product = productB
>>> line.quantity = 10000
>>> line.production = production
>>> line.save()
>>> # production.enology_products.append(productB)
>>> line = EnologyProduct()
>>> line.product = productC
>>> line.quantity = 3000
>>> line.production = production
>>> line.save()
>>> # production.enology_products.append(productC)
>>> production.reload()
>>> production.click('wait')
>>> production.state
'waiting'
>>> len(production.inputs)
6
>>> input, = [i for i in production.inputs if i.product == product2]
>>> input.quantity
100.0
>>> input, = [i for i in production.inputs if i.product == product3]
>>> input.quantity
50.0
>>> input, = [i for i in production.inputs if i.product == product4]
>>> input.quantity
150.0
>>> OutputDistribution = Model.get('production.output.distribution')
>>> m1 = OutputDistribution()
>>> m1.production = production
>>> m1.product = mostflor
>>> m1.location = storage
>>> m1.produced_quantity = 3000
>>> production.output_distribution.append(m1)
>>> m2 = OutputDistribution()
>>> m2.production = production
>>> m2.product = mostflor
>>> m2.location = storage
>>> m2.produced_quantity = 1500
>>> production.output_distribution.append(m2)
>>> m3 = OutputDistribution()
>>> m3.production = production
>>> m3.product = mostprimeres
>>> m3.location = storage
>>> m3.produced_quantity = 3500
>>> production.output_distribution.append(m3)
>>> #import pdb; pdb.set_trace()
>>> production.save()
>>> production.reload()
>>> len(production.output_distribution)
3
>>> #[x.name for x in production.allowed_output_products]
>>> #[x.name for x in production.production_template.outputs]
>>> production.click('assign_try')
True
>>> production.click('run')
>>> production.click('done')
>>> len(production.outputs)
3
>>> most = production.outputs[0]
>>> len(most.product.varieties)
2
>>> [(x.variety.name, x.percent) for x in most.product.varieties]
[('Parellada', 16.0), ('Macabeu', 82.0)]
>>> [x.name for x in most.product.denominations_of_origin]
['Catalunya']

View File

@ -2,10 +2,11 @@
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
import unittest
import doctest
from trytond.tests.test_tryton import ModuleTestCase
from trytond.tests.test_tryton import suite as test_suite
from trytond.tests.test_tryton import doctest_teardown
from trytond.tests.test_tryton import doctest_checker
class AgronomicsTestCase(ModuleTestCase):
@ -17,4 +18,8 @@ def suite():
suite = test_suite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
AgronomicsTestCase))
suite.addTests(doctest.DocFileSuite('scenario_production_template.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite

View File

@ -6,8 +6,10 @@ depends:
party
product_classification
product_classification_taxonomic
product_template_form_quantity
quality_control_sample
purchase_contract
production
xml:
plot.xml
party.xml
@ -15,3 +17,4 @@ xml:
weighning.xml
wine.xml
message.xml
production.xml

View File

@ -0,0 +1,8 @@
<form>
<label name="product"/>
<field name="product"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="uom"/>
<field name="uom"/>
</form>

View File

@ -0,0 +1,5 @@
<tree>
<field name="product"/>
<field name="quantity"/>
<field name="uom"/>
</tree>

19
view/production_form.xml Normal file
View File

@ -0,0 +1,19 @@
<?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. -->
<data>
<xpath expr="/form/label[@name='bom']" position="before">
<label name="production_template"/>
<field name="production_template"/>
</xpath>
<xpath expr="/form/notebook" position="inside">
<page name="enology_products">
<field name="enology_products" colspan="4"/>
<field name="allowed_enology_products" colspan="4" invisible="1"/>
</page>
<page name="output_distribution">
<field name="output_distribution" colspan="4"/>
<field name="allowed_output_products" colspan="4" invisible="1"/>
</page>
</xpath>
</data>

8
view/production_list.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='state']" position="before">
<field name="cost" sum="Total"/>
</xpath>
</data>

View File

@ -0,0 +1,17 @@
<?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="product"/>
<field name="product"/>
<label name="location"/>
<field name="location"/>
<label name="uom"/>
<field name="uom"/>
<label name="initial_quantity"/>
<field name="initial_quantity"/>
<label name="final_quantity"/>
<field name="final_quantity"/>
<label name="produced_quantity"/>
<field name="produced_quantity"/>
</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. -->
<tree>
<field name="product"/>
<field name="location"/>
<field name="uom"/>
<field name="initial_quantity"/>
<field name="final_quantity"/>
<field name="produced_quantity"/>
</tree>

View File

@ -0,0 +1,16 @@
<?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="pass_feature"/>
<field name="pass_feature"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="uom"/>
<field name="uom"/>
<field name="inputs" colspan="2"/>
<field name="outputs" colspan="2"/>
<field name="enology_products" 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="product"/>
<field name="product"/>
<label name="uom"/>
<field name="uom"/>
<label name="quantity"/>
<field name="quantity"/>
</form>

View File

@ -0,0 +1,8 @@
<?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="product"/>
<field name="quantity"/>
<field name="uom"/>
</tree>

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>
<field name="name"/>
<field name="pass_feature"/>
<field name="quantity"/>
<field name="uom"/>
</tree>

View File

@ -1,3 +1,6 @@
<?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. -->
<data>
<xpath expr="/form/notebook/page[@id='general']/field[@name='cost_price_method']" position="after">
<label name="agronomic_type"/>

View File

@ -1,3 +1,6 @@
<?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. -->
<data>
<xpath expr="/tree" position="inside">
<field name="agronomic_type" tree_invisible="1"/>