implemented funcionality

This commit is contained in:
?ngel ?lvarez 2013-12-29 13:38:44 +01:00
parent c13730e4f7
commit 17c14ffd71
13 changed files with 898 additions and 65 deletions

View File

@ -2,7 +2,11 @@
#copyright notices and license terms.
from trytond.pool import Pool
from .plan import *
def register():
Pool.register(
PlanOperationLine,
Plan,
module='product_cost_plan_operation', type_='model')

91
locale/ca_ES.po Normal file
View File

@ -0,0 +1,91 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.cost.plan,operation_cost:"
msgid "Operation Cost"
msgstr "Cost operació"
msgctxt "field:product.cost.plan,operations:"
msgid "Operation Lines"
msgstr "Línies d'operacions"
msgctxt "field:product.cost.plan,route:"
msgid "Route"
msgstr "Ruta"
msgctxt "field:product.cost.plan.operation_line,cost:"
msgid "Cost"
msgstr "Cost"
msgctxt "field:product.cost.plan.operation_line,create_date:"
msgid "Create Date"
msgstr "Data de creació"
msgctxt "field:product.cost.plan.operation_line,create_uid:"
msgid "Create User"
msgstr "Usuari de creació"
msgctxt "field:product.cost.plan.operation_line,id:"
msgid "ID"
msgstr "Identificador"
msgctxt "field:product.cost.plan.operation_line,plan:"
msgid "Plan"
msgstr "Pla"
msgctxt "field:product.cost.plan.operation_line,quantity:"
msgid "Quantity"
msgstr "Quantitat"
msgctxt "field:product.cost.plan.operation_line,rec_name:"
msgid "Name"
msgstr "Nom del camp"
msgctxt "field:product.cost.plan.operation_line,route_operation:"
msgid "Route Operation"
msgstr "Ruta"
msgctxt "field:product.cost.plan.operation_line,unit_digits:"
msgid "Unit Digits"
msgstr "Decimals unitaris"
msgctxt "field:product.cost.plan.operation_line,uom:"
msgid "Uom"
msgstr "UdM"
msgctxt "field:product.cost.plan.operation_line,uom_category:"
msgid "Uom Category"
msgstr "Categoria d'UdM"
msgctxt "field:product.cost.plan.operation_line,work_center:"
msgid "Work Center"
msgstr "Centre de treball"
msgctxt "field:product.cost.plan.operation_line,write_date:"
msgid "Write Date"
msgstr "Data modificació"
msgctxt "field:product.cost.plan.operation_line,write_uid:"
msgid "Write User"
msgstr "Usuari modificació"
msgctxt "model:ir.action,name:act_product_cost_plan_operation_line"
msgid "Product Cost Plan Operation"
msgstr "Operació del Pla de costos del producte"
msgctxt "model:product.cost.plan.operation_line,name:"
msgid "Product Cost Plan Operation Line"
msgstr "Operació del Pla de costos del producte"
msgctxt "view:product.cost.plan.operation_line:"
msgid "Product Cost Plan BOM"
msgstr "LdM Pla de costos de producte"
msgctxt "view:product.cost.plan.operation_line:"
msgid "Product Cost Plan Operation"
msgstr "Operació del Pla de costos del producte"
msgctxt "view:product.cost.plan:"
msgid "Operations"
msgstr "Operacions"

91
locale/es_ES.po Normal file
View File

@ -0,0 +1,91 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.cost.plan,operation_cost:"
msgid "Operation Cost"
msgstr "Coste operación"
msgctxt "field:product.cost.plan,operations:"
msgid "Operation Lines"
msgstr "Lineas operaciones"
msgctxt "field:product.cost.plan,route:"
msgid "Route"
msgstr "Ruta"
msgctxt "field:product.cost.plan.operation_line,cost:"
msgid "Cost"
msgstr "Coste"
msgctxt "field:product.cost.plan.operation_line,create_date:"
msgid "Create Date"
msgstr "Fecha de creación"
msgctxt "field:product.cost.plan.operation_line,create_uid:"
msgid "Create User"
msgstr "Usuario de creación"
msgctxt "field:product.cost.plan.operation_line,id:"
msgid "ID"
msgstr "Identificador"
msgctxt "field:product.cost.plan.operation_line,plan:"
msgid "Plan"
msgstr "Plan"
msgctxt "field:product.cost.plan.operation_line,quantity:"
msgid "Quantity"
msgstr "Cantidad"
msgctxt "field:product.cost.plan.operation_line,rec_name:"
msgid "Name"
msgstr "Nom del camp"
msgctxt "field:product.cost.plan.operation_line,route_operation:"
msgid "Route Operation"
msgstr "Ruta de operación"
msgctxt "field:product.cost.plan.operation_line,unit_digits:"
msgid "Unit Digits"
msgstr "Dígitos unidad"
msgctxt "field:product.cost.plan.operation_line,uom:"
msgid "Uom"
msgstr "UdM"
msgctxt "field:product.cost.plan.operation_line,uom_category:"
msgid "Uom Category"
msgstr "Categoría de UdM"
msgctxt "field:product.cost.plan.operation_line,work_center:"
msgid "Work Center"
msgstr "Centro de trabajo"
msgctxt "field:product.cost.plan.operation_line,write_date:"
msgid "Write Date"
msgstr "Fecha modificación"
msgctxt "field:product.cost.plan.operation_line,write_uid:"
msgid "Write User"
msgstr "Usuario modificación"
msgctxt "model:ir.action,name:act_product_cost_plan_operation_line"
msgid "Product Cost Plan Operation"
msgstr "Operación de Plan de coste del producto"
msgctxt "model:product.cost.plan.operation_line,name:"
msgid "Product Cost Plan Operation Line"
msgstr "Operación de Plan de coste del producto"
msgctxt "view:product.cost.plan.operation_line:"
msgid "Product Cost Plan BOM"
msgstr "LdM Plan de coste del producto"
msgctxt "view:product.cost.plan.operation_line:"
msgid "Product Cost Plan Operation"
msgstr "Operación de Plan de coste del producto"
msgctxt "view:product.cost.plan:"
msgid "Operations"
msgstr "Operaciones"

152
plan.py
View File

@ -1,67 +1,113 @@
from decimal import Decimal
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
class PlanOperationLine:
__all__ = ['PlanOperationLine', 'Plan']
__metaclass__ = PoolMeta
class PlanOperationLine(ModelSQL, ModelView):
'Product Cost Plan Operation Line'
__name__ = 'product.cost.plan.operation_line'
plan = fields.Many2One('product.cost.plan', 'Plan', required=True)
product = fields.Many2One('product.product', 'Product', required=True)
quantity = fields.Float('Quantity', required=True)
product_cost_price = fields.Numeric('Product Cost Price', required=True)
cost_price = fields.Numeric('Cost Price', required=True)
work_center = fields.Many2One('production.work_center', 'Work Center',
required=True)
route_operation = fields.Many2One('production.route.operation',
'Route Operation')
uom_category = fields.Function(fields.Many2One(
'product.uom.category', 'Uom Category', on_change_with=[
'work_center']),
'on_change_with_uom_category')
uom = fields.Many2One('product.uom', 'Uom', required=True, domain=[
('category', '=', Eval('uom_category')),
], depends=['uom_category'], on_change_with=['work_center'])
unit_digits = fields.Function(fields.Integer('Unit Digits',
on_change_with=['uom']), 'on_change_with_unit_digits')
quantity = fields.Float('Quantity', required=True,
digits=(16, Eval('unit_digits', 2)), depends=['unit_digits'])
cost = fields.Function(fields.Numeric('Cost', on_change_with=['quantity',
'cost_price', 'uom', 'work_center']), 'on_change_with_cost')
def on_change_with_uom_category(self, name=None):
if self.work_center:
return self.work_center.uom.category.id
def on_change_with_uom(self):
if self.work_center:
return self.work_center.uom.id
def on_change_with_unit_digits(self, name=None):
if self.uom:
return self.uom.digits
return 2
def on_change_with_cost(self, name=None):
pool = Pool()
Uom = pool.get('product.uom')
quantity = Uom.compute_qty(self.uom, self.quantity,
self.work_center.uom)
return Decimal(str(quantity)) * self.work_center.cost_price
class Plan:
__name__ = 'product.cost.plan'
route = fields.Many2One('production.route', 'Route',
on_change=['route', 'operations'], states={
'readonly': Eval('state') != 'draft',
}, depends=['state'])
operations = fields.One2Many('product.cost.plan.operation_line', 'plan',
'Operation Lines')
'Operation Lines', states={
'readonly': Eval('state') != 'draft',
}, depends=['state'])
operation_cost = fields.Function(fields.Numeric('Operation Cost',
on_change_with=['operations']), 'on_change_with_operation_cost')
@classmethod
def get_margins(cls, plans, names):
res = {}
for plan in plans:
# TODO:
pass
return res
def update_operations(self):
pool = Pool()
WorkCenter = pool.get('production.work_center')
if not self.route:
return {}
operations = {
'remove': [x.id for x in self.operations],
'add': [],
}
changes = {
'operations': operations,
}
for operation in self.route.operations:
work_center = None
if operation.work_center:
work_center = operation.work_center
elif operation.work_center_category:
centers = WorkCenter.search([
('category', '=', operation.work_center_category),
], limit=1)
if centers:
work_center, = centers
@classmethod
@ModelView.button
@Workflow.transition('confirmed')
def confirm(cls, productions):
'''
Create margins lines
'''
pass
if not work_center:
self.raise_user_error('no_work_center', operation.rec_name)
operations['add'].append({
'work_center': work_center.id,
'route_operation': operation.id,
'uom': work_center.uom.id,
'quantity': 0.0,
})
return changes
# Mòdul: product_cost_plan_teb
def on_change_route(self):
return self.update_operations()
class Plan:
__name__ = 'product.cost.plan'
party = fields.Many2One('party.party', 'Party')
payment_term = fields.Many2One('account.invoice.payment_term',
'Payment Term', on_change_with=['party'])
commission = fields.Float('Commission %', required=True)
# TODO: Add here??
pallet = fields.Boolean('TEB Pallet?')
pallet_quantity = fields.fields.Float('Quantity per Pallet')
def on_change_with_total_cost(self, name=None):
cost = super(Plan, self).on_change_with_total_cost(name)
return cost + self.operation_cost
@staticmethod
def default_commission():
return 0.0
def on_change_with_payment_term(self):
return (self.party.customer_payment_term.id
if self.party and self.party.customer_payment_term else None)
@classmethod
@ModelView.button
@Workflow.transition('confirmed')
def confirm(cls, productions):
'''
Create:
- payment term cost/margin
- commission cost/margin
- pallet cost/margin
'''
pass
# TODO: Comptabilitat analítica, despeses estructurals, transport
def on_change_with_operation_cost(self, name=None):
cost = Decimal('0.0')
for operation in self.operations:
cost += operation.cost
return cost

