Merge lp:~openerp-dev/openobject-addons/trunk-mo-disassemble into lp:openobject-addons

Proposed by SnippetBucket.com
Status: Needs review
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-mo-disassemble
Merge into: lp:openobject-addons
Diff against target: 1089 lines (+568/-49) (has conflicts)
16 files modified
mrp/__openerp__.py (+6/-0)
mrp/mrp.py (+192/-23)
mrp/mrp_demo.xml (+1/-1)
mrp/mrp_view.xml (+57/-10)
mrp/procurement.py (+28/-0)
mrp/static/src/js/mrp.js (+38/-0)
mrp/test/disassemble_process.yml (+96/-0)
mrp/test/order_demo.yml (+0/-2)
mrp/wizard/__init__.py (+4/-0)
mrp/wizard/change_production_qty.py (+1/-1)
mrp/wizard/disassemble_qty.py (+64/-0)
mrp/wizard/disassemble_qty_view.xml (+37/-0)
mrp/wizard/mrp_product_produce.py (+18/-1)
mrp/wizard/mrp_product_produce_view.xml (+20/-8)
mrp_byproduct/mrp_byproduct.py (+4/-2)
mrp_operations/mrp_operations.py (+2/-1)
Text conflict in mrp/__openerp__.py
Text conflict in mrp/mrp.py
Text conflict in mrp/mrp_view.xml
Text conflict in mrp/procurement.py
Text conflict in mrp/wizard/__init__.py
Text conflict in mrp/wizard/mrp_product_produce.py
Text conflict in mrp/wizard/mrp_product_produce_view.xml
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-mo-disassemble
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+164835@code.launchpad.net

Description of the change

Hello,

Task: [MRP] allow disassembling through manufacturing orders

In the Manufacturing Order, allow to use negative quantities in the Product Quantity field so that the selected product is dismantled and individual components are put back into inventory, with all appropriate stock moves.

More details on pad:
http://pad.openerp.com/p/r.Vquhp9c9xsuPRWaX

Thanks,
TTA

To post a comment you must log in.
8782. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8783. By Jitendra Prajapati(OpenERP)

[FIX/IMP]except disassamble coming from procurement.

Unmerged revisions

8783. By Jitendra Prajapati(OpenERP)

[FIX/IMP]except disassamble coming from procurement.

8782. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8781. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8780. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8779. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8778. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8777. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8776. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8775. By Jitendra Prajapati(OpenERP)

[MERGE]with main branch

8774. By Jitendra Prajapati(OpenERP)

