diff --git a/addons/mrp/__openerp__.py b/addons/mrp/__openerp__.py index f114660aecf..8d1fb018987 100644 --- a/addons/mrp/__openerp__.py +++ b/addons/mrp/__openerp__.py @@ -90,7 +90,6 @@ Dashboard provided by this module: ], 'demo_xml': [ 'mrp_demo.xml', - 'mrp_production_order_demo.yml' ], 'test': [ 'test/order_demo.yml', diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 07c46c13017..d2760deedbd 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -312,6 +312,7 @@ class mrp_bom(osv.osv): phantom = False if bom.type == 'phantom' and not bom.bom_lines: newbom = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties) + if newbom: res = self._bom_explode(cr, uid, self.browse(cr, uid, [newbom])[0], factor*bom.product_qty, properties, addthis=True, level=level+10) result = result + res[0] @@ -579,7 +580,7 @@ class mrp_production(osv.osv): self.write(cr, uid, ids, {'state': 'picking_except'}) return True - def action_compute(self, cr, uid, ids, properties=[]): + def action_compute(self, cr, uid, ids, properties=[], context=None): """ Computes bills of material of a product. @param properties: List containing dictionaries of properties. @return: No. of products. @@ -957,7 +958,7 @@ class mrp_production(osv.osv): destination_location_id = production.product_id.product_tmpl_id.property_stock_production.id if not source_location_id: source_location_id = production.location_src_id.id - move_id = move_obj.create(cr, uid, { + move_id = stock_move.create(cr, uid, { 'name': move_name, 'date': production.date_planned, 'product_id': production_line.product_id.id, @@ -971,7 +972,7 @@ class mrp_production(osv.osv): 'state': 'waiting', 'company_id': production.company_id.id, }) - production.write('move_lines': [(4, move_id)]}, context=context) + production.write({'move_lines': [(4, move_id)]}, context=context) return move_id def action_confirm(self, cr, uid, ids, context=None): diff --git a/addons/mrp/mrp_demo.xml b/addons/mrp/mrp_demo.xml index 4386c492b1f..45958601f05 100644 --- a/addons/mrp/mrp_demo.xml +++ b/addons/mrp/mrp_demo.xml @@ -559,73 +559,160 @@ - + + Default BOM for Shelf of 100cm SHE100 - 129 + 10 1.0 - - Assembly Section - 123 - - - 4.0 - - - + + Side Panel - 125 + 101 2.0 - - Metal Cleats - 127 - + + Assembly Section + 102 + - 12.0 + 4.0 + phantom - 131 + 103 1.0 Rear panel SHE100 + phantom - 133 + 104 3.0 - Shelf 100 + RCK100 + phantom + + + + + 133 + + + 1.0 + RCK100 + + + 1331 + + + + 1.0 + phantom + SPAN100 + + + 1332 + + + + 4.0 + METC000 + + + + 135 + + + 1.0 + SPAN100 + + + 1351 + + + + 0.083 + WOOD010 + + + + Assembly Section + 123 + + + 1.0 + - 135 + 1231 - - 1.0 - - Wood Lintel 4m + 0.25 + + Wood Lintel 0.25m + + + 131 + + + 1.0 + Rear panel SHE100 + + + 1311 + + + + 0.25 + WOOD002 0.25m + + Default BOM for Shelf of 200cm @@ -636,34 +723,14 @@ 1.0 - - Default BOM for KIT Shelf of 100cm - SHE100KIT - 139 - - - 1.0 - phantom - - - - Assembly Section - 143 - - - 4.0 - - - - - Side Panel - 145 - - - 2.0 - - - + 147 @@ -709,18 +776,54 @@ + + Default BOM for KIT Shelf of 100cm + SHE100KIT + 139 + + + 1.0 + phantom + + + + + + Assembly Section + 143 + + + 4.0 + + + + + Side Panel + 145 + + + 2.0 + + + + + - t - + Dozen + bigger - - 5 + + 3 @@ -755,9 +858,10 @@ - + + 1.0 @@ -769,7 +873,7 @@ - + @@ -784,7 +888,7 @@ - + @@ -874,7 +978,7 @@ - + @@ -889,7 +993,7 @@ - + diff --git a/addons/mrp/test/cancel_order.yml b/addons/mrp/test/cancel_order.yml index 76f3a9cec3c..d10b8c1780b 100644 --- a/addons/mrp/test/cancel_order.yml +++ b/addons/mrp/test/cancel_order.yml @@ -1,28 +1,25 @@ - - In order to test effect of cancelling Internal picking on production order, I first confirm order for PC3. + I first confirm order for shirt. - - !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_order3} -- - I check that the related internal picking is waiting availability. -- - !assert {model: mrp.production, id: mrp_production_order3}: - - picking_id.state == 'confirmed' + !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_shirt} - In order to cancel the production order, I first cancel its picking. - !function {model: stock.picking, name: action_cancel}: - model: mrp.production - eval: "[obj(ref('mrp_production_order3')).picking_id.id]" + eval: "[obj(ref('mrp_production_shirt')).picking_id.id]" - Now I cancel the production order. - - !workflow {model: mrp.production, action: button_cancel, ref: mrp_production_order3} + !workflow {model: mrp.production, action: button_cancel, ref: mrp_production_shirt} - Now I check that the production order is cancelled. - - !assert {model: mrp.production, id: mrp_production_order3}: + !assert {model: mrp.production, id: mrp_production_shirt}: - state == 'cancel' - - I remove this production order. + I remove cancelled production order. - - !delete {model: mrp.production, id: mrp_production_order3} + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_shirt"), context=context) + self.unlink(cr, uid, [order.id]) diff --git a/addons/mrp/test/order_demo.yml b/addons/mrp/test/order_demo.yml index 4064262c78f..5015f604ce4 100644 --- a/addons/mrp/test/order_demo.yml +++ b/addons/mrp/test/order_demo.yml @@ -1,12 +1,16 @@ - - !record {model: mrp.bom, id: mrp_bom_metalcleats3}: - product_id: product.product_product_metalcleats0 - + In order to test process of production order, I create Bill of material of Shelf 100cm. - - !record {model: mrp.production, id: mrp_production_shelf}: + !record {model: mrp.bom, id: mrp_bom_defaultbomforshelfofcm0}: + product_id: product.product_product_shelfofcm0 +- + I create Production Order of Shelf 100cm to produce 5.0 Dozen PCE. +- + !record {model: mrp.production, id: mrp_production_shelf100cm}: location_src_id: stock.stock_location_stock location_dest_id: stock.stock_location_output product_id: product.product_product_shelfofcm0 bom_id: mrp_bom_defaultbomforshelfofcm0 + product_uom: product.product_uom_dozen product_qty: 5.0 diff --git a/addons/mrp/test/order_process.yml b/addons/mrp/test/order_process.yml index bced289a2d9..ce1b8864422 100644 --- a/addons/mrp/test/order_process.yml +++ b/addons/mrp/test/order_process.yml @@ -1,11 +1,11 @@ - - I change production qty with 3 Dozen Shelf 100cm. + I change production qty with 5 Dozen Shelf 100cm. - !python {model: change.production.qty}: | context.update({'active_id': ref('mrp_production_shelf100cm')}) - !record {model: change.production.qty, id: mrp_production_qty}: - product_qty: 3.0 + product_qty: 5.0 - !python {model: change.production.qty}: | self.change_prod_qty(cr, uid, [ref("mrp_production_qty")], context=context) @@ -14,38 +14,58 @@ - !python {model: mrp.production}: | order = self.browse(cr, uid, ref("mrp_production_shelf100cm")) - assert move.product_uom.id == ref("product.product_uom_dozen"), "UOM is not correspond." - assert move.product_qty == 3, "Qty is not changed." + assert order.product_uom.id == ref("product.product_uom_dozen"), "UOM is not correspond." + assert order.product_qty == 5, "Qty is not changed." - I compute the production order. - !python {model: mrp.production}: | order = self.browse(cr, uid, ref("mrp_production_shelf100cm"), context=context) - order.action_compute() + order.action_compute(context=context) - I check production lines after compute. - !python {model: mrp.production}: | order = self.browse(cr, uid, ref("mrp_production_shelf100cm"), context=context) - assert len(order.move_lines), "Production lines are not generated." - for line in order.move_lines: - if line.product_id.id == ref('product.product_product_assemblysection0'): - assert line.product_qty == (4.0*3.0*12.0), "Qty is not correspond." + assert len(order.product_lines) == 5, "Production lines are not generated proper." + sidepanel = False + woodlintelm = False + woodmm0 = False + woodmm10 = False + metalcleats = False + for line in order.product_lines: + if line.product_id.id == ref('product.product_product_sidepanel0'): #SIDEPAN 2 PCE + assert not sidepanel, "Production line is already generated for SIDEPAN." + assert line.product_qty == (2.0*12.0*5.0), "Qty is not correspond." assert line.product_uom.id == ref('product.product_uom_unit'), "UOM is not correspond" - elif line.product_id.id == ref('product.product_product_sidepanel0'): - assert line.product_qty == (2.0*3.0*12.0), "Qty is not correspond." - assert line.product_uom.id == ref('product.product_uom_unit'), "UOM is not correspond" - elif line.product_id.id == ref('product.product_product_metalcleats0'): - assert line.product_qty == (12.0*3.0*12.0), "Qty is not correspond." - assert line.product_uom.id == ref('product.product_uom_unit'), "UOM is not correspond" - elif line.product_id.id == ref('product.product_product_rearpanelarm0'): - assert line.product_qty == (1.0*3.0*12.0), "Qty is not correspond." - assert line.product_uom.id == ref('product.product_uom_unit'), "UOM is not correspond" - elif line.product_id.id == ref('product.product_product_shelf0'): - assert line.product_qty == (3.0*3.0*12.0), "Qty is not correspond." + sidepanel = True + elif line.product_id.id == ref('product.product_product_woodlintelm0'): #LIN40 4*0.25 Meter + assert not woodlintelm, "Production line is already generated for LIN40." + assert line.product_qty == (4*0.25*12.0*5.0), "Qty is not correspond." + assert line.product_uom.id == ref('product.product_uom_meter'), "UOM is not correspond" + woodlintelm = True + elif line.product_id.id == ref('product.product_product_woodmm0'): #WOOD002 0.25 m + assert not woodmm0, "Production line is already generated for WOOD002." + assert line.product_qty == (0.25*12.0*5.0), "Qty is not correspond." + assert line.product_uom.id == ref('product.product_uom_meter'), "UOM is not correspond" + woodmm0 = True + elif line.product_id.id == ref('product.product_product_metalcleats0'): #METC000 4*3 PCE + assert not metalcleats, "Production line is already generated for METC000." + assert line.product_qty == (4*3*12.0*5.0), "Qty is not correspond." assert line.product_uom.id == ref('product.product_uom_unit'), "UOM is not correspond" + metalcleats = True + elif line.product_id.id == ref('product.product_product_woodmm10'): #WOOD010 0.083*3 m + assert not woodmm10, "Production line is already generated for WOOD010." + assert line.product_qty == (0.083*3*12.0*5.0), "Qty is not correspond." + assert line.product_uom.id == ref('product.product_uom_meter'), "UOM is not correspond" + woodmm10 = True else: - assert_exception("Lines are not correspond.") + raise AssertionError('unknown order line: %s' % line) + assert sidepanel, "Production line is not generated for SIDEPAN." + assert woodlintelm, "Production line is not generated for LIN40." + assert woodmm0, "Production line is not generated for WOOD002." + assert metalcleats, "Production line is not generated for METC000." + assert woodmm10, "Production line is not generated for WOOD010." - I confirm the Production Order. - @@ -63,25 +83,27 @@ assert move.product_id.id == order.product_id.id, "Product is not correspond." assert move.product_uom.id == order.product_uom.id, "UOM is not correspond." assert move.product_qty == order.product_qty, "Qty is not correspond." - assert move.product_uos == order.product_uos, "UOS is not correspond." - assert move.product_uos_qty == order.product_uos_qty, "UOS qty is not correspond." + assert move.product_uos_qty == order.product_uos and order.product_uos_qty or order.product_qty, "UOS qty is not correspond." + if order.product_uos: + assert move.product_uos.id == order.product_uos.id, "UOS is not correspond." assert move.location_id.id == source_location_id, "Source Location is not correspond." assert move.location_dest_id.id == order.location_dest_id.id, "Destination Location is not correspond." routing_loc = None - if production.bom_id.routing_id and production.bom_id.routing_id.location_id: - routing_loc = production.bom_id.routing_id.location_id.id - + if order.bom_id.routing_id and order.bom_id.routing_id.location_id: + routing_loc = order.bom_id.routing_id.location_id.id + date_planned = order.date_planned for move_line in order.move_lines: for order_line in order.product_lines: - if line.product_id.type not in ('product', 'consu'): + if move_line.product_id.type not in ('product', 'consu'): continue if move_line.product_id.id == order_line.product_id.id: assert move_line.date == date_planned, "Planned date is not correspond in 'To consume line'." assert move_line.product_qty == order_line.product_qty, "Qty is not correspond in 'To consume line'." assert move_line.product_uom.id == order_line.product_uom.id, "UOM is not correspond in 'To consume line'." - assert move_line.product_uos_qty == order_line.product_uos and order_line.product_uos_qty or False, "UOS qty is not correspond in 'To consume line'." - assert move_line.product_uos == order_line.product_uos and order_line.product_uos.id or False, "UOS is not correspond in 'To consume line'." - assert move_line.location_id.id == routing_loc or production.location_src_id.id, "Source location is not correspond in 'To consume line'." + assert move_line.product_uos_qty == order_line.product_uos and order_line.product_uos_qty or order_line.product_qty, "UOS qty is not correspond in 'To consume line'." + if order_line.product_uos: + assert move_line.product_uos.id == order_line.product_uos.id, "UOS is not correspond in 'To consume line'." + assert move_line.location_id.id == routing_loc or order.location_src_id.id, "Source location is not correspond in 'To consume line'." assert move_line.location_dest_id.id == source_location_id, "Destination Location is not correspond in 'To consume line'." - @@ -95,37 +117,39 @@ routing_loc = None pick_type = 'internal' address_id = False - if production.bom_id.routing_id and production.bom_id.routing_id.location_id: - routing_loc = production.bom_id.routing_id.location_id + if order.bom_id.routing_id and order.bom_id.routing_id.location_id: + routing_loc = order.bom_id.routing_id.location_id if routing_loc.usage <> 'internal': pick_type = 'out' address_id = routing_loc.address_id and routing_loc.address_id.id or False routing_loc = routing_loc.id assert order.picking_id.type == pick_type, "Shipment should be Internal." - assert order.picking_id.address_id == address_id, "Shipment Address is not correspond with Adderss of Routing Location." - date_planned = production.date_planned + assert order.picking_id.address_id.id == address_id, "Shipment Address is not correspond with Adderss of Routing Location." + date_planned = order.date_planned for move_line in order.picking_id.move_lines: for order_line in order.product_lines: - if line.product_id.type not in ('product', 'consu'): + if move_line.product_id.type not in ('product', 'consu'): continue if move_line.product_id.id == order_line.product_id.id: assert move_line.date == date_planned, "Planned date is not correspond." assert move_line.product_qty == order_line.product_qty, "Qty is not correspond." assert move_line.product_uom.id == order_line.product_uom.id, "UOM is not correspond." - assert move_line.product_uos_qty == order_line.product_uos and order_line.product_uos_qty or False, "UOS qty is not correspond." - assert move_line.product_uos == order_line.product_uos and order_line.product_uos.id or False, "UOS is not correspond." - assert move_line.location_id.id == production.location_src_id.id, "Source location is not correspond." - assert move_line.location_dest_id.id == routing_loc or production.location_src_id.id, "Destination Location is not correspond." - procurement_ids = procurement.search(cr, uid, [('move_id','=',move_line.id)] + assert move_line.product_uos_qty == order_line.product_uos and order_line.product_uos_qty or order_line.product_qty, "UOS qty is not correspond." + if order_line.product_uos: + assert move_line.product_uos.id == order_line.product_uos.id, "UOS is not correspond." + assert move_line.location_id.id == order.location_src_id.id, "Source location is not correspond." + assert move_line.location_dest_id.id == routing_loc or order.location_src_id.id, "Destination Location is not correspond." + procurement_ids = procurement.search(cr, uid, [('move_id','=',move_line.id)]) assert procurement_ids, "Procurement should be created for shipment line of raw materials." shipment_procurement = procurement.browse(cr, uid, procurement_ids[0], context=context) assert shipment_procurement.date_planned == date_planned, "Planned date is not correspond in procurement." assert shipment_procurement.product_id.id == order_line.product_id.id, "Product is not correspond in procurement." assert shipment_procurement.product_qty == order_line.product_qty, "Qty is not correspond in procurement." assert shipment_procurement.product_uom.id == order_line.product_uom.id, "UOM is not correspond in procurement." - assert shipment_procurement.product_uos_qty == order_line.product_uos and order_line.product_qty or False, "UOS qty is not correspond in procurement." - assert shipment_procurement.product_uos.id == order_line.product_uos and order_line.product_uos.id or False, "UOS is not correspond in procurement." - assert shipment_procurement.location_id.id == production.location_src_id.id, "Location is not correspond in procurement." + assert shipment_procurement.product_uos_qty == order_line.product_uos and order_line.product_uos_qty or order_line.product_qty, "UOS qty is not correspond in procurement." + if order_line.product_uos: + assert shipment_procurement.product_uos.id == order_line.product_uos.id, "UOS is not correspond in procurement." + assert shipment_procurement.location_id.id == order.location_src_id.id, "Location is not correspond in procurement." assert shipment_procurement.procure_method == order_line.product_id.procure_method, "Procure method is not correspond in procurement." @@ -181,8 +205,9 @@ - I check production order after produced. - - !assert {model: mrp.production, id: mrp_production_shelf100cm}: - - state == 'done' + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_shelf100cm")) + assert order.state == 'done', "Production order should be closed." - I print a "BOM Structure". diff --git a/addons/mrp/wizard/mrp_product_produce.py b/addons/mrp/wizard/mrp_product_produce.py index 4ae4a254d49..db4d6e77691 100644 --- a/addons/mrp/wizard/mrp_product_produce.py +++ b/addons/mrp/wizard/mrp_product_produce.py @@ -60,22 +60,11 @@ class mrp_product_produce(osv.osv_memory): } def do_produce(self, cr, uid, ids, context=None): - """ To check the product type - @param self: The object pointer. - @param cr: A database cursor - @param uid: ID of the user currently logged in - @param ids: the ID or list of IDs if we want more than one - @param context: A standard dictionary - @return: - """ - if context is None: - context = {} - prod_obj = self.pool.get('mrp.production') - production_ids = context.get('active_ids', []) - for data in self.browse(cr, uid, ids, context=context): - for production_id in production_ids: - prod_obj.action_produce(cr, uid, production_id, - data.product_qty, data.mode, context=context) + production_id = context.get('active_id', False) + assert production_id, "Production Id should be specified in context as a Active ID" + data = self.browse(cr, uid, ids[0], context=context) + self.pool.get('mrp.production').action_produce(cr, uid, production_id, + data.product_qty, data.mode, context=context) return {} mrp_product_produce() diff --git a/addons/product/product_demo.xml b/addons/product/product_demo.xml index 3aebec13715..99347667f80 100644 --- a/addons/product/product_demo.xml +++ b/addons/product/product_demo.xml @@ -442,6 +442,16 @@ product + + SPAN100 + produce + + + + Shelf Panel + product + + WOOD002 buy @@ -455,6 +465,19 @@ + + WOOD010 + buy + 7.0 + + + Wood 10mm + + + product + + + PROJ produce @@ -509,7 +532,7 @@ RPAN100 - buy + produce 10.0 @@ -548,7 +571,7 @@ RCK100 - buy + produce 5.0