70
plan.xml Normal file
View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<tryton>
<data>
<record model="ir.ui.view" id="product_cost_plan_view_form">
<field name="model">product.cost.plan</field>
<field name="type">form</field>
<field name="name">cost_plan_form</field>
<field name="inherit"
ref="product_cost_plan.product_cost_plan_view_form"/>
</record>
<record model="ir.ui.view" id="product_cost_plan_view_list">
<field name="model">product.cost.plan</field>
<field name="type">tree</field>
<field name="name">cost_plan_list</field>
<field name="inherit"
ref="product_cost_plan.product_cost_plan_view_list"/>
</record>
<record model="ir.ui.view"
id="product_cost_plan_operation_line_view_form">
<field name="model">product.cost.plan.operation_line</field>
<field name="type">form</field>
<field name="name">cost_plan_operation_line_form</field>
</record>
<record model="ir.ui.view"
id="product_cost_plan_operation_line_view_list">
<field name="model">product.cost.plan.operation_line</field>
<field name="type">tree</field>
<field name="name">cost_plan_operation_line_list</field>
</record>
<record model="ir.action.act_window"
id="act_product_cost_plan_operation_line">
<field name="name">Product Cost Plan Operation</field>
<field name="res_model">product.cost.plan.operation_line</field>
</record>
<record model="ir.action.act_window.view"
id="act_product_cost_plan_operation_line_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="product_cost_plan_operation_line_view_list"/>
<field name="act_window" ref="act_product_cost_plan_operation_line"/>
</record>
<record model="ir.action.act_window.view"
id="act_product_cost_plan_operation_line_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="product_cost_plan_operation_line_view_form"/>
<field name="act_window" ref="act_product_cost_plan_operation_line"/>
</record>
<record model="ir.model.access"
id="access_product_cost_plan_operation_line">
<field name="model"
search="[('model', '=', 'product.cost.plan.operation_line')]"/>
<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_product_cost_plan_operation_line_admin">
<field name="model"
search="[('model', '=', 'product.cost.plan.operation_line')]"/>
<field name="group"
ref="product_cost_plan.group_product_cost_plan_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>
</data>
</tryton>

View File

@ -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

View File