[MERGE]with lp:openobject-addons

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'idea'
=== added directory 'idea/static'
=== added directory 'idea/static/src'
=== added directory 'idea/static/src/img'
=== modified file 'mrp/__openerp__.py'
--- mrp/__openerp__.py 2014-05-07 17:12:05 +0000
+++ mrp/__openerp__.py 2014-05-20 10:51:47 +0000
@@ -62,7 +62,11 @@
62 'wizard/change_production_qty_view.xml',62 'wizard/change_production_qty_view.xml',
63 'wizard/mrp_price_view.xml',63 'wizard/mrp_price_view.xml',
64 'wizard/mrp_workcenter_load_view.xml',64 'wizard/mrp_workcenter_load_view.xml',
65<<<<<<< TREE
65 'wizard/stock_move_view.xml',66 'wizard/stock_move_view.xml',
67=======
68 'wizard/disassemble_qty_view.xml',
69>>>>>>> MERGE-SOURCE
66 'mrp_view.xml',70 'mrp_view.xml',
67 'mrp_report.xml',71 'mrp_report.xml',
68 'company_view.xml',72 'company_view.xml',
@@ -78,9 +82,11 @@
78 'test/order_demo.yml',82 'test/order_demo.yml',
79 'test/order_process.yml',83 'test/order_process.yml',
80 'test/cancel_order.yml',84 'test/cancel_order.yml',
85 'test/disassemble_process.yml',
81 ],86 ],
82 'installable': True,87 'installable': True,
83 'application': True,88 'application': True,
84 'auto_install': False,89 'auto_install': False,
90 'js': ['static/src/js/mrp.js',],
85}91}
86# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:92# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
8793
=== modified file 'mrp/mrp.py'
--- mrp/mrp.py 2014-05-08 11:59:17 +0000
+++ mrp/mrp.py 2014-05-20 10:51:47 +0000
@@ -96,6 +96,12 @@
96 value = {'costs_hour': cost.standard_price}96 value = {'costs_hour': cost.standard_price}
97 return {'value': value}97 return {'value': value}
9898
99class stock_move(osv.osv):
100 _inherit = 'stock.move'
101 _columns = {
102 'disassemble': fields.boolean('Disassemble'),
103 }
104
99class mrp_routing(osv.osv):105class mrp_routing(osv.osv):
100 """106 """
101 For specifying the routings of Work Centers.107 For specifying the routings of Work Centers.
@@ -426,14 +432,15 @@
426 """ Return product quantity percentage """432 """ Return product quantity percentage """
427 result = dict.fromkeys(ids, 100)433 result = dict.fromkeys(ids, 100)
428 for mrp_production in self.browse(cr, uid, ids, context=context):434 for mrp_production in self.browse(cr, uid, ids, context=context):
429 if mrp_production.product_qty:435 if abs(mrp_production.product_qty):
430 done = 0.0436 done = 0.0
431 for move in mrp_production.move_created_ids2:437 for move in mrp_production.move_created_ids2:
432 if not move.scrapped and move.product_id == mrp_production.product_id:438 if not move.scrapped and move.product_id == mrp_production.product_id:
433 done += move.product_qty439 done += move.product_qty
434 result[mrp_production.id] = done / mrp_production.product_qty * 100440 result[mrp_production.id] = done / abs(mrp_production.product_qty) * 100
435 return result441 return result
436442
443<<<<<<< TREE
437 def _moves_assigned(self, cr, uid, ids, name, arg, context=None):444 def _moves_assigned(self, cr, uid, ids, name, arg, context=None):
438 """ Test whether all the consume lines are assigned """445 """ Test whether all the consume lines are assigned """
439 res = {}446 res = {}
@@ -451,6 +458,13 @@
451 res += self.pool.get("mrp.production").search(cr, uid, [('move_lines', 'in', move.id)], context=context)458 res += self.pool.get("mrp.production").search(cr, uid, [('move_lines', 'in', move.id)], context=context)
452 return res459 return res
453460
461=======
462 def create(self, cr, uid, values, context=None):
463 if values['product_qty'] < 0:
464 self._description = _('Disassemble Order')
465 return super(mrp_production, self).create(cr, uid, values, context=context)
466
467>>>>>>> MERGE-SOURCE
454 _columns = {468 _columns = {
455 'name': fields.char('Reference', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}),469 'name': fields.char('Reference', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}),
456 'origin': fields.char('Source Document', size=64, readonly=True, states={'draft': [('readonly', False)]},470 'origin': fields.char('Source Document', size=64, readonly=True, states={'draft': [('readonly', False)]},
@@ -493,8 +507,13 @@
493 'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation',507 'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation',
494 readonly=True, states={'draft': [('readonly', False)]}),508 readonly=True, states={'draft': [('readonly', False)]}),
495 'state': fields.selection(509 'state': fields.selection(
510<<<<<<< TREE
496 [('draft', 'New'), ('cancel', 'Cancelled'), ('confirmed', 'Awaiting Raw Materials'),511 [('draft', 'New'), ('cancel', 'Cancelled'), ('confirmed', 'Awaiting Raw Materials'),
497 ('ready', 'Ready to Produce'), ('in_production', 'Production Started'), ('done', 'Done')],512 ('ready', 'Ready to Produce'), ('in_production', 'Production Started'), ('done', 'Done')],
513=======
514 [('draft', 'New'), ('cancel', 'Cancelled'), ('picking_except', 'Picking Exception'), ('confirmed', 'Awaiting Raw Materials'),
515 ('ready', 'Ready to Produce'), ('in_production', 'Production Started'), ('done', 'Done')],
516>>>>>>> MERGE-SOURCE
498 string='Status', readonly=True,517 string='Status', readonly=True,
499 track_visibility='onchange',518 track_visibility='onchange',
500 help="When the production order is created the status is set to 'Draft'.\n\519 help="When the production order is created the status is set to 'Draft'.\n\
@@ -505,21 +524,35 @@
505 When the production is over, the status is set to 'Done'."),524 When the production is over, the status is set to 'Done'."),
506 'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store=True),525 'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store=True),
507 'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store=True),526 'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store=True),
527<<<<<<< TREE
508 'user_id': fields.many2one('res.users', 'Responsible'),528 'user_id': fields.many2one('res.users', 'Responsible'),
509 'company_id': fields.many2one('res.company', 'Company', required=True),529 'company_id': fields.many2one('res.company', 'Company', required=True),
510 'ready_production': fields.function(_moves_assigned, type='boolean', store={'stock.move': (_mrp_from_move, ['state'], 10)}),530 'ready_production': fields.function(_moves_assigned, type='boolean', store={'stock.move': (_mrp_from_move, ['state'], 10)}),
531=======
532 'user_id':fields.many2one('res.users', 'Responsible'),
533 'company_id': fields.many2one('res.company','Company',required=True),
534 'disassemble': fields.boolean('Disassemble'),
535 'disassemble_doc': fields.char('Disassemble Document(s)', size=64, readonly=True, help="Reference of disassembled document(s) for this Manufacturing Order."),
536 'qty_to_disassemble': fields.float('Remaining Quantity to Disassemble', help="Available product quantity to disassemble", digits_compute=dp.get_precision('Product Unit of Measure')),
537>>>>>>> MERGE-SOURCE
511 }538 }
512539
513 _defaults = {540 _defaults = {
514 'priority': lambda *a: '1',541 'priority': lambda *a: '1',
515 'state': lambda *a: 'draft',542 'state': lambda *a: 'draft',
516 'date_planned': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),543 'date_planned': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
544<<<<<<< TREE
517 'product_qty': lambda *a: 1.0,545 'product_qty': lambda *a: 1.0,
546=======
547 'product_qty': 1.0,
548>>>>>>> MERGE-SOURCE
518 'user_id': lambda self, cr, uid, c: uid,549 'user_id': lambda self, cr, uid, c: uid,
519 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'mrp.production') or '/',550 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'mrp.production') or '/',
520 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.production', context=c),551 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.production', context=c),
521 'location_src_id': _src_id_default,552 'location_src_id': _src_id_default,
522 'location_dest_id': _dest_id_default553 'location_dest_id': _dest_id_default,
554 'disassemble': False,
555 'disassemble_doc': False,
523 }556 }
524557
525 _sql_constraints = [558 _sql_constraints = [
@@ -528,16 +561,6 @@
528561
529 _order = 'priority desc, date_planned asc'562 _order = 'priority desc, date_planned asc'
530563
531 def _check_qty(self, cr, uid, ids, context=None):
532 for order in self.browse(cr, uid, ids, context=context):
533 if order.product_qty <= 0:
534 return False
535 return True
536
537 _constraints = [
538 (_check_qty, 'Order quantity cannot be negative or zero!', ['product_qty']),
539 ]
540
541 def unlink(self, cr, uid, ids, context=None):564 def unlink(self, cr, uid, ids, context=None):
542 for production in self.browse(cr, uid, ids, context=context):565 for production in self.browse(cr, uid, ids, context=context):
543 if production.state not in ('draft', 'cancel'):566 if production.state not in ('draft', 'cancel'):
@@ -547,17 +570,37 @@
547 def copy(self, cr, uid, id, default=None, context=None):570 def copy(self, cr, uid, id, default=None, context=None):
548 if default is None:571 if default is None:
549 default = {}572 default = {}
573 mo = self.browse(cr, uid, id, context=context)
574 origin = False
575 if default.get('disassemble', False):
576 origin = mo.origin + '-' + mo.name if not mo.disassemble and mo.origin else mo.name
550 default.update({577 default.update({
551 'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.production'),578 'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.production'),
552 'move_lines': [],579<<<<<<< TREE
553 'move_lines2': [],580 'move_lines': [],
554 'move_created_ids': [],581 'move_lines2': [],
555 'move_created_ids2': [],582 'move_created_ids': [],
556 'product_lines': [],583 'move_created_ids2': [],
557 'move_prod_id': False,584 'product_lines': [],
585 'move_prod_id': False,
586=======
587 'move_lines': [],
588 'move_lines2': [],
589 'move_created_ids': [],
590 'move_created_ids2': [],
591 'product_lines': [],
592 'move_prod_id': False,
593 'picking_id': False,
594 'origin': origin,
595>>>>>>> MERGE-SOURCE
558 })596 })
559 return super(mrp_production, self).copy(cr, uid, id, default, context)597 return super(mrp_production, self).copy(cr, uid, id, default, context)
560598
599 def onchange_product_qty(self, cr, uid, ids, quantity, context=None):
600 if quantity < 0:
601 return {'value': {'disassemble': True, 'qty_to_disassemble': quantity}}
602 return {'value': {'disassemble': False, 'qty_to_disassemble': quantity}}
603
561 def location_id_change(self, cr, uid, ids, src, dest, context=None):604 def location_id_change(self, cr, uid, ids, src, dest, context=None):
562 """ Changes destination location if source location is changed.605 """ Changes destination location if source location is changed.
563 @param src: Source location id.606 @param src: Source location id.
@@ -645,7 +688,7 @@
645 raise osv.except_osv(_('Error!'), _("Cannot find a bill of material for this product."))688 raise osv.except_osv(_('Error!'), _("Cannot find a bill of material for this product."))
646689
647 # get components and workcenter_lines from BoM structure690 # get components and workcenter_lines from BoM structure
648 factor = uom_obj._compute_qty(cr, uid, production.product_uom.id, production.product_qty, bom_point.product_uom.id)691 factor = uom_obj._compute_qty(cr, uid, production.product_uom.id, abs(production.product_qty), bom_point.product_uom.id)
649 res = bom_obj._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id)692 res = bom_obj._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id)
650 results = res[0] # product_lines693 results = res[0] # product_lines
651 results2 = res[1] # workcenter_lines694 results2 = res[1] # workcenter_lines
@@ -667,6 +710,34 @@
667 """710 """
668 return len(self._action_compute_lines(cr, uid, ids, properties=properties, context=context))711 return len(self._action_compute_lines(cr, uid, ids, properties=properties, context=context))
669712
713 def action_disassemble(self, cr, uid, id, qty, context=None):
714 """ Disassemble the production order.
715 """
716 mo = self.browse(cr, uid, id, context=context)
717 values = {
718 'disassemble': True,
719 'origin': mo.name,
720 'routing_id': False,
721 'product_qty': qty,
722 'qty_to_disassemble': 0,
723 }
724 mo_id = self.copy(cr, uid, mo.id, values, context=context)
725 if mo_id:
726 source_doc = self.read(cr, uid, mo_id, ['name'], context=context)
727 mo.write({'disassemble_doc': mo.disassemble_doc and mo.disassemble_doc + ", " + source_doc['name'] or source_doc['name']}, context=context)
728 view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mrp', 'mrp_production_form_view')
729 view_id = view_ref and view_ref[1] or False,
730 return {
731 'type': 'ir.actions.act_window',
732 'name': _('Disassemble Manufacturing Order'),
733 'res_model': 'mrp.production',
734 'res_id': mo_id,
735 'view_type': 'form',
736 'view_mode': 'form',
737 'view_id': False,
738 'target': 'current',
739 }
740
670 def action_cancel(self, cr, uid, ids, context=None):741 def action_cancel(self, cr, uid, ids, context=None):
671 """ Cancels the production order and related stock moves.742 """ Cancels the production order and related stock moves.
672 @return: True743 @return: True
@@ -691,9 +762,11 @@
691 @return: True762 @return: True
692 """763 """
693 move_obj = self.pool.get('stock.move')764 move_obj = self.pool.get('stock.move')
694 self.write(cr, uid, ids, {'state': 'ready'})
695765
696 for production in self.browse(cr, uid, ids, context=context):766 for production in self.browse(cr, uid, ids, context=context):
767 if production.disassemble:
768 self.action_confirm(cr, uid, [production.id])
769 production.write({'state': 'ready'}, context=context)
697 if not production.move_created_ids:770 if not production.move_created_ids:
698 self._make_production_produce_line(cr, uid, production, context=context)771 self._make_production_produce_line(cr, uid, production, context=context)
699772
@@ -841,9 +914,53 @@
841 # trigger workflow if not products to consume (eg: services)914 # trigger workflow if not products to consume (eg: services)
842 self.signal_button_produce(cr, uid, [production_id])915 self.signal_button_produce(cr, uid, [production_id])
843916
917<<<<<<< TREE
844 produced_qty = self._get_produced_qty(cr, uid, production, context=context)918 produced_qty = self._get_produced_qty(cr, uid, production, context=context)
845919
846 main_production_move = False920 main_production_move = False
921=======
922 produced_qty = 0
923 for produced_product in production.move_created_ids2:
924 if (produced_product.scrapped) or (produced_product.product_id.id != production.product_id.id):
925 continue
926 produced_qty += produced_product.product_qty
927 if production_mode in ['consume','consume_produce']:
928 consumed_data = {}
929
930 # Calculate already consumed qtys
931 for consumed in production.move_lines2:
932 if consumed.scrapped:
933 continue
934 if not consumed_data.get(consumed.product_id.id, False):
935 consumed_data[consumed.product_id.id] = 0
936 consumed_data[consumed.product_id.id] += consumed.product_qty
937
938 # Find product qty to be consumed and consume it
939 for scheduled in production.product_lines:
940
941 # total qty of consumed product we need after this consumption
942 total_consume = ((production_qty + produced_qty) * scheduled.product_qty / abs(production.product_qty))
943 # qty available for consume and produce
944 qty_avail = scheduled.product_qty - consumed_data.get(scheduled.product_id.id, 0.0)
945
946 if float_compare(qty_avail, 0, precision_rounding=scheduled.product_id.uom_id.rounding) <= 0:
947 # there will be nothing to consume for this raw material
948 continue
949
950 raw_product = [move for move in production.move_lines if move.product_id.id==scheduled.product_id.id]
951 if raw_product:
952 # qtys we have to consume
953 qty = total_consume - consumed_data.get(scheduled.product_id.id, 0.0)
954 if float_compare(qty, qty_avail, precision_rounding=scheduled.product_id.uom_id.rounding) == 1:
955 # if qtys we have to consume is more than qtys available to consume
956 prod_name = scheduled.product_id.name_get()[0][1]
957 raise osv.except_osv(_('Warning!'), _('You are going to consume total %s quantities of "%s".\nBut you can only consume up to total %s quantities.') % (qty, prod_name, qty_avail))
958 if float_compare(qty, 0, precision_rounding=scheduled.product_id.uom_id.rounding) <= 0:
959 # we already have more qtys consumed than we need
960 continue
961 raw_product[0].action_consume(qty, raw_product[0].location_id.id, context=context)
962
963>>>>>>> MERGE-SOURCE
847 if production_mode == 'consume_produce':964 if production_mode == 'consume_produce':
848 # To produce remaining qty of final product965 # To produce remaining qty of final product
849 #vals = {'state':'confirmed'}966 #vals = {'state':'confirmed'}
@@ -861,8 +978,14 @@
861 for produce_product in production.move_created_ids:978 for produce_product in production.move_created_ids:
862 produced_qty = produced_products.get(produce_product.product_id.id, 0)979 produced_qty = produced_products.get(produce_product.product_id.id, 0)
863 subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context)980 subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context)
981<<<<<<< TREE
864 rest_qty = (subproduct_factor * production.product_qty) - produced_qty982 rest_qty = (subproduct_factor * production.product_qty) - produced_qty
865 if float_compare(rest_qty, (subproduct_factor * production_qty), precision_rounding=produce_product.product_id.uom_id.rounding) < 0:983 if float_compare(rest_qty, (subproduct_factor * production_qty), precision_rounding=produce_product.product_id.uom_id.rounding) < 0:
984=======
985 rest_qty = (subproduct_factor * abs(production.product_qty)) - produced_qty
986
987 if rest_qty < (subproduct_factor * production_qty):
988>>>>>>> MERGE-SOURCE
866 prod_name = produce_product.product_id.name_get()[0][1]989 prod_name = produce_product.product_id.name_get()[0][1]
867 raise osv.except_osv(_('Warning!'), _('You are going to produce total %s quantities of "%s".\nBut you can only produce up to total %s quantities.') % ((subproduct_factor * production_qty), prod_name, rest_qty))990 raise osv.except_osv(_('Warning!'), _('You are going to produce total %s quantities of "%s".\nBut you can only produce up to total %s quantities.') % ((subproduct_factor * production_qty), prod_name, rest_qty))
868 if float_compare(rest_qty, 0, precision_rounding=produce_product.product_id.uom_id.rounding) > 0:991 if float_compare(rest_qty, 0, precision_rounding=produce_product.product_id.uom_id.rounding) > 0:
@@ -963,8 +1086,19 @@
963 def test_ready(self, cr, uid, ids):1086 def test_ready(self, cr, uid, ids):
964 res = False1087 res = False
965 for production in self.browse(cr, uid, ids):1088 for production in self.browse(cr, uid, ids):
1089<<<<<<< TREE
966 if production.ready_production:1090 if production.ready_production:
967 res = True1091 res = True
1092=======
1093 boms = self._action_compute_lines(cr, uid, [production.id])
1094 res = False
1095 for bom in boms:
1096 product = self.pool.get('product.product').browse(cr, uid, bom['product_id'])
1097 if production.disassemble:
1098 res = False
1099 elif product.type in ('product', 'consu'):
1100 res = True
1101>>>>>>> MERGE-SOURCE
968 return res1102 return res
969 1103
970 1104
@@ -976,13 +1110,21 @@
976 'name': production.name,1110 'name': production.name,
977 'date': production.date_planned,1111 'date': production.date_planned,
978 'product_id': production.product_id.id,1112 'product_id': production.product_id.id,
1113<<<<<<< TREE
1114=======
1115 'product_qty': abs(production.product_qty),
1116>>>>>>> MERGE-SOURCE
979 'product_uom': production.product_uom.id,1117 'product_uom': production.product_uom.id,
980 'product_uom_qty': production.product_qty,1118 'product_uom_qty': production.product_qty,
981 'product_uos_qty': production.product_uos and production.product_uos_qty or False,1119 'product_uos_qty': production.product_uos and production.product_uos_qty or False,
982 'product_uos': production.product_uos and production.product_uos.id or False,1120 'product_uos': production.product_uos and production.product_uos.id or False,
983 'location_id': source_location_id,1121 'location_id': production.disassemble and destination_location_id or source_location_id ,
984 'location_dest_id': destination_location_id,1122 'location_dest_id': production.disassemble and source_location_id or destination_location_id,
985 'move_dest_id': production.move_prod_id.id,1123 'move_dest_id': production.move_prod_id.id,
1124<<<<<<< TREE
1125=======
1126 'state': production.disassemble and 'assigned' or 'waiting', # for products to produce
1127>>>>>>> MERGE-SOURCE
986 'company_id': production.company_id.id,1128 'company_id': production.company_id.id,
987 'production_id': production.id,1129 'production_id': production.id,
988 'origin': production.name,1130 'origin': production.name,
@@ -1019,6 +1161,7 @@
1019 move_id = stock_move.create(cr, uid, {1161 move_id = stock_move.create(cr, uid, {
1020 'name': production.name,1162 'name': production.name,
1021 'date': production.date_planned,1163 'date': production.date_planned,
1164<<<<<<< TREE
1022 'product_id': product.id,1165 'product_id': product.id,
1023 'product_uom_qty': qty,1166 'product_uom_qty': qty,
1024 'product_uom': uom_id,1167 'product_uom': uom_id,
@@ -1026,12 +1169,27 @@
1026 'product_uos': uos_id or False,1169 'product_uos': uos_id or False,
1027 'location_id': source_location_id,1170 'location_id': source_location_id,
1028 'location_dest_id': destination_location_id,1171 'location_dest_id': destination_location_id,
1172=======
1173 'product_id': production_line.product_id.id,
1174 'product_qty': production_line.product_qty,
1175 'product_uom': production_line.product_uom.id,
1176 'product_uos_qty': production_line.product_uos and production_line.product_uos_qty or False,
1177 'product_uos': production_line.product_uos and production_line.product_uos.id or False,
1178 'location_id': production.disassemble and destination_location_id or source_location_id,
1179 'location_dest_id': production.disassemble and source_location_id or destination_location_id,
1180 'move_dest_id': parent_move_id,
1181 'state': production.disassemble and 'assigned' or 'waiting', # for products to consume
1182>>>>>>> MERGE-SOURCE
1029 'company_id': production.company_id.id,1183 'company_id': production.company_id.id,
1184<<<<<<< TREE
1030 'procure_method': self._get_raw_material_procure_method(cr, uid, product, context=context),1185 'procure_method': self._get_raw_material_procure_method(cr, uid, product, context=context),
1031 'raw_material_production_id': production.id,1186 'raw_material_production_id': production.id,
1032 #this saves us a browse in create()1187 #this saves us a browse in create()
1033 'price_unit': product.standard_price,1188 'price_unit': product.standard_price,
1034 'origin': production.name,1189 'origin': production.name,
1190=======
1191 'disassemble': production.disassemble
1192>>>>>>> MERGE-SOURCE
1035 })1193 })
1036 return move_id1194 return move_id
10371195
@@ -1045,9 +1203,20 @@
1045 uncompute_ids = filter(lambda x: x, [not x.product_lines and x.id or False for x in self.browse(cr, uid, ids, context=context)])1203 uncompute_ids = filter(lambda x: x, [not x.product_lines and x.id or False for x in self.browse(cr, uid, ids, context=context)])
1046 self.action_compute(cr, uid, uncompute_ids, context=context)1204 self.action_compute(cr, uid, uncompute_ids, context=context)
1047 for production in self.browse(cr, uid, ids, context=context):1205 for production in self.browse(cr, uid, ids, context=context):
1206<<<<<<< TREE
1048 self._make_production_produce_line(cr, uid, production, context=context)1207 self._make_production_produce_line(cr, uid, production, context=context)
10491208
1050 stock_moves = []1209 stock_moves = []
1210=======
1211 if not production.disassemble:
1212 shipment_id = self._make_production_internal_shipment(cr, uid, production, context=context)
1213 produce_move_id = self._make_production_produce_line(cr, uid, production, context=context)
1214
1215 # Take routing location as a Source Location.
1216 source_location_id = production.location_src_id.id
1217 if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
1218 source_location_id = production.bom_id.routing_id.location_id.id
1219>>>>>>> MERGE-SOURCE
1051 for line in production.product_lines:1220 for line in production.product_lines:
1052 stock_move_id = self._make_production_consume_line(cr, uid, line, context=context)1221 stock_move_id = self._make_production_consume_line(cr, uid, line, context=context)
1053 if stock_move_id:1222 if stock_move_id:
10541223
=== modified file 'mrp/mrp_demo.xml'
--- mrp/mrp_demo.xml 2014-01-20 14:42:43 +0000
+++ mrp/mrp_demo.xml 2014-05-20 10:51:47 +0000
@@ -38,7 +38,6 @@
3838
39 <record id="mrp_workcenter_0" model="mrp.workcenter">39 <record id="mrp_workcenter_0" model="mrp.workcenter">
40 <field name="name">Assembly workshop</field>40 <field name="name">Assembly workshop</field>
41 <field name="calendar_id" ref="resource.timesheet_group1"/>
42 <field name="capacity_per_cycle">5</field>41 <field name="capacity_per_cycle">5</field>
43 <field name="time_cycle">1</field>42 <field name="time_cycle">1</field>
44 <field name="time_start">0.1</field>43 <field name="time_start">0.1</field>
@@ -661,6 +660,7 @@
661 <record id="mrp_production_2" model="mrp.production">660 <record id="mrp_production_2" model="mrp.production">
662 <field name="product_id" ref="product.product_product_27"/>661 <field name="product_id" ref="product.product_product_27"/>
663 <field name="product_uom" ref="product.product_uom_unit"/>662 <field name="product_uom" ref="product.product_uom_unit"/>
663 <field name="product_qty">5</field>
664 <field name="location_src_id" ref="stock.stock_location_stock"/>664 <field name="location_src_id" ref="stock.stock_location_stock"/>
665 <field name="location_dest_id" ref="stock.stock_location_output"/>665 <field name="location_dest_id" ref="stock.stock_location_output"/>
666 <field name="bom_id" ref="mrp.mrp_bom_7"/>666 <field name="bom_id" ref="mrp.mrp_bom_7"/>
667667
=== modified file 'mrp/mrp_view.xml'
--- mrp/mrp_view.xml 2014-05-07 18:29:17 +0000
+++ mrp/mrp_view.xml 2014-05-20 10:51:47 +0000
@@ -671,32 +671,57 @@
671 <field name="arch" type="xml">671 <field name="arch" type="xml">
672 <form string="Manufacturing Orders" version="7.0">672 <form string="Manufacturing Orders" version="7.0">
673 <header>673 <header>
674<<<<<<< TREE
674 <button name="button_confirm" states="draft" string="Confirm Production" class="oe_highlight"/>675 <button name="button_confirm" states="draft" string="Confirm Production" class="oe_highlight"/>
675 <button name="%(act_mrp_product_produce)d" states="ready,in_production" string="Produce" type="action" class="oe_highlight"/>676 <button name="%(act_mrp_product_produce)d" states="ready,in_production" string="Produce" type="action" class="oe_highlight"/>
676 <button name="action_assign" states="confirmed,picking_except" string="Check Availability" type="object" class="oe_highlight"/>677 <button name="action_assign" states="confirmed,picking_except" string="Check Availability" type="object" class="oe_highlight"/>
677 <button name="force_production" states="confirmed" string="Force Reservation" type="object"/>678 <button name="force_production" states="confirmed" string="Force Reservation" type="object"/>
679=======
680 <button name="button_confirm" string="Confirm Production" class="oe_highlight" attrs="{'invisible':['|',('disassemble', '=', True),('state','!=','draft')]}"/>
681 <button name="button_confirm" string="Confirm Dismantling" class="oe_highlight" attrs="{'invisible':['|',('disassemble', '=', False),('state','!=','draft')]}"/>
682 <button name="%(act_mrp_product_produce)d" string="Produce" type="action" class="oe_highlight" attrs="{'invisible':['|',('disassemble', '=', True),('state','not in',('ready', 'in_production'))]}"/>
683 <button name="%(act_mrp_disassemble_product)d" string="Disassemble" type="action" class="oe_highlight" attrs="{'invisible':['|',('disassemble', '=', False),('state','not in',('confirmed', 'ready', 'in_production'))]}"/>
684 <button name="force_production" states="confirmed" string="Force Reservation" type="object" class="oe_highlight"/>
685 <button name="force_production" states="picking_except" string="Force Reservation" type="object"/>
686>>>>>>> MERGE-SOURCE
678 <button name="button_produce" states="ready" string="Mark as Started"/>687 <button name="button_produce" states="ready" string="Mark as Started"/>
688<<<<<<< TREE
679 <button name="button_cancel" states="draft,ready,in_production" string="Cancel Production"/>689 <button name="button_cancel" states="draft,ready,in_production" string="Cancel Production"/>
680 <button name="action_cancel" type="object" states="confirmed" string="Cancel Production"/>690 <button name="action_cancel" type="object" states="confirmed" string="Cancel Production"/>
681 <field name="state" widget="statusbar" statusbar_visible="draft,ready,in_production,done" statusbar_colors='{"confirmed":"blue"}'/>691 <field name="state" widget="statusbar" statusbar_visible="draft,ready,in_production,done" statusbar_colors='{"confirmed":"blue"}'/>
692=======
693 <button name="button_recreate" states="picking_except" string="Recreate Picking"/>
694 <button name="button_cancel" string="Cancel Production" attrs="{'invisible':['|',('disassemble', '=', True),('state','not in',('draft','ready','in_production','picking_except'))]}"/>
695 <button name="button_cancel" string="Cancel Dismantling" attrs="{'invisible':['|',('disassemble', '=', False),('state','not in',('draft','ready','in_production','picking_except'))]}"/>
696 <button name="action_cancel" type="object" string="Cancel Production" attrs="{'invisible':['|',('disassemble', '=', True),('state','!=','confirmed')]}"/>
697 <button name="action_cancel" type="object" string="Cancel Dismantling" attrs="{'invisible':['|',('disassemble', '=', False), ('state','!=','confirmed')]}"/>
698 <button name="%(action_change_disassemble_qty)d" type="action" string="Disassemble" attrs="{'invisible':['|','|', ('state','!=','done'), ('qty_to_disassemble','=',0)]}"/>
699 <field name="state" widget="statusbar" statusbar_visible="draft,ready,in_production,done" statusbar_colors='{"picking_except":"red","confirmed":"blue"}'/>
700>>>>>>> MERGE-SOURCE
682 </header>701 </header>
683 <sheet>702 <sheet>
684 <div class="oe_title">703 <div class="oe_title">
685 <h1>Manufacturing Order <field name="name" class="oe_inline"/></h1>704 <h1><label string="Disassemble" attrs="{'invisible':[('disassemble','=',False)]}" class="oe_inline"/>
705 Manufacturing Order <field name="name" class="oe_inline"/></h1>
686 </div>706 </div>
687 <group>707 <group>
688 <group>708 <group>
709<<<<<<< TREE
689 <field name="product_id" on_change="product_id_change(product_id, product_qty)" domain="[('bom_ids','!=',False),('bom_ids.bom_id','=',False),('bom_ids.type','!=','phantom')]" class="oe_inline" context='{"default_type": "product"}'/>710 <field name="product_id" on_change="product_id_change(product_id, product_qty)" domain="[('bom_ids','!=',False),('bom_ids.bom_id','=',False),('bom_ids.type','!=','phantom')]" class="oe_inline" context='{"default_type": "product"}'/>
711=======
712 <field name="product_id" on_change="product_id_change(product_id, product_qty)" domain="[('bom_ids','!=',False),('bom_ids.bom_id','=',False)]" class="oe_inline" context='{"default_supply_method":"produce", "default_type": "product"}'/>
713 <field name="qty_to_disassemble" invisible="1"/>
714>>>>>>> MERGE-SOURCE
690 <label for="product_qty"/>715 <label for="product_qty"/>
691 <div>716 <div>
692 <field name="product_qty" class="oe_inline" on_change="product_id_change(product_id, product_qty)"/>717 <field name="product_qty" widget="mrp_product_qty" class="oe_inline" on_change="onchange_product_qty(product_qty)"/>
693 <field name="product_uom" groups="product.group_uom" class="oe_inline"/>718 <field name="product_uom" groups="product.group_uom" class="oe_inline"/>
694 <button type="action"719 <button type="action"
695 name="%(mrp.action_change_production_qty)d"720 name="%(mrp.action_change_production_qty)d"
696 string="Update" states="confirmed" class="oe_edit_only oe_link"/>721 string="Update" states="confirmed" class="oe_edit_only oe_link"/>
697 </div>722 </div>
698 <label for="product_uos_qty" groups="product.group_uos"/>723 <label for="product_uos_qty" attrs="{'invisible':[('disassemble', '=', True)]}" groups="product.group_uos"/>
699 <div groups="product.group_uos">724 <div attrs="{'invisible':[('disassemble', '=', True)]}" groups="product.group_uos">
700 <field name="product_uos_qty" class="oe_inline"/>725 <field name="product_uos_qty" class="oe_inline"/>
701 <label string="-" attrs="{'invisible':[('product_uos','=',False)]}" class="oe_inline"/>726 <label string="-" attrs="{'invisible':[('product_uos','=',False)]}" class="oe_inline"/>
702 <field name="product_uos" class="oe_inline"/>727 <field name="product_uos" class="oe_inline"/>
@@ -715,16 +740,21 @@
715 </group>740 </group>
716 </group>741 </group>
717 <notebook>742 <notebook>
718 <page string="Consumed Products">743 <page string="Consumed Products" name="consumed_products">
719 <group>744 <group>
720 <group string="Products to Consume">745 <group string="Products to Consume" name="group_to_consume">
721 <field name="move_lines" nolabel="1" options="{'reload_on_button': true}">746 <field name="move_lines" nolabel="1" options="{'reload_on_button': true}">
722 <tree colors="blue:state == 'draft';black:state in ('ready','assigned','in_production');gray:state in ('cancel','done');red:state in ('confirmed','waiting')" string="Products to Consume">747 <tree colors="blue:state == 'draft';black:state in ('ready','assigned','in_production');gray:state in ('cancel','done');red:state in ('confirmed','waiting')" string="Products to Consume">
723 <field name="product_id"/>748 <field name="product_id"/>
724 <field name="product_qty" string="Quantity"/>749 <field name="product_qty" string="Quantity"/>
725 <field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>750 <field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
726 <field name="state" invisible="1"/>751 <field name="state" invisible="1"/>
752<<<<<<< TREE
727 <button name="%(mrp.move_consume)d"753 <button name="%(mrp.move_consume)d"
754=======
755 <field name="disassemble" invisible="1"/>
756 <button name="%(stock.move_consume)d"
757>>>>>>> MERGE-SOURCE
728 string="Consume Products" type="action"758 string="Consume Products" type="action"
729 icon="gtk-go-forward" context="{'consume': True}"759 icon="gtk-go-forward" context="{'consume': True}"
730 states="assigned"760 states="assigned"
@@ -732,11 +762,11 @@
732 <button name="%(stock.move_scrap)d"762 <button name="%(stock.move_scrap)d"
733 string="Scrap Products" type="action"763 string="Scrap Products" type="action"
734 icon="terp-gtk-jump-to-ltr" context="{'scrap': True}"764 icon="terp-gtk-jump-to-ltr" context="{'scrap': True}"
735 states="draft,waiting,confirmed,assigned"/>765 attrs="{'invisible':['|',('disassemble', '=', True),('state', '=', 'cancel')]}"/>
736 </tree>766 </tree>
737 </field>767 </field>
738 </group>768 </group>
739 <group string="Consumed Products">769 <group string="Consumed Products" name="group_consumed">
740 <field name="move_lines2" nolabel="1" options="{'reload_on_button': true}">770 <field name="move_lines2" nolabel="1" options="{'reload_on_button': true}">
741 <tree colors="red:scrapped==True;blue:state == 'draft';black:state in ('confirmed','ready','in_production');gray:state == 'cancel' " string="Consumed Products" editable="bottom">771 <tree colors="red:scrapped==True;blue:state == 'draft';black:state in ('confirmed','ready','in_production');gray:state == 'cancel' " string="Consumed Products" editable="bottom">
742 <field name="product_id" readonly="1"/>772 <field name="product_id" readonly="1"/>
@@ -745,12 +775,17 @@
745 <field name="product_uom" readonly="1" string="Unit of Measure" groups="product.group_uom"/>775 <field name="product_uom" readonly="1" string="Unit of Measure" groups="product.group_uom"/>
746 <field name="state" invisible="1"/>776 <field name="state" invisible="1"/>
747 <field name="scrapped" invisible="1"/>777 <field name="scrapped" invisible="1"/>
778 <field name="disassemble" invisible="1"/>
779 <button name="%(stock.move_scrap)d"
780 string="Scrap Products" type="action"
781 icon="terp-gtk-jump-to-ltr" context="{'scrap': True}"
782 attrs="{'invisible':['|',('disassemble', '=', False),('state', '=', 'cancel')]}"/>
748 </tree>783 </tree>
749 </field>784 </field>
750 </group>785 </group>
751 </group>786 </group>
752 </page>787 </page>
753 <page string="Finished Products">788 <page string="Finished Products" attrs="{'invisible':[('disassemble', '=', True)]}">
754 <group>789 <group>
755 <group string="Products to Produce">790 <group string="Products to Produce">
756 <field name="move_created_ids" nolabel="1" options="{'reload_on_button': true}">791 <field name="move_created_ids" nolabel="1" options="{'reload_on_button': true}">
@@ -804,7 +839,7 @@
804 </tree>839 </tree>
805 </field>840 </field>
806 </page>841 </page>
807 <page string="Scheduled Products">842 <page string="Scheduled Products" attrs="{'invisible':[('disassemble', '=', True)]}">
808 <button name="action_compute" states="draft"843 <button name="action_compute" states="draft"
809 string="Compute Data" type="object"844 string="Compute Data" type="object"
810 icon="terp-stock_format-scientific"/>845 icon="terp-stock_format-scientific"/>
@@ -816,10 +851,18 @@
816 <field name="priority"/>851 <field name="priority"/>
817 <field name="date_start" invisible="1"/>852 <field name="date_start" invisible="1"/>
818 <field name="date_finished" invisible="1"/>853 <field name="date_finished" invisible="1"/>
854 <field name="disassemble" invisible="1"/>
855 <field name="disassemble_doc" attrs="{'invisible':[('disassemble_doc', '=', False)]}"/>
819 </group>856 </group>
820 <group>857 <group>
858<<<<<<< TREE
821 <field name="company_id" groups="base.group_multi_company" widget="selection" /> 859 <field name="company_id" groups="base.group_multi_company" widget="selection" />
822 <field name="move_prod_id" groups="stock.group_locations"/>860 <field name="move_prod_id" groups="stock.group_locations"/>
861=======
862 <field name="company_id" groups="base.group_multi_company" widget="selection"/>
863 <field name="picking_id" attrs="{'invisible':[('disassemble', '=', True)]}"/>
864 <field name="move_prod_id" attrs="{'invisible':[('disassemble', '=', True)]}" groups="stock.group_locations"/>
865>>>>>>> MERGE-SOURCE
823 </group>866 </group>
824 </group>867 </group>
825 </page>868 </page>
@@ -845,6 +888,10 @@
845 help="Manufacturing Orders which are ready to start production."/>888 help="Manufacturing Orders which are ready to start production."/>
846 <filter icon="terp-check" string="In Production" name="inprogress" domain="[('state','=','in_production')]"889 <filter icon="terp-check" string="In Production" name="inprogress" domain="[('state','=','in_production')]"
847 help="Manufacturing Orders which are currently in production."/>890 help="Manufacturing Orders which are currently in production."/>
891 <filter string="Manufacturing" name="manufacturing" domain="[('disassemble', '=', False)]"
892 help="Manufacturing Orders."/>
893 <filter string="Disassemble" name="disassemble" domain="[('product_qty', '&lt;', 0)]"
894 help="Disassemble Orders."/>
848 <separator/>895 <separator/>
849 <filter icon="terp-gnome-cpu-frequency-applet+" string="Late" domain="['&amp;', ('date_planned','&lt;', current_date), ('state', 'in', ('draft', 'confirmed', 'ready'))]"896 <filter icon="terp-gnome-cpu-frequency-applet+" string="Late" domain="['&amp;', ('date_planned','&lt;', current_date), ('state', 'in', ('draft', 'confirmed', 'ready'))]"
850 help="Production started late"/>897 help="Production started late"/>
851898
=== modified file 'mrp/procurement.py'
--- mrp/procurement.py 2014-05-07 17:14:31 +0000
+++ mrp/procurement.py 2014-05-20 10:51:47 +0000
@@ -77,6 +77,7 @@
77 bom_obj = self.pool.get('mrp.bom')77 bom_obj = self.pool.get('mrp.bom')
78 procurement_obj = self.pool.get('procurement.order')78 procurement_obj = self.pool.get('procurement.order')
79 for procurement in procurement_obj.browse(cr, uid, ids, context=context):79 for procurement in procurement_obj.browse(cr, uid, ids, context=context):
80<<<<<<< TREE
80 if self.check_bom_exists(cr, uid, [procurement.id], context=context):81 if self.check_bom_exists(cr, uid, [procurement.id], context=context):
81 if procurement.bom_id:82 if procurement.bom_id:
82 bom_id = procurement.bom_id.id83 bom_id = procurement.bom_id.id
@@ -116,6 +117,33 @@
116 else:117 else:
117 res[procurement.id] = False118 res[procurement.id] = False
118 self.message_post(cr, uid, [procurement.id], body=_("No BoM exists for this product!"), context=context)119 self.message_post(cr, uid, [procurement.id], body=_("No BoM exists for this product!"), context=context)
120=======
121 res_id = procurement.move_id.id
122 newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0)
123 newdate = newdate - relativedelta(days=company.manufacturing_lead)
124 produce_id = production_obj.create(cr, uid, {
125 'origin': procurement.origin,
126 'product_id': procurement.product_id.id,
127 'product_qty': procurement.product_qty,
128 'qty_to_disassemble': procurement.product_qty,
129 'product_uom': procurement.product_uom.id,
130 'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
131 'product_uos': procurement.product_uos and procurement.product_uos.id or False,
132 'location_src_id': procurement.location_id.id,
133 'location_dest_id': procurement.location_id.id,
134 'bom_id': procurement.bom_id and procurement.bom_id.id or False,
135 'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
136 'move_prod_id': res_id,
137 'company_id': procurement.company_id.id,
138 })
139
140 res[procurement.id] = produce_id
141 self.write(cr, uid, [procurement.id], {'state': 'running', 'production_id': produce_id})
142 bom_result = production_obj.action_compute(cr, uid,
143 [produce_id], properties=[x.id for x in procurement.property_ids])
144 production_obj.signal_button_confirm(cr, uid, [produce_id])
145 self.production_order_create_note(cr, uid, ids, context=context)
146>>>>>>> MERGE-SOURCE
119 return res147 return res
120148
121 def production_order_create_note(self, cr, uid, procurement, context=None):149 def production_order_create_note(self, cr, uid, procurement, context=None):
122150
=== added directory 'mrp/static/src/js'
=== added file 'mrp/static/src/js/mrp.js'
--- mrp/static/src/js/mrp.js 1970-01-01 00:00:00 +0000
+++ mrp/static/src/js/mrp.js 2014-05-20 10:51:47 +0000
@@ -0,0 +1,38 @@
1openerp.mrp = function(instance) {
2var _t = instance.web._t;
3
4instance.web.form.mrp_product_qty = instance.web.form.FieldFloat.extend({
5 init: function(field_manager, node) {
6 var self = this;
7 this._super(field_manager, node);
8 this.on("change:value", this, function() {
9 self.update_label(this.get('value'));
10 });
11 var $page = this.view.$el.find("a[name='consumed_products']");
12 var $label_product = this.view.$el.find("div[name='group_to_consume']");
13 var $label_consumed = this.view.$el.find("div[name='group_consumed']");
14 this.label_list = [$page, $label_product, $label_consumed];
15 this.label_value = [[_t("Consumed Products"),_t("Disassembled Products")],
16 [_t("Products to Consume"),_t("Products to Disassemble")],
17 [_t("Consumed Products"),_t("Disassembled Products")]];
18 },
19 update_label:function(value){
20 var self = this
21 _.map(self.label_list, function(ele, i){
22 value > 0 ? ele.text(self.label_value[i][0]) : ele.text(self.label_value[i][1])
23 });
24 },
25 parse_value: function(val, def) {
26 if (this.widget) this.widget='float'
27 return instance.web.parse_value(val, this, def);
28 },
29 format_value: function(val, def) {
30 if (this.widget) this.widget='float'
31 return instance.web.format_value(val, this, def);
32 },
33
34});
35instance.web.form.widgets = instance.web.form.widgets.extend({
36'mrp_product_qty': 'instance.web.form.mrp_product_qty',
37});
38}
039
=== added file 'mrp/test/disassemble_process.yml'
--- mrp/test/disassemble_process.yml 1970-01-01 00:00:00 +0000
+++ mrp/test/disassemble_process.yml 2014-05-20 10:51:47 +0000
@@ -0,0 +1,96 @@
1-
2 MRP user can doing all process related to Production Order, so let's check data with giving the access rights of user.
3-
4 !context
5 uid: 'res_users_mrp_user'
6-
7 In order to test Disassemble feature in OpenERP we will create a Production order with negative quantity for PC Assemble SC349
8-
9 !record {model: mrp.production, id: mrp_production_test2}:
10 product_id: product.product_product_4
11 product_qty: -5.0
12 location_src_id: stock.stock_location_14
13 location_dest_id: stock.stock_location_output
14 bom_id: mrp_bom_24
15 routing_id: mrp.mrp_routing_1
16-
17 I compute the production order.
18-
19 !python {model: mrp.production}: |
20 order = self.browse(cr, uid, ref("mrp_production_test2"), context=context)
21 order.action_compute(context=context)
22-
23 I check production lines after compute.
24-
25 !python {model: mrp.production}: |
26 order = self.browse(cr, uid, ref("mrp_production_test2"), context=context)
27 assert len(order.product_lines) == 5, "Production lines are not generated proper."
28-
29 Now I check workcenter lines.
30-
31 !python {model: mrp.production}: |
32 from openerp.tools import float_compare
33 def assert_equals(value1, value2, msg, float_compare=float_compare):
34 assert float_compare(value1, value2, precision_digits=2) == 0, msg
35 order = self.browse(cr, uid, ref("mrp_production_test2"), context=context)
36 assert len(order.workcenter_lines), "Workcenter lines are not generated proper."
37-
38 I confirm the Production Order.
39-
40 !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_test2}
41-
42 I check details of Produce Move of Production Order to trace Final Product.
43-
44 !python {model: mrp.production}: |
45 order = self.browse(cr, uid, ref("mrp_production_test2"))
46 assert order.state == 'ready', "Production order should be ready."
47 assert order.move_created_ids, "Trace Record is not created for Final Product."
48 move = order.move_created_ids[0]
49 source_location_id = order.product_id.property_stock_production.id
50 assert move.date == order.date_planned, "Planned date is not correspond."
51 assert move.product_id.id == order.product_id.id, "Product is not correspond."
52 assert move.product_uom.id == order.product_uom.id, "UOM is not correspond."
53 assert move.product_qty == abs(order.product_qty), "Qty is not correspond."
54 assert move.product_uos_qty == order.product_uos and order.product_uos_qty or abs(order.product_qty), "UOS qty is not correspond."
55 if order.product_uos:
56 assert move.product_uos.id == order.product_uos.id, "UOS is not correspond."
57 assert move.location_id.id == order.location_dest_id.id, "Source Location is not correspond."
58 assert move.location_dest_id.id == source_location_id, "Destination Location is not correspond."
59 routing_loc = None
60 if order.bom_id.routing_id and order.bom_id.routing_id.location_id:
61 routing_loc = order.bom_id.routing_id.location_id.id
62 date_planned = order.date_planned
63 for move_line in order.move_lines:
64 for order_line in order.product_lines:
65 if move_line.product_id.type not in ('product', 'consu'):
66 continue
67 if move_line.product_id.id == order_line.product_id.id:
68 assert move_line.date == date_planned, "Planned date is not correspond in 'To consume line'."
69 assert move_line.product_qty == order_line.product_qty, "Qty is not correspond in 'To consume line'."
70 assert move_line.product_uom.id == order_line.product_uom.id, "UOM is not correspond in 'To consume line'."
71 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'."
72 if order_line.product_uos:
73 assert move_line.product_uos.id == order_line.product_uos.id, "UOS is not correspond in 'To consume line'."
74 assert move_line.location_id.id == source_location_id, "Source location is not correspond in 'To consume line'."
75 assert move_line.location_dest_id.id == routing_loc or order.location_src_id.id, "Destination Location is not correspond in 'To consume line'."
76-
77 I check that production order in ready state.
78-
79 !python {model: mrp.production}: |
80 order = self.browse(cr, uid, ref("mrp_production_test2"))
81 assert order.state == 'ready', 'Production order should be in Ready State.'
82
83-
84 I check that production order in production state after start production.
85-
86 !python {model: mrp.production}: |
87 order = self.browse(cr, uid, ref("mrp_production_test2"))
88 context.update({'active_id': ref('mrp_production_test2')})
89 assert self.action_produce(cr, uid, order.id , 5.0, 'consume_produce'), 'Can not do action produce.'
90
91-
92 I check that production order in Done state.
93-
94 !python {model: mrp.production}: |
95 order = self.browse(cr, uid, ref("mrp_production_test2"))
96 assert order.state == 'done', 'Production order should be in Done State.'
097
=== modified file 'mrp/test/order_demo.yml'
--- mrp/test/order_demo.yml 2014-04-04 16:17:13 +0000
+++ mrp/test/order_demo.yml 2014-05-20 10:51:47 +0000
@@ -13,5 +13,3 @@
13 location_dest_id: stock.stock_location_output13 location_dest_id: stock.stock_location_output
14 bom_id: mrp_bom_2414 bom_id: mrp_bom_24
15 routing_id: mrp.mrp_routing_115 routing_id: mrp.mrp_routing_1
16
17
1816
=== modified file 'mrp/wizard/__init__.py'
--- mrp/wizard/__init__.py 2014-01-28 15:18:34 +0000
+++ mrp/wizard/__init__.py 2014-05-20 10:51:47 +0000
@@ -23,7 +23,11 @@
23import mrp_price23import mrp_price
24import mrp_workcenter_load24import mrp_workcenter_load
25import change_production_qty25import change_production_qty
26<<<<<<< TREE
26import stock_move27import stock_move
28=======
29import disassemble_qty
30>>>>>>> MERGE-SOURCE
27#import mrp_change_standard_price31#import mrp_change_standard_price
2832
29# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:33# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3034
=== modified file 'mrp/wizard/change_production_qty.py'
--- mrp/wizard/change_production_qty.py 2013-11-29 16:56:44 +0000
+++ mrp/wizard/change_production_qty.py 2014-05-20 10:51:47 +0000
@@ -71,7 +71,7 @@
71 move_obj = self.pool.get('stock.move')71 move_obj = self.pool.get('stock.move')
72 for wiz_qty in self.browse(cr, uid, ids, context=context):72 for wiz_qty in self.browse(cr, uid, ids, context=context):
73 prod = prod_obj.browse(cr, uid, record_id, context=context)73 prod = prod_obj.browse(cr, uid, record_id, context=context)
74 prod_obj.write(cr, uid, [prod.id], {'product_qty': wiz_qty.product_qty})74 prod_obj.write(cr, uid, [prod.id], {'product_qty': wiz_qty.product_qty, 'qty_to_disassemble': wiz_qty.product_qty, 'disassemble': wiz_qty.product_qty < 0 and True or False}, context=context)
75 prod_obj.action_compute(cr, uid, [prod.id])75 prod_obj.action_compute(cr, uid, [prod.id])
7676
77 for move in prod.move_lines:77 for move in prod.move_lines:
7878
=== added file 'mrp/wizard/disassemble_qty.py'
--- mrp/wizard/disassemble_qty.py 1970-01-01 00:00:00 +0000
+++ mrp/wizard/disassemble_qty.py 2014-05-20 10:51:47 +0000
@@ -0,0 +1,64 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from openerp.osv import fields, osv
23from openerp.tools.translate import _
24import openerp.addons.decimal_precision as dp
25
26class change_disassemble_qty(osv.osv_memory):
27 _name = 'change.disassemble.qty'
28 _description = 'Change Quantity for Disassemble Products'
29
30 _columns = {
31 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
32 }
33
34 def default_get(self, cr, uid, fields, context=None):
35 """ To get default values for the object.
36 @param self: The object pointer.
37 @param cr: A database cursor
38 @param uid: ID of the user currently logged in
39 @param fields: List of fields for which we want default values
40 @param context: A standard dictionary
41 @return: A dictionary which of fields with values.
42 """
43 if context is None:
44 context = {}
45 res = super(change_disassemble_qty, self).default_get(cr, uid, fields, context=context)
46 prod = self.pool.get('mrp.production').browse(cr, uid, context.get('active_id'), context=context)
47 if 'product_qty' in fields:
48 res.update({'product_qty': prod.qty_to_disassemble * -1 })
49 return res
50
51 def change_disassemble_qty(self, cr, uid, ids, context=None):
52 mrp_production_obj = self.pool.get('mrp.production')
53 mrp_id = context.get('active_id', False)
54 qty = self.browse(cr, uid, ids[0], context=context).product_qty
55 if qty >= 0:
56 raise osv.except_osv(_('Warning!'), _('Quantity must be negative to disassemble.'))
57 mrp_record = mrp_production_obj.browse(cr, uid, mrp_id, context=context)
58 mrp_record.write({'qty_to_disassemble': mrp_record.qty_to_disassemble - abs(qty)}, context=context)
59 if mrp_record.qty_to_disassemble < abs(qty) :
60 raise osv.except_osv(_('Warning!'), _('You are going to disassemble total %s quantities of "%s".\nBut you can only disassemble up to total %s quantities.') % (abs(qty), mrp_record.product_id.name, mrp_record.qty_to_disassemble))
61 return mrp_production_obj.action_disassemble(cr, uid, mrp_id, qty, context=context)
62
63# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
64
065
=== added file 'mrp/wizard/disassemble_qty_view.xml'
--- mrp/wizard/disassemble_qty_view.xml 1970-01-01 00:00:00 +0000
+++ mrp/wizard/disassemble_qty_view.xml 2014-05-20 10:51:47 +0000
@@ -0,0 +1,37 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <!-- Change Product Quantity for Disassemble Order-->
6
7 <record id="view_change_disassemble_qty_wizard" model="ir.ui.view">
8 <field name="name">Change Disassemble Order Qty</field>
9 <field name="model">change.disassemble.qty</field>
10 <field name="arch" type="xml">
11 <form string="Change Disassemble Order Quantity in Negative" version="7.0">
12 <newline/>
13 <group col="7">
14 <field name="product_qty" />
15 <label string="Use negative quantity for disassemble order" colspan="5" class="oe_left oe_grey" style="margin-top: 5px;"/>
16 </group>
17 <footer>
18 <button name="change_disassemble_qty" string="Create"
19 colspan="1" type="object" class="oe_highlight" />
20 or
21 <button string="Cancel" class="oe_link" special="cancel" />
22 </footer>
23 </form>
24 </field>
25 </record>
26
27 <record id="action_change_disassemble_qty" model="ir.actions.act_window">
28 <field name="name">Select Quantity to Disassemble</field>
29 <field name="type">ir.actions.act_window</field>
30 <field name="res_model">change.disassemble.qty</field>
31 <field name="view_type">form</field>
32 <field name="view_mode">form</field>
33 <field name="target">new</field>
34 </record>
35
36 </data>
37</openerp>
038
=== modified file 'mrp/wizard/mrp_product_produce.py'
--- mrp/wizard/mrp_product_produce.py 2014-05-07 16:59:51 +0000
+++ mrp/wizard/mrp_product_produce.py 2014-05-20 10:51:47 +0000
@@ -20,7 +20,9 @@
20##############################################################################20##############################################################################
2121
22from openerp.osv import fields, osv22from openerp.osv import fields, osv
23from lxml import etree
23import openerp.addons.decimal_precision as dp24import openerp.addons.decimal_precision as dp
25from openerp.tools.translate import _
2426
2527
26class mrp_product_produce_line(osv.osv_memory):28class mrp_product_produce_line(osv.osv_memory):
@@ -52,6 +54,7 @@
52 'track_production': fields.boolean('Track production'),54 'track_production': fields.boolean('Track production'),
53 }55 }
5456
57<<<<<<< TREE
55 def on_change_qty(self, cr, uid, ids, product_qty, consume_lines, context=None):58 def on_change_qty(self, cr, uid, ids, product_qty, consume_lines, context=None):
56 """ 59 """
57 When changing the quantity of products to be produced it will 60 When changing the quantity of products to be produced it will
@@ -72,6 +75,20 @@
72 return {'value': {'consume_lines': new_consume_lines}}75 return {'value': {'consume_lines': new_consume_lines}}
7376
7477
78=======
79 def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
80 if context is None:
81 context = {}
82 res = super(mrp_product_produce,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
83 doc = etree.XML(res['arch'])
84 mrp_production = self.pool.get('mrp.production').browse(cr, uid, context.get('active_id'), context=context)
85 if view_type == 'form' and mrp_production.disassemble == True:
86 for node in doc.xpath("//group[@name='produce']"):
87 node.set('string',_('Product to Disassemble'))
88 res['arch'] = etree.tostring(doc)
89 return res
90
91>>>>>>> MERGE-SOURCE
75 def _get_product_qty(self, cr, uid, context=None):92 def _get_product_qty(self, cr, uid, context=None):
76 """ To obtain product quantity93 """ To obtain product quantity
77 @param self: The object pointer.94 @param self: The object pointer.
@@ -89,7 +106,7 @@
89 if move.product_id == prod.product_id:106 if move.product_id == prod.product_id:
90 if not move.scrapped:107 if not move.scrapped:
91 done += move.product_qty108 done += move.product_qty
92 return (prod.product_qty - done) or prod.product_qty109 return (abs(prod.product_qty) - done) or abs(prod.product_qty)
93110
94 def _get_product_id(self, cr, uid, context=None):111 def _get_product_id(self, cr, uid, context=None):
95 """ To obtain product id112 """ To obtain product id
96113
=== modified file 'mrp/wizard/mrp_product_produce_view.xml'
--- mrp/wizard/mrp_product_produce_view.xml 2014-02-05 10:43:24 +0000
+++ mrp/wizard/mrp_product_produce_view.xml 2014-05-20 10:51:47 +0000
@@ -1,17 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<openerp>2<openerp>
3 <data>3 <data>
4 4
5
6 <!-- Produce -->5 <!-- Produce -->
7 6
8 <record id="view_mrp_product_produce_wizard" model="ir.ui.view">7 <record id="view_mrp_product_produce_wizard" model="ir.ui.view">
9 <field name="name">MRP Product Produce</field>8 <field name="name">MRP Product Produce</field>
10 <field name="model">mrp.product.produce</field>9 <field name="model">mrp.product.produce</field>
11 <field name="arch" type="xml">10 <field name="arch" type="xml">
12 <form string="Produce" version="7.0">11 <form string="Produce" version="7.0">
13 <group string="Produce">12 <group name="produce" string="Produce">
14 <field name="mode"/>13 <field name="mode"/>
14<<<<<<< TREE
15 <field name="product_qty" colspan="2" on_change="on_change_qty(product_qty, consume_lines, context)"/>15 <field name="product_qty" colspan="2" on_change="on_change_qty(product_qty, consume_lines, context)"/>
16 <field name="product_id" invisible="1"/>16 <field name="product_id" invisible="1"/>
17 <field name="track_production" invisible="1"/>17 <field name="track_production" invisible="1"/>
@@ -31,6 +31,10 @@
31 </tree>31 </tree>
32 </field>32 </field>
33 </group>33 </group>
34=======
35 <field name="product_qty" colspan="2"/>
36 </group>
37>>>>>>> MERGE-SOURCE
34 <footer>38 <footer>
35 <button name="do_produce" type="object" string="Confirm" class="oe_highlight"/>39 <button name="do_produce" type="object" string="Confirm" class="oe_highlight"/>
36 or40 or
@@ -47,8 +51,16 @@
47 <field name="view_type">form</field>51 <field name="view_type">form</field>
48 <field name="view_mode">form</field>52 <field name="view_mode">form</field>
49 <field name="target">new</field>53 <field name="target">new</field>
50 </record> 54 </record>
51 55
52 56 <record id="act_mrp_disassemble_product" model="ir.actions.act_window">
57 <field name="name">Disassemble</field>
58 <field name="type">ir.actions.act_window</field>
59 <field name="res_model">mrp.product.produce</field>
60 <field name="view_type">form</field>
61 <field name="view_mode">form</field>
62 <field name="target">new</field>
63 </record>
64
53 </data>65 </data>
54</openerp> 66</openerp>
5567
=== modified file 'mrp_byproduct/mrp_byproduct.py'
--- mrp_byproduct/mrp_byproduct.py 2014-04-22 12:16:25 +0000
+++ mrp_byproduct/mrp_byproduct.py 2014-05-20 10:51:47 +0000
@@ -102,6 +102,8 @@
102 qty1 *= product_uom_factor / (production.bom_id.product_qty or 1.0)102 qty1 *= product_uom_factor / (production.bom_id.product_qty or 1.0)
103 if production.product_uos_qty:103 if production.product_uos_qty:
104 qty2 *= product_uos_factor / (production.bom_id.product_uos_qty or 1.0)104 qty2 *= product_uos_factor / (production.bom_id.product_uos_qty or 1.0)
105 if production.disassemble:
106 continue
105 data = {107 data = {
106 'name': 'PROD:'+production.name,108 'name': 'PROD:'+production.name,
107 'date': production.date_planned,109 'date': production.date_planned,
@@ -110,8 +112,8 @@
110 'product_uom': sub_product.product_uom.id,112 'product_uom': sub_product.product_uom.id,
111 'product_uos_qty': qty2,113 'product_uos_qty': qty2,
112 'product_uos': production.product_uos and production.product_uos.id or False,114 'product_uos': production.product_uos and production.product_uos.id or False,
113 'location_id': source,115 'location_id': source if not production.disassemble else production.location_dest_id.id,
114 'location_dest_id': production.location_dest_id.id,116 'location_dest_id': production.location_dest_id.id if not production.disassemble else source,
115 'move_dest_id': production.move_prod_id.id,117 'move_dest_id': production.move_prod_id.id,
116 'state': 'waiting',118 'state': 'waiting',
117 'production_id': production.id119 'production_id': production.id
118120
=== modified file 'mrp_operations/mrp_operations.py'
--- mrp_operations/mrp_operations.py 2014-04-23 09:48:07 +0000
+++ mrp_operations/mrp_operations.py 2014-05-20 10:51:47 +0000
@@ -139,7 +139,8 @@
139 if flag:139 if flag:
140 for production in prod_obj_pool.browse(cr, uid, [prod_obj.id], context= None):140 for production in prod_obj_pool.browse(cr, uid, [prod_obj.id], context= None):
141 if production.move_lines or production.move_created_ids:141 if production.move_lines or production.move_created_ids:
142 prod_obj_pool.action_produce(cr,uid, production.id, production.product_qty, 'consume_produce', context = None)142 product_qty = production.disassemble and abs(production.product_qty) or production.product_qty
143 prod_obj_pool.action_produce(cr,uid, production.id, product_qty, 'consume_produce', context = None)
143 prod_obj_pool.signal_button_produce_done(cr, uid, [oper_obj.production_id.id])144 prod_obj_pool.signal_button_produce_done(cr, uid, [oper_obj.production_id.id])
144 return145 return
145146

Subscribers

People subscribed via source and target branches

to all changes: