implement funcionality
This commit is contained in:
parent
73cbc662e6
commit
68f13fb2dc
|
@ -0,0 +1,227 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
msgctxt "field:product.cost.plan,bom:"
|
||||
msgid "BOM"
|
||||
msgstr "Llista de materials"
|
||||
|
||||
msgctxt "field:product.cost.plan,boms:"
|
||||
msgid "BOMs"
|
||||
msgstr "Llistes de materials"
|
||||
|
||||
msgctxt "field:product.cost.plan,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Data de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuari de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producte"
|
||||
|
||||
msgctxt "field:product.cost.plan,product_cost:"
|
||||
msgid "Product Cost"
|
||||
msgstr "Cost del producte"
|
||||
|
||||
msgctxt "field:product.cost.plan,products:"
|
||||
msgid "Products"
|
||||
msgstr "Productes"
|
||||
|
||||
msgctxt "field:product.cost.plan,quantity:"
|
||||
msgid "Quantity"
|
||||
msgstr "Quantitat"
|
||||
|
||||
msgctxt "field:product.cost.plan,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
msgctxt "field:product.cost.plan,state:"
|
||||
msgid "State"
|
||||
msgstr "Estat"
|
||||
|
||||
msgctxt "field:product.cost.plan,total_cost:"
|
||||
msgid "Total Cost"
|
||||
msgstr "Cost total"
|
||||
|
||||
msgctxt "field:product.cost.plan,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Data modificació"
|
||||
|
||||
msgctxt "field:product.cost.plan,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuari modificació"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,bom:"
|
||||
msgid "BOM"
|
||||
msgstr "Llista de materials"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Data de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuari de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,plan:"
|
||||
msgid "Plan"
|
||||
msgstr "Pla"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producte"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Data modificació"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuari modificació"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,cost_price:"
|
||||
msgid "Cost Price"
|
||||
msgstr "Preu de cost"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Data de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuari de creació"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,last_purchase_price:"
|
||||
msgid "Last Purchase Price"
|
||||
msgstr "Últim preu de compra"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,plan:"
|
||||
msgid "Plan"
|
||||
msgstr "Pla"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producte"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,product_cost_price:"
|
||||
msgid "Product Cost Price"
|
||||
msgstr "Preu de cost del producte"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,quantity:"
|
||||
msgid "Quantity"
|
||||
msgstr "Quantitat"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,total:"
|
||||
msgid "Total Cost"
|
||||
msgstr "Cost total"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,uom:"
|
||||
msgid "Uom"
|
||||
msgstr "UdM"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,uom_category:"
|
||||
msgid "Uom Category"
|
||||
msgstr "Categoria d'UdM"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Data modificació"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuari modificació"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Pla de costos de producte"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan_bom_line"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Pla de costos de producte"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan_product_line"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Línia de producte de Pla de costos de producte"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Pla de costos de producte"
|
||||
|
||||
msgctxt "model:product.cost.plan,name:"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Pla de costos de producte"
|
||||
|
||||
msgctxt "model:product.cost.plan.bom_line,name:"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Pla de costos de producte"
|
||||
|
||||
msgctxt "model:product.cost.plan.product_line,name:"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Línia de producte de Pla de costos de producte"
|
||||
|
||||
msgctxt "model:res.group,name:group_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Pla de costos de producte"
|
||||
|
||||
msgctxt "model:res.group,name:group_product_cost_plan_admin"
|
||||
msgid "Product Cost Plan Administration"
|
||||
msgstr "Administració Pla de costos de producte"
|
||||
|
||||
msgctxt "selection:product.cost.plan,state:"
|
||||
msgid "Computed"
|
||||
msgstr "Calcul·lat"
|
||||
|
||||
msgctxt "selection:product.cost.plan,state:"
|
||||
msgid "Draft"
|
||||
msgstr "Esborrany"
|
||||
|
||||
msgctxt "view:product.cost.plan.bom_line:"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Pla de costos de producte"
|
||||
|
||||
msgctxt "view:product.cost.plan.product_line:"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Línia de producte de Pla de costos de producte"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "BOM Configuration"
|
||||
msgstr "Configuració de llistes de materials"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Compute"
|
||||
msgstr "Calcula"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Pla de costos de producte"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Reset"
|
||||
msgstr "Reinicialitza"
|
|
@ -0,0 +1,227 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
msgctxt "field:product.cost.plan,bom:"
|
||||
msgid "BOM"
|
||||
msgstr "Lista de material"
|
||||
|
||||
msgctxt "field:product.cost.plan,boms:"
|
||||
msgid "BOMs"
|
||||
msgstr "Listas de material"
|
||||
|
||||
msgctxt "field:product.cost.plan,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Fecha de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuario de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producto"
|
||||
|
||||
msgctxt "field:product.cost.plan,product_cost:"
|
||||
msgid "Product Cost"
|
||||
msgstr "Coste del producto"
|
||||
|
||||
msgctxt "field:product.cost.plan,products:"
|
||||
msgid "Products"
|
||||
msgstr "Productos"
|
||||
|
||||
msgctxt "field:product.cost.plan,quantity:"
|
||||
msgid "Quantity"
|
||||
msgstr "Cantidad"
|
||||
|
||||
msgctxt "field:product.cost.plan,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
msgctxt "field:product.cost.plan,state:"
|
||||
msgid "State"
|
||||
msgstr "Estado"
|
||||
|
||||
msgctxt "field:product.cost.plan,total_cost:"
|
||||
msgid "Total Cost"
|
||||
msgstr "Coste total"
|
||||
|
||||
msgctxt "field:product.cost.plan,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Fecha modificación"
|
||||
|
||||
msgctxt "field:product.cost.plan,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuario modificación"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,bom:"
|
||||
msgid "BOM"
|
||||
msgstr "Lista de material"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Fecha de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuario de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,plan:"
|
||||
msgid "Plan"
|
||||
msgstr "Plan"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producto"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Fecha modificación"
|
||||
|
||||
msgctxt "field:product.cost.plan.bom_line,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuario modificación"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,cost_price:"
|
||||
msgid "Cost Price"
|
||||
msgstr "Precio de coste"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,create_date:"
|
||||
msgid "Create Date"
|
||||
msgstr "Fecha de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,create_uid:"
|
||||
msgid "Create User"
|
||||
msgstr "Usuario de creación"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,id:"
|
||||
msgid "ID"
|
||||
msgstr "Identificador"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,last_purchase_price:"
|
||||
msgid "Last Purchase Price"
|
||||
msgstr "Último precio de compra"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,plan:"
|
||||
msgid "Plan"
|
||||
msgstr "Plan"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,product:"
|
||||
msgid "Product"
|
||||
msgstr "Producto"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,product_cost_price:"
|
||||
msgid "Product Cost Price"
|
||||
msgstr "Precio de coste del producto"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,quantity:"
|
||||
msgid "Quantity"
|
||||
msgstr "Cantidad"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,rec_name:"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,total:"
|
||||
msgid "Total Cost"
|
||||
msgstr "Coste total"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,uom:"
|
||||
msgid "Uom"
|
||||
msgstr "UdM"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,uom_category:"
|
||||
msgid "Uom Category"
|
||||
msgstr "Categoría de UdM"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,write_date:"
|
||||
msgid "Write Date"
|
||||
msgstr "Fecha modificación"
|
||||
|
||||
msgctxt "field:product.cost.plan.product_line,write_uid:"
|
||||
msgid "Write User"
|
||||
msgstr "Usuario modificación"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Plan de coste del producto"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan_bom_line"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Plan de coste del producto"
|
||||
|
||||
msgctxt "model:ir.action,name:act_product_cost_plan_product_line"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Linea de producto Plan de coste del producto"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Plan de coste del producto"
|
||||
|
||||
msgctxt "model:product.cost.plan,name:"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Plan de coste del producto"
|
||||
|
||||
msgctxt "model:product.cost.plan.bom_line,name:"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Plan de coste del producto"
|
||||
|
||||
msgctxt "model:product.cost.plan.product_line,name:"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Linea de producto Plan de coste del producto"
|
||||
|
||||
msgctxt "model:res.group,name:group_product_cost_plan"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Plan de coste del producto"
|
||||
|
||||
msgctxt "model:res.group,name:group_product_cost_plan_admin"
|
||||
msgid "Product Cost Plan Administration"
|
||||
msgstr "Administración Plan de coste del producto"
|
||||
|
||||
msgctxt "selection:product.cost.plan,state:"
|
||||
msgid "Computed"
|
||||
msgstr "Calculado"
|
||||
|
||||
msgctxt "selection:product.cost.plan,state:"
|
||||
msgid "Draft"
|
||||
msgstr "Borrador"
|
||||
|
||||
msgctxt "view:product.cost.plan.bom_line:"
|
||||
msgid "Product Cost Plan BOM"
|
||||
msgstr "LdM Plan de coste del producto"
|
||||
|
||||
msgctxt "view:product.cost.plan.product_line:"
|
||||
msgid "Product Cost Plan Product Line"
|
||||
msgstr "Linea de producto Plan de coste del producto"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "BOM Configuration"
|
||||
msgstr "Configuración lista de material"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Compute"
|
||||
msgstr "Calcular"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "General"
|
||||
msgstr "General"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Product Cost Plan"
|
||||
msgstr "Plan de coste del producto"
|
||||
|
||||
msgctxt "view:product.cost.plan:"
|
||||
msgid "Reset"
|
||||
msgstr "Reiniciar"
|
186
plan.py
186
plan.py
|
@ -9,14 +9,25 @@ __all__ = ['Plan', 'PlanBOM', 'PlanProductLine']
|
|||
class Plan(Workflow, ModelSQL, ModelView):
|
||||
'Product Cost Plan'
|
||||
__name__ = 'product.cost.plan'
|
||||
product = fields.Many2One('product.product', 'Product', required=True)
|
||||
|
||||
product = fields.Many2One('product.product', 'Product', required=True,
|
||||
states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
}, depends=['state'], on_change=['product', 'bom', 'boms'])
|
||||
bom = fields.Many2One('production.bom', 'BOM', on_change_with=['product'],
|
||||
required=True)
|
||||
required=True, states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
}, depends=['state', 'product'],
|
||||
domain=[
|
||||
('output_products', '=', Eval('product', 0)),
|
||||
],)
|
||||
boms = fields.One2Many('product.cost.plan.bom_line', 'plan', 'BOMs',
|
||||
states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
}, depends=['state'], on_change_with=['bom'])
|
||||
quantity = fields.Float('Quantity', required=True)
|
||||
}, depends=['state'], on_change_with=['bom', 'boms'])
|
||||
quantity = fields.Float('Quantity', required=True, states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
}, depends=['state'])
|
||||
products = fields.One2Many('product.cost.plan.product_line', 'plan',
|
||||
'Products', states={
|
||||
'readonly': Eval('state') == 'draft',
|
||||
|
@ -24,7 +35,7 @@ class Plan(Workflow, ModelSQL, ModelView):
|
|||
product_cost = fields.Function(fields.Numeric('Product Cost',
|
||||
on_change_with=['products']), 'on_change_with_product_cost')
|
||||
total_cost = fields.Function(fields.Numeric('Total Cost',
|
||||
on_change_with=['products']),
|
||||
on_change_with=['product_cost']),
|
||||
'on_change_with_total_cost')
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
|
@ -39,11 +50,13 @@ class Plan(Workflow, ModelSQL, ModelView):
|
|||
('computed', 'draft'),
|
||||
))
|
||||
cls._buttons.update({
|
||||
'confirm': {
|
||||
'invisible': Eval('state') == 'confirmed',
|
||||
'compute': {
|
||||
'invisible': Eval('state') == 'computed',
|
||||
'icon': 'tryton-go-next',
|
||||
},
|
||||
'reset': {
|
||||
'invisible': Eval('state') == 'draft',
|
||||
'icon': 'tryton-go-previous',
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -51,16 +64,45 @@ class Plan(Workflow, ModelSQL, ModelView):
|
|||
def default_state():
|
||||
return 'draft'
|
||||
|
||||
def on_change_product(self):
|
||||
res = {'bom': None}
|
||||
bom = self.on_change_with_bom()
|
||||
self.bom = bom
|
||||
res['boms'] = self.on_change_with_boms()
|
||||
return res
|
||||
|
||||
def on_change_with_bom(self):
|
||||
BOM = Pool().get('production.bom')
|
||||
product_id = self.product.id if self.product else None
|
||||
boms = BOM.search([('output_products', '=', product_id)])
|
||||
if not self.product:
|
||||
return
|
||||
boms = BOM.search([('output_products', '=', self.product.id)])
|
||||
if boms:
|
||||
return boms[0].id
|
||||
return None
|
||||
|
||||
def on_change_with_boms(self):
|
||||
return []
|
||||
boms = {
|
||||
'remove': [x.id for x in self.boms],
|
||||
'add': [],
|
||||
}
|
||||
if not self.bom:
|
||||
return boms
|
||||
|
||||
def find_boms(inputs):
|
||||
res = []
|
||||
for input_ in inputs:
|
||||
if input_.product.boms:
|
||||
res.append(input_.product.id)
|
||||
for product_bom in input_.product.boms:
|
||||
if product_bom.bom and product_bom.bom.inputs:
|
||||
res.extend(find_boms(product_bom.bom.inputs))
|
||||
return res
|
||||
|
||||
products = set(find_boms(self.bom.inputs))
|
||||
for product in products:
|
||||
boms['add'].append({
|
||||
'product': product,
|
||||
})
|
||||
return boms
|
||||
|
||||
def on_change_with_product_cost(self, name=None):
|
||||
cost = Decimal('0.0')
|
||||
|
@ -73,34 +115,134 @@ class Plan(Workflow, ModelSQL, ModelView):
|
|||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('confirmed')
|
||||
@Workflow.transition('draft')
|
||||
def reset(cls, plans):
|
||||
pool = Pool()
|
||||
ProductLines = pool.get('product.cost.plan.product_line')
|
||||
|
||||
to_delete = []
|
||||
for plan in plans:
|
||||
to_delete.extend(plan.products)
|
||||
|
||||
if to_delete:
|
||||
ProductLines.delete(to_delete)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('computed')
|
||||
def compute(cls, plans):
|
||||
'''
|
||||
Create all necessary products and operations
|
||||
'''
|
||||
pass
|
||||
pool = Pool()
|
||||
ProductLines = pool.get('product.cost.plan.product_line')
|
||||
|
||||
to_create = []
|
||||
for plan in plans:
|
||||
to_create.extend(plan.explode_bom(plan.product, plan.bom,
|
||||
plan.quantity, plan.product.default_uom))
|
||||
if to_create:
|
||||
ProductLines.create(to_create)
|
||||
|
||||
def explode_bom(self, product, bom, quantity, uom):
|
||||
" Returns products for the especified products"
|
||||
pool = Pool()
|
||||
Input = pool.get('production.bom.input')
|
||||
res = []
|
||||
|
||||
plan_boms = {}
|
||||
for plan_bom in self.boms:
|
||||
if plan_bom.bom:
|
||||
plan_boms[plan_bom.product.id] = plan_bom.bom
|
||||
|
||||
factor = bom.compute_factor(product, quantity, uom)
|
||||
|
||||
for input_ in bom.inputs:
|
||||
product = input_.product
|
||||
if product.id in plan_boms:
|
||||
quantity = Input.compute_quantity(input_, factor)
|
||||
res.extend(self.explode_bom(product, plan_boms[product.id],
|
||||
quantity, input_.uom))
|
||||
else:
|
||||
line = self.get_product_line(input_, factor)
|
||||
if line:
|
||||
line['plan'] = self.id
|
||||
res.append(line)
|
||||
return res
|
||||
|
||||
def get_product_line(self, input_, factor):
|
||||
"""
|
||||
Returns a dict with values of the new line to create
|
||||
params:
|
||||
*input_*: Production.bom.input record for the product
|
||||
*factor*: The factor to calculate the quantity
|
||||
"""
|
||||
pool = Pool()
|
||||
Input = pool.get('production.bom.input')
|
||||
quantity = Input.compute_quantity(input_, factor)
|
||||
return {
|
||||
'product': input_.product.id,
|
||||
'quantity': quantity,
|
||||
'uom': input_.uom.id,
|
||||
'product_cost_price': input_.product.cost_price,
|
||||
'cost_price': input_.product.cost_price,
|
||||
}
|
||||
|
||||
|
||||
class PlanBOM(ModelSQL, ModelView):
|
||||
'Product Cost Plan BOM'
|
||||
__name__ = 'product.cost.plan.bom_line'
|
||||
|
||||
plan = fields.Many2One('product.cost.plan', 'Plan', required=True)
|
||||
product = fields.Many2One('product.product', 'Product', required=True)
|
||||
bom = fields.Many2One('production.bom', 'BOM')
|
||||
bom = fields.Many2One('production.bom', 'BOM', domain=[
|
||||
('output_products', '=', Eval('product', 0)),
|
||||
], depends=['product'])
|
||||
|
||||
|
||||
class PlanProductLine(ModelSQL, ModelView):
|
||||
'Product Cost Plan Product Line'
|
||||
__name__ = 'product.cost.plan.product_line'
|
||||
|
||||
plan = fields.Many2One('product.cost.plan', 'Plan', required=True)
|
||||
product = fields.Many2One('product.product', 'Product', required=True)
|
||||
product = fields.Many2One('product.product', 'Product', required=True,
|
||||
domain=[
|
||||
('type', '!=', 'service'),
|
||||
], on_change=['product', 'uom'])
|
||||
quantity = fields.Float('Quantity', required=True)
|
||||
uom_category = fields.Function(fields.Many2One(
|
||||
'product.uom.category', 'Uom Category',
|
||||
on_change_with=['product']), 'on_change_with_uom_category')
|
||||
uom = fields.Many2One('product.uom', 'Uom', required=True,
|
||||
domain=[
|
||||
('category', '=', Eval('uom_category')),
|
||||
], depends=['uom_category'])
|
||||
product_cost_price = fields.Numeric('Product Cost Price', required=True)
|
||||
last_purchase_price = fields.Numeric('Last Purchase Price')
|
||||
cost_price = fields.Numeric('Cost Price', required=True)
|
||||
total = fields.Function(fields.Numeric('Total Cost', on_change_with=[
|
||||
'quantity', 'cost_price']), 'on_change_with_total')
|
||||
'quantity', 'cost_price', 'uom', 'product']),
|
||||
'on_change_with_total')
|
||||
|
||||
def on_change_with_total(self):
|
||||
return ((self.quantity or Decimal('0.0'))
|
||||
* (self.cost_price or Decimal('0.0')))
|
||||
def on_change_product(self):
|
||||
res = {}
|
||||
if self.product:
|
||||
uoms = self.product.default_uom.category.uoms
|
||||
if (not self.uom or self.uom not in uoms):
|
||||
res['uom'] = self.product.default_uom.id
|
||||
res['uom.rec_name'] = self.product.default_uom.rec_name
|
||||
res['product_cost'] = self.product.cost_price
|
||||
else:
|
||||
res['uom'] = None
|
||||
res['uom.rec_name'] = ''
|
||||
res['product_cost'] = None
|
||||
return res
|
||||
|
||||
def on_change_with_uom_category(self, name=None):
|
||||
if self.product:
|
||||
return self.product.default_uom.category.id
|
||||
|
||||
def on_change_with_total(self, name=None):
|
||||
pool = Pool()
|
||||
Uom = pool.get('product.uom')
|
||||
quantity = Uom.compute_qty(self.uom, self.quantity,
|
||||
self.product.default_uom, round=False)
|
||||
|
||||
return Decimal(str(quantity)) * (self.cost_price or Decimal('0.0'))
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
===================
|
||||
Production Scenario
|
||||
===================
|
||||
|
||||
=============
|
||||
General Setup
|
||||
=============
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime
|
||||
>>> from dateutil.relativedelta import relativedelta
|
||||
>>> from decimal import Decimal
|
||||
>>> from proteus import config, Model, Wizard
|
||||
>>> today = datetime.date.today()
|
||||
|
||||
Create database::
|
||||
|
||||
>>> config = config.set_trytond()
|
||||
>>> config.pool.test = True
|
||||
|
||||
Install production Module::
|
||||
|
||||
>>> Module = Model.get('ir.module.module')
|
||||
>>> modules = Module.find([('name', '=', 'product_cost_plan')])
|
||||
>>> Module.install([x.id for x in modules], config.context)
|
||||
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> Currency = Model.get('currency.currency')
|
||||
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||
>>> Company = Model.get('company.company')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> company_config = Wizard('company.company.config')
|
||||
>>> company_config.execute('company')
|
||||
>>> company = company_config.form
|
||||
>>> party = Party(name='Dunder Mifflin')
|
||||
>>> party.save()
|
||||
>>> company.party = party
|
||||
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||
>>> if not currencies:
|
||||
... currency = Currency(name='Euro', symbol=u'$', code='USD',
|
||||
... rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
|
||||
... mon_decimal_point=',')
|
||||
... currency.save()
|
||||
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||
... rate=Decimal('1.0'), currency=currency).save()
|
||||
... else:
|
||||
... currency, = currencies
|
||||
>>> company.currency = currency
|
||||
>>> company_config.execute('add')
|
||||
>>> company, = Company.find()
|
||||
|
||||
Reload the context::
|
||||
|
||||
>>> User = Model.get('res.user')
|
||||
>>> config._context = User.get_preferences(True, config.context)
|
||||
|
||||
Configuration production location::
|
||||
|
||||
>>> Location = Model.get('stock.location')
|
||||
>>> warehouse, = Location.find([('code', '=', 'WH')])
|
||||
>>> production_location, = Location.find([('code', '=', 'PROD')])
|
||||
>>> warehouse.production_location = production_location
|
||||
>>> warehouse.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> product = Product()
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'goods'
|
||||
>>> template.list_price = Decimal(30)
|
||||
>>> template.cost_price = Decimal(20)
|
||||
>>> template.save()
|
||||
>>> product.template = template
|
||||
>>> product.save()
|
||||
|
||||
Create Components::
|
||||
|
||||
>>> meter, = ProductUom.find([('name', '=', 'Meter')])
|
||||
>>> centimeter, = ProductUom.find([('name', '=', 'centimeter')])
|
||||
>>> componentA = Product()
|
||||
>>> templateA = ProductTemplate()
|
||||
>>> templateA.name = 'component A'
|
||||
>>> templateA.default_uom = meter
|
||||
>>> templateA.type = 'goods'
|
||||
>>> templateA.list_price = Decimal(2)
|
||||
>>> templateA.cost_price = Decimal(1)
|
||||
>>> templateA.save()
|
||||
>>> componentA.template = templateA
|
||||
>>> componentA.save()
|
||||
|
||||
>>> componentB = Product()
|
||||
>>> templateB = ProductTemplate()
|
||||
>>> templateB.name = 'component B'
|
||||
>>> templateB.default_uom = meter
|
||||
>>> templateB.type = 'goods'
|
||||
>>> templateB.list_price = Decimal(2)
|
||||
>>> templateB.cost_price = Decimal(1)
|
||||
>>> templateB.save()
|
||||
>>> componentB.template = templateB
|
||||
>>> componentB.save()
|
||||
|
||||
>>> component1 = Product()
|
||||
>>> template1 = ProductTemplate()
|
||||
>>> template1.name = 'component 1'
|
||||
>>> template1.default_uom = unit
|
||||
>>> template1.type = 'goods'
|
||||
>>> template1.list_price = Decimal(5)
|
||||
>>> template1.cost_price = Decimal(2)
|
||||
>>> template1.save()
|
||||
>>> component1.template = template1
|
||||
>>> component1.save()
|
||||
|
||||
>>> component2 = Product()
|
||||
>>> template2 = ProductTemplate()
|
||||
>>> template2.name = 'component 2'
|
||||
>>> template2.default_uom = meter
|
||||
>>> template2.type = 'goods'
|
||||
>>> template2.list_price = Decimal(7)
|
||||
>>> template2.cost_price = Decimal(5)
|
||||
>>> template2.save()
|
||||
>>> component2.template = template2
|
||||
>>> component2.save()
|
||||
|
||||
Create Bill of Material::
|
||||
|
||||
>>> BOM = Model.get('production.bom')
|
||||
>>> BOMInput = Model.get('production.bom.input')
|
||||
>>> BOMOutput = Model.get('production.bom.output')
|
||||
>>> component_bom = BOM(name='component1')
|
||||
>>> input1 = BOMInput()
|
||||
>>> component_bom.inputs.append(input1)
|
||||
>>> input1.product = componentA
|
||||
>>> input1.quantity = 1
|
||||
>>> input2 = BOMInput()
|
||||
>>> component_bom.inputs.append(input2)
|
||||
>>> input2.product = componentB
|
||||
>>> input2.quantity = 1
|
||||
>>> output = BOMOutput()
|
||||
>>> component_bom.outputs.append(output)
|
||||
>>> output.product = component1
|
||||
>>> output.quantity = 1
|
||||
>>> component_bom.save()
|
||||
|
||||
>>> ProductBom = Model.get('product.product-production.bom')
|
||||
>>> component1.boms.append(ProductBom(bom=component_bom))
|
||||
>>> component1.save()
|
||||
|
||||
>>> bom = BOM(name='product')
|
||||
>>> input1 = BOMInput()
|
||||
>>> bom.inputs.append(input1)
|
||||
>>> input1.product = component1
|
||||
>>> input1.quantity = 5
|
||||
>>> input2 = BOMInput()
|
||||
>>> bom.inputs.append(input2)
|
||||
>>> input2.product = component2
|
||||
>>> input2.quantity = 150
|
||||
>>> input2.uom = centimeter
|
||||
>>> output = BOMOutput()
|
||||
>>> bom.outputs.append(output)
|
||||
>>> output.product = product
|
||||
>>> output.quantity = 1
|
||||
>>> bom.save()
|
||||
|
||||
>>> ProductBom = Model.get('product.product-production.bom')
|
||||
>>> product.boms.append(ProductBom(bom=bom))
|
||||
>>> product.save()
|
||||
|
||||
Create a cost plan for product (without child boms)::
|
||||
|
||||
>>> CostPlan = Model.get('product.cost.plan')
|
||||
>>> plan = CostPlan()
|
||||
>>> plan.product = product
|
||||
>>> len(plan.boms) == 1
|
||||
True
|
||||
>>> plan.boms[0].bom == None
|
||||
True
|
||||
>>> plan.quantity = 10
|
||||
>>> plan.save()
|
||||
>>> plan.state
|
||||
u'draft'
|
||||
>>> CostPlan.compute([plan.id], config.context)
|
||||
>>> plan.reload()
|
||||
>>> plan.state
|
||||
u'computed'
|
||||
>>> len(plan.products) == 2
|
||||
True
|
||||
>>> c1, = plan.products.find([
|
||||
... ('product', '=', component1.id),
|
||||
... ], limit=1)
|
||||
>>> c1.quantity == 50.0
|
||||
True
|
||||
>>> c2, = plan.products.find([
|
||||
... ('product', '=', component2.id),
|
||||
... ], limit=1)
|
||||
>>> c2.quantity == 1500.0
|
||||
True
|
||||
>>> cA = plan.products.find([
|
||||
... ('product', '=', componentA.id),
|
||||
... ], limit=1)
|
||||
>>> len(cA) == 0
|
||||
True
|
||||
>>> cB = plan.products.find([
|
||||
... ('product', '=', componentB.id),
|
||||
... ], limit=1)
|
||||
>>> len(cB) == 0
|
||||
True
|
||||
>>> plan.total_cost == Decimal('175.0')
|
||||
True
|
||||
|
||||
Create a cost plan for product (with child boms)::
|
||||
|
||||
>>> CostPlan = Model.get('product.cost.plan')
|
||||
>>> plan = CostPlan()
|
||||
>>> plan.product = product
|
||||
>>> len(plan.boms) == 1
|
||||
True
|
||||
>>> plan.quantity = 10
|
||||
>>> plan.save()
|
||||
>>> plan.state
|
||||
u'draft'
|
||||
>>> for product_bom in plan.boms:
|
||||
... product_bom.bom = product_bom.product.boms[0]
|
||||
... product_bom.save()
|
||||
>>> plan.reload()
|
||||
>>> CostPlan.compute([plan.id], config.context)
|
||||
>>> plan.reload()
|
||||
>>> plan.state
|
||||
u'computed'
|
||||
>>> len(plan.products) == 3
|
||||
True
|
||||
>>> cA, = plan.products.find([
|
||||
... ('product', '=', componentA.id),
|
||||
... ], limit=1)
|
||||
>>> cA.quantity == 50.0
|
||||
True
|
||||
>>> cB, = plan.products.find([
|
||||
... ('product', '=', componentB.id),
|
||||
... ], limit=1)
|
||||
>>> cB.quantity == 50.0
|
||||
True
|
||||
>>> c2, = plan.products.find([
|
||||
... ('product', '=', component2.id),
|
||||
... ], limit=1)
|
||||
>>> c2.quantity == 1500.0
|
||||
True
|
||||
>>> plan.total_cost == Decimal('175.0')
|
||||
True
|
||||
|
|
@ -10,7 +10,7 @@ if os.path.isdir(DIR):
|
|||
sys.path.insert(0, os.path.dirname(DIR))
|
||||
|
||||
import unittest
|
||||
#import doctest TODO: Remove if no sceneario needed.
|
||||
import doctest
|
||||
import trytond.tests.test_tryton
|
||||
from trytond.tests.test_tryton import test_view, test_depends
|
||||
from trytond.backend.sqlite.database import Database as SQLiteDatabase
|
||||
|
@ -50,10 +50,9 @@ def doctest_dropdb(test):
|
|||
def suite():
|
||||
suite = trytond.tests.test_tryton.suite()
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
|
||||
# TODO: remove if no scenario needed.
|
||||
#suite.addTests(doctest.DocFileSuite('scenario_invoice.rst',
|
||||
# setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
|
||||
# optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
suite.addTests(doctest.DocFileSuite('scenario_product_cost_plan.rst',
|
||||
setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
return suite
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -21,8 +21,12 @@
|
|||
<label name="total_cost"/>
|
||||
<field name="total_cost"/>
|
||||
<newline/>
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
<button name="compute"/>
|
||||
<button name="reset"/>
|
||||
<group id="state" colspan="6">
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
<group id="buttons" colspan="2">
|
||||
<button name="compute" string="Compute"/>
|
||||
<button name="reset" string="Reset"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<form string="Product Cost Plan Product Line">
|
||||
<label name="plan"/>
|
||||
<field name="plan"/>
|
||||
<newline/>
|
||||
<label name="product"/>
|
||||
<field name="product"/>
|
||||
<label name="plan"/>
|
||||
<field name="plan"/>
|
||||
<label name="quantity"/>
|
||||
<field name="quantity"/>
|
||||
<label name="uom"/>
|
||||
<field name="uom"/>
|
||||
<label name="product_cost_price"/>
|
||||
<field name="product_cost_price"/>
|
||||
<label name="last_purchase_price"/>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<field name="plan"/>
|
||||
<field name="product"/>
|
||||
<field name="quantity"/>
|
||||
<field name="uom"/>
|
||||
<field name="product_cost_price"/>
|
||||
<field name="cost_price"/>
|
||||
<field name="last_purchase_price"/>
|
||||
|
|
Loading…
Reference in New Issue