@ -0,0 +1,222 @@
===================
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_operation')])
>>> 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 a route with two operations on diferent work center::
>>> ProductUom = Model.get('product.uom')
>>> Route = Model.get('production.route')
>>> OperationType = Model.get('production.operation.type')
>>> RouteOperation = Model.get('production.route.operation')
>>> assembly = OperationType(name='Assembly')
>>> assembly.save()
>>> clean = OperationType(name='clean')
>>> clean.save()
>>> WorkCenter = Model.get('production.work_center')
>>> hour, = ProductUom.find([('name', '=', 'Hour')])
>>> workcenter1 = WorkCenter()
>>> workcenter1.name = 'Assembler Machine'
>>> workcenter1.type = 'machine'
>>> workcenter1.uom = hour
>>> workcenter1.cost_price = Decimal('25.0')
>>> workcenter1.save()
>>> workcenter2 = WorkCenter()
>>> workcenter2.name = 'Cleaner Machine'
>>> workcenter2.type = 'machine'
>>> workcenter2.uom = hour
>>> workcenter2.cost_price = Decimal('50.0')
>>> workcenter2.save()
>>> route = Route(name='default route')
>>> route_operation = RouteOperation()
>>> route.operations.append(route_operation)
>>> route_operation.sequence = 1
>>> route_operation.operation_type = assembly
>>> route_operation.work_center = workcenter1
>>> route_operation = RouteOperation()
>>> route.operations.append(route_operation)
>>> route_operation.sequence = 2
>>> route_operation.operation_type = clean
>>> route_operation.work_center = workcenter2
>>> route.save()
>>> route.reload()
>>> len(route.operations) == 2
True
Create product::
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> product = Product()
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.list_price = Decimal(30)
>>> template.cost_price = Decimal(20)
>>> template.save()
>>> product.template = template
>>> product.save()
Create Components::
>>> component1 = Product()
>>> template1 = ProductTemplate()
>>> template1.name = 'component 1'
>>> template1.default_uom = unit
>>> template1.type = 'goods'
>>> template1.list_price = Decimal(5)
>>> template1.cost_price = Decimal(1)
>>> template1.save()
>>> component1.template = template1
>>> component1.save()
>>> meter, = ProductUom.find([('name', '=', 'Meter')])
>>> centimeter, = ProductUom.find([('name', '=', 'centimeter')])
>>> 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')
>>> 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 an Inventory::
>>> Inventory = Model.get('stock.inventory')
>>> InventoryLine = Model.get('stock.inventory.line')
>>> storage, = Location.find([
... ('code', '=', 'STO'),
... ])
>>> inventory = Inventory()
>>> inventory.location = storage
>>> inventory_line1 = InventoryLine()
>>> inventory.lines.append(inventory_line1)
>>> inventory_line1.product = component1
>>> inventory_line1.quantity = 10
>>> inventory_line2 = InventoryLine()
>>> inventory.lines.append(inventory_line2)
>>> inventory_line2.product = component2
>>> inventory_line2.quantity = 5
>>> inventory.save()
>>> Inventory.confirm([inventory.id], config.context)
>>> inventory.state
u'done'
Create a cost plan for product::
>>> CostPlan = Model.get('product.cost.plan')
>>> plan = CostPlan()
>>> plan.product = product
>>> plan.route = route
>>> len(plan.operations) == 2
True
>>> plan.quantity = 10
>>> plan.save()
>>> plan.state
u'draft'
>>> for operation in plan.operations:
... operation.quantity = 1.0
... operation.save()
>>> CostPlan.compute([plan.id], config.context)
>>> plan.reload()
>>> plan.state
u'computed'
>>> len(plan.products) == 2
True
>>> plan.operation_cost == Decimal('75.0')
True
>>> plan.total_cost == plan.product_cost + plan.operation_cost
True

View File

@ -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
@ -24,12 +24,12 @@ class TestCase(unittest.TestCase):
def setUp(self):
trytond.tests.test_tryton.install_module('product_cost_plan_operation')
# def test0005views(self):
# '''
# Test views.
# '''
# test_view('product_cost_plan_operation')
#
def test0005views(self):
'''
Test views.
'''
test_view('product_cost_plan_operation')
def test0006depends(self):
'''
Test depends.
@ -50,10 +50,10 @@ 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_operation.rst',
setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite
if __name__ == '__main__':

View File

@ -1,6 +1,7 @@
[tryton]
version=3.0.0
depends:
production
product_cost_plan
production_operation
xml:
plan.xml

16
view/cost_plan_form.xml Normal file
View File

@ -0,0 +1,16 @@
<?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="/form/field[@name='quantity']" position="after">
<label name="route"/>
<field name="route"/>
</xpath>
<xpath expr="/form/notebook/page[@id='general']" position="after">
<page string="Operations" id="operations">
<field name="operations" colspan="4"/>
<label name="operation_cost"/>
<field name="operation_cost"/>
</page>
</xpath>
</data>

8
view/cost_plan_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='bom']" position="after">
<field name="route"/>
</xpath>
</data>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form string="Product Cost Plan BOM">
<label name="plan"/>
<field name="plan"/>
<newline/>
<label name="route_operation"/>
<field name="route_operation"/>
<label name="work_center"/>
<field name="work_center"/>
<label name="quantity"/>
<field name="quantity"/>
<label name="uom"/>
<field name="uom"/>
</form>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<tree string="Product Cost Plan Operation" editable="bottom">
<field name="plan"/>
<field name="route_operation"/>
<field name="work_center"/>
<field name="quantity"/>
<field name="uom"/>
<field name="cost"/>
</tree>