[IMP] notifications in mrp,bom,product.

bzr revid: bth@tinyerp.com-20120306133816-59cs058o3oq8arro
This commit is contained in:
Bhumi Thakkar (Open ERP) 2012-03-06 19:08:16 +05:30
parent 526281d470
commit d83bf22983
7 changed files with 174 additions and 34 deletions

View File

@ -130,6 +130,7 @@ class mrp_bom(osv.osv):
"""
_name = 'mrp.bom'
_description = 'Bill of Material'
_inherit = ['mail.thread']
def _child_compute(self, cr, uid, ids, name, arg, context=None):
""" Gets child bom.
@ -312,7 +313,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]
@ -358,6 +359,19 @@ class mrp_bom(osv.osv):
default.update({'name': bom_data['name'] + ' ' + _('Copy'), 'bom_id':False})
return super(mrp_bom, self).copy_data(cr, uid, id, default, context=context)
def create(self, cr, uid, vals, context=None):
obj_id = super(mrp_bom, self).create(cr, uid, vals, context=context)
self.create_notification(cr, uid, [obj_id], context=context)
return obj_id
def create_notification(self, cr, uid, ids, context=None):
prod_obj = self.pool.get('product.product')
for obj in self.browse(cr, uid, ids, context=context):
for prod in prod_obj.browse(cr, uid, [obj.product_id], context=context):
self.message_append_note(cr, uid, ids, _('System notification'),
_("Bill of Material is <b>Created</b> for <em>%s</em> product.") % (prod.id.name_template), type='notification', context=context)
return True
mrp_bom()
class mrp_bom_revision(osv.osv):
@ -393,6 +407,7 @@ class mrp_production(osv.osv):
_name = 'mrp.production'
_description = 'Manufacturing Order'
_date_name = 'date_planned'
_inherit = ['mail.thread']
def _production_calc(self, cr, uid, ids, prop, unknow_none, context=None):
""" Calculates total hours and total no. of cycles for a production order.
@ -497,12 +512,54 @@ class mrp_production(osv.osv):
(_check_qty, 'Order quantity cannot be negative or zero!', ['product_qty']),
]
def create(self, cr, uid, vals, context=None):
obj_id = super(mrp_production, self).create(cr, uid, vals, context=context)
self.create_notification(cr, uid, [obj_id], context=context)
return obj_id
def unlink(self, cr, uid, ids, context=None):
for production in self.browse(cr, uid, ids, context=context):
if production.state not in ('draft', 'cancel'):
raise osv.except_osv(_('Invalid action !'), _('Cannot delete a manufacturing order in state \'%s\'') % production.state)
return super(mrp_production, self).unlink(cr, uid, ids, context=context)
def create_notification(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
if obj.user_id.id :
self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context)
self.message_append_note(cr, uid, ids, _('System notification'),
_("Manufacturing Order is <b>Created</b>."), type='notification', need_action_user_id=obj.user_id.id, context=context)
else :
self.message_append_note(cr, uid, ids, _('System notification'),
_("Manufacturing Order is <b>Created</b>."), type='notification', context=context)
return True
def cancel_notification(self, cr, uid, ids, context=None):
message = _("Manufacturing order is <b>cancelled</b>.")
self.message_append_note(cr, uid, ids, '', message, context=context)
return True
def ready_notification(self, cr, uid, ids, context=None):
message = _("Manufacturing order is <b>ready to produce</b>.")
self.message_append_note(cr, uid, ids, '', message, context=context)
return True
def inproduction_notification(self, cr, uid, ids, context=None):
message = _("Manufacturing order is <b>in production</b>.")
self.message_append_note(cr, uid, ids, '', message, context=context)
return True
def done_notification(self, cr, uid, ids, context=None):
self.message_mark_done(cr, uid, ids, context)
message = _("Manufacturing order is <b>done</b>.")
self.message_append_note(cr, uid, ids, '', message, context=context)
return True
def waiting_notification(self, cr, uid, ids, context=None):
message = _("Manufacturing order is <b>waiting for goods</b>.")
self.message_append_note(cr, uid, ids, '', message, context=context)
return True
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
@ -629,9 +686,10 @@ class mrp_production(osv.osv):
move_obj.action_cancel(cr, uid, [x.id for x in production.move_created_ids])
move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines])
self.write(cr, uid, ids, {'state': 'cancel'})
self.cancel_notification(cr, uid, ids, context)
return True
def action_ready(self, cr, uid, ids):
def action_ready(self, cr, uid, ids, context=None):
""" Changes the production state to Ready and location id of stock move.
@return: True
"""
@ -643,18 +701,18 @@ class mrp_production(osv.osv):
if production.move_prod_id:
move_obj.write(cr, uid, [production.move_prod_id.id],
{'location_id': production.location_dest_id.id})
message = _("Manufacturing order '%s' is ready to produce.") % ( name,)
self.log(cr, uid, production_id, message)
self.ready_notification(cr, uid, [production_id], context)
return True
def action_production_end(self, cr, uid, ids):
def action_production_end(self, cr, uid, ids, context=None):
""" Changes production state to Finish and writes finished date.
@return: True
"""
for production in self.browse(cr, uid, ids):
self._costs_generate(cr, uid, production)
return self.write(cr, uid, ids, {'state': 'done', 'date_finished': time.strftime('%Y-%m-%d %H:%M:%S')})
self.write(cr, uid, ids, {'state': 'done', 'date_finished': time.strftime('%Y-%m-%d %H:%M:%S')})
self.done_notification(cr, uid, ids, context)
return True
def test_production_done(self, cr, uid, ids):
""" Tests whether production is done or not.
@ -670,9 +728,9 @@ class mrp_production(osv.osv):
return res
def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None):
""" Compute the factor to compute the qty of procucts to produce for the given production_id. By default,
it's always equal to the quantity encoded in the production order or the production wizard, but if the
module mrp_subproduct is installed, then we must use the move_id to identify the product to produce
""" Compute the factor to compute the qty of procucts to produce for the given production_id. By default,
it's always equal to the quantity encoded in the production order or the production wizard, but if the
module mrp_subproduct is installed, then we must use the move_id to identify the product to produce
and its quantity.
:param production_id: ID of the mrp.order
:param move_id: ID of the stock move that needs to be produced. Will be used in mrp_subproduct.
@ -698,7 +756,6 @@ class mrp_production(osv.osv):
if (produced_product.scrapped) or (produced_product.product_id.id <> production.product_id.id):
continue
produced_qty += produced_product.product_qty
if production_mode in ['consume','consume_produce']:
consumed_data = {}
@ -733,7 +790,7 @@ class mrp_production(osv.osv):
prod_name = scheduled.product_id.name_get()[0][1]
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))
if qty <= 0.0:
# we already have more qtys consumed than we need
# we already have more qtys consumed than we need
continue
raw_product[0].action_consume(qty, raw_product[0].location_id.id, context=context)
@ -819,11 +876,12 @@ class mrp_production(osv.osv):
} )
return amount
def action_in_production(self, cr, uid, ids):
def action_in_production(self, cr, uid, ids, context=None):
""" Changes state to In Production and writes starting date.
@return: True
"""
self.write(cr, uid, ids, {'state': 'in_production', 'date_start': time.strftime('%Y-%m-%d %H:%M:%S')})
self.inproduction_notification(cr, uid, ids, context)
return True
def test_if_product(self, cr, uid, ids):
@ -890,14 +948,14 @@ class mrp_production(osv.osv):
'state': 'waiting',
'company_id': production.company_id.id,
})
def _make_production_internal_shipment(self, cr, uid, production, context=None):
ir_sequence = self.pool.get('ir.sequence')
stock_picking = self.pool.get('stock.picking')
routing_loc = None
pick_type = 'internal'
address_id = False
# Take routing address as a Shipment Address.
# If usage of routing location is a internal, make outgoing shipment otherwise internal shipment
if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
@ -926,7 +984,7 @@ class mrp_production(osv.osv):
stock_move = self.pool.get('stock.move')
source_location_id = production.product_id.product_tmpl_id.property_stock_production.id
destination_location_id = production.location_dest_id.id
move_name = _('PROD: %s') + production.name
move_name = _('PROD: %s') + production.name
data = {
'name': move_name,
'date': production.date_planned,
@ -983,7 +1041,7 @@ class mrp_production(osv.osv):
for production in self.browse(cr, uid, ids, context=context):
shipment_id = self._make_production_internal_shipment(cr, uid, production, context=context)
produce_move_id = self._make_production_produce_line(cr, uid, production, context=context)
# Take routing location as a Source Location.
source_location_id = production.location_src_id.id
if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
@ -994,14 +1052,14 @@ class mrp_production(osv.osv):
shipment_move_id = self._make_production_internal_shipment_line(cr, uid, line, shipment_id, consume_move_id,\
destination_location_id=source_location_id, context=context)
self._make_production_line_procurement(cr, uid, line, shipment_move_id, context=context)
wf_service.trg_validate(uid, 'stock.picking', shipment_id, 'button_confirm', cr)
production.write({'state':'confirmed'}, context=context)
message = _("Manufacturing order '%s' is scheduled for the %s.") % (
production.name,
datetime.strptime(production.date_planned,'%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'),
)
self.log(cr, uid, production.id, message)
self.waiting_notification(cr, uid, [production.id], context);
return shipment_id
def force_production(self, cr, uid, ids, *args):
@ -1019,6 +1077,7 @@ class mrp_production_workcenter_line(osv.osv):
_name = 'mrp.production.workcenter.line'
_description = 'Work Order'
_order = 'sequence'
_inherit = ['mail.thread']
_columns = {
'name': fields.char('Work Order', size=64, required=True),

View File

@ -410,6 +410,7 @@
<field colspan="4" name="property_ids" nolabel="1" groups="base.group_extended"/>
</page>
</notebook>
<field name="message_ids_social" widget="ThreadView"/>
</form>
</field>
</record>
@ -644,6 +645,7 @@
<label string="" colspan="2"/>
<field name="product_uos_qty" groups="product.group_uos"/>
<field name="product_uos" groups="product.group_uos"/>
<field name="user_id"/>
</group>
<notebook colspan="4">
@ -773,16 +775,14 @@
<field colspan="4" name="product_lines" nolabel="1" widget="one2many_list"/>
</page>
<page string="Extra Information">
<field name="user_id"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="priority" groups="base.group_extended"/>
<newline/>
<field name="date_start"/>
<field name="date_finished"/>
<field name="picking_id" groups="base.group_extended"/>
<field name="move_prod_id" groups="base.group_extended"/>
</page>
</notebook>
<field name="message_ids_social" widget="ThreadView"/>
</form>
</field>
</record>

View File

@ -156,11 +156,62 @@ class mrp_production_workcenter_line(osv.osv):
prod_obj.write(cr, uid, [prod.production_id.id], {'date_start':dstart}, context=context, mini=False)
return result
def draft_notification(self, cr, uid, ids):
prod_obj = self.pool.get('mrp.production')
for workorder in self.browse(cr, uid, ids):
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
message = _("<em>%s</em> Work Order is <b>created</b>.") % (workorder.name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
womessage = _("Work Order is <b>created</b> for <em>%s</em> production order.") % (prod.id.name)
self.message_append_note(cr, uid, ids, '', womessage)
return True
def start_notification(self, cr, uid, ids):
prod_obj = self.pool.get('mrp.production')
for workorder in self.browse(cr, uid, ids):
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
message = _("<em>%s</em> Work Order is <b>started</b>.") % (workorder.name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
womessage = _("Work Order is <b>started</b> for <em>%s</em> production order.") % (prod.id.name)
self.message_append_note(cr, uid, ids, '', womessage)
return True
def done_notification(self, cr, uid, ids):
prod_obj = self.pool.get('mrp.production')
for workorder in self.browse(cr, uid, ids):
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
message = _("<em>%s</em>Work Order is <b>finished</b>.") % (workorder.name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
womessage = _("Work Order is <b>done</b> for <em>%s</em> production order.") % (prod.id.name)
self.message_append_note(cr, uid, ids, '', womessage)
return True
def pending_notification(self, cr, uid, ids):
prod_obj = self.pool.get('mrp.production')
for workorder in self.browse(cr, uid, ids):
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
message = _("<em>%s</em>Work Order is <b>pending</b>.") % (workorder.name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
womessage = _("Work Order is <b>pending</b> for <em>%s</em> production order.") % (prod.id.name)
self.message_append_note(cr, uid, ids, '', womessage)
return True
def cancel_notification(self, cr, uid, ids):
prod_obj = self.pool.get('mrp.production')
for workorder in self.browse(cr, uid, ids):
for prod in prod_obj.browse(cr, uid, [workorder.production_id]):
message = _("<em>%s</em>Work Order is <b>cancelled</b>.") % (workorder.name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
womessage = _("Work Order is <b>cancelled</b> for <em>%s</em> production order.") % (prod.id.name)
self.message_append_note(cr, uid, ids, '', womessage)
return True
def action_draft(self, cr, uid, ids):
""" Sets state to draft.
@return: True
"""
self.write(cr, uid, ids, {'state':'draft'})
self.draft_notification(cr, uid, ids)
return True
def action_start_working(self, cr, uid, ids):
@ -169,6 +220,7 @@ class mrp_production_workcenter_line(osv.osv):
"""
self.modify_production_order_state(cr, uid, ids, 'start')
self.write(cr, uid, ids, {'state':'startworking', 'date_start': time.strftime('%Y-%m-%d %H:%M:%S')})
self.start_notification(cr, uid, ids)
return True
def action_done(self, cr, uid, ids):
@ -185,6 +237,7 @@ class mrp_production_workcenter_line(osv.osv):
delay += (date_finished-date_start).seconds / float(60*60)
self.write(cr, uid, ids, {'state':'done', 'date_finished': date_now,'delay':delay})
self.done_notification(cr, uid, ids)
self.modify_production_order_state(cr,uid,ids,'done')
return True
@ -193,6 +246,7 @@ class mrp_production_workcenter_line(osv.osv):
@return: True
"""
self.write(cr, uid, ids, {'state':'cancel'})
self.cancel_notification(cr, uid, ids)
return True
def action_pause(self, cr, uid, ids):
@ -200,6 +254,7 @@ class mrp_production_workcenter_line(osv.osv):
@return: True
"""
self.write(cr, uid, ids, {'state':'pause'})
self.pending_notification(cr, uid, ids)
return True
def action_resume(self, cr, uid, ids):
@ -207,6 +262,7 @@ class mrp_production_workcenter_line(osv.osv):
@return: True
"""
self.write(cr, uid, ids, {'state':'startworking'})
self.start_notification(cr, uid, ids)
return True
mrp_production_workcenter_line()
@ -251,7 +307,7 @@ class mrp_production(osv.osv):
if prod.workcenter_lines:
wf_service.trg_validate(uid, 'mrp.production.workcenter.line', prod.workcenter_lines[0].id, 'button_start_working', cr)
return super(mrp_production,self).action_in_production(cr, uid, ids)
def action_cancel(self, cr, uid, ids, context=None):
""" Cancels work order if production order is canceled.
@return: Super method

View File

@ -118,6 +118,7 @@
</group>
</page>
</notebook>
<field name="message_ids_social" widget="ThreadView"/>
</form>
</field>
</record>

View File

@ -167,7 +167,7 @@ class product_uom(osv.osv):
if value == 'reference':
return {'value': {'factor': 1, 'factor_inv': 1}}
return {}
def write(self, cr, uid, ids, vals, context=None):
if 'category_id' in vals:
for uom in self.browse(cr, uid, ids, context=context):
@ -231,7 +231,7 @@ class product_category(osv.osv):
_parent_store = True
_parent_order = 'sequence, name'
_order = 'parent_left'
def _check_recursion(self, cr, uid, ids, context=None):
level = 100
while len(ids):
@ -259,7 +259,7 @@ class product_template(osv.osv):
_description = "Product Template"
def _get_main_product_supplier(self, cr, uid, product, context=None):
"""Determines the main (best) product supplier for ``product``,
"""Determines the main (best) product supplier for ``product``,
returning the corresponding ``supplierinfo`` record, or False
if none were found. The default strategy is to select the
supplier with the highest priority (i.e. smallest sequence).
@ -503,6 +503,7 @@ class product_product(osv.osv):
_description = "Product"
_table = "product_product"
_inherits = {'product.template': 'product_tmpl_id'}
_inherit = ['mail.thread']
_order = 'default_code,name_template'
_columns = {
'qty_available': fields.function(_product_qty_available, type='float', string='Quantity On Hand'),
@ -526,7 +527,18 @@ class product_product(osv.osv):
'color': fields.integer('Color Index'),
'product_image': fields.binary('Image'),
}
def create(self, cr, uid, vals, context=None):
obj_id = super(product_product, self).create(cr, uid, vals, context=context)
self.create_notification(cr, uid, [obj_id], context=context)
return obj_id
def create_notification(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
self.message_append_note(cr, uid, ids, _('System notification'),
_("Product is <b>Created</b>."), type='notification', context=context)
return True
def unlink(self, cr, uid, ids, context=None):
unlink_ids = []
unlink_product_tmpl_ids = []

View File

@ -87,7 +87,7 @@
</group>
<group colspan="1" col="1">
<field name="product_image" widget='image' nolabel="1"/>
</group>
</group>
</group>
<notebook colspan="4">
@ -192,6 +192,7 @@
</field>
</page>
</notebook>
<field name="message_ids_social" widget="ThreadView"/>
</form>
</field>
</record>
@ -257,24 +258,24 @@
<field name="view_mode">tree,form,kanban</field>
<field name="view_type">form</field>
<field name="context">{"search_default_filter_to_sell":1}</field>
<field name="view_id" ref="product_product_tree_view"/>
<field name="search_view_id" ref="product_search_form_view"/>
<field name="view_id" ref="product_product_tree_view"/>
<field name="search_view_id" ref="product_search_form_view"/>
<field name="help">You must define a Product for everything you buy or sell. Products can be raw materials, stockable products, consumables or services. The Product form contains detailed information about your products related to procurement logistics, sales price, product category, suppliers and so on.</field>
</record>
<record id="open_view_product_tree1" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="product_product_tree_view"/>
<field name="act_window_id" ref="product_normal_action_sell"/>
</record>
<record id="open_view_product_form1" model="ir.actions.act_window.view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="product_normal_form_view"/>
<field name="act_window_id" ref="product_normal_action_sell"/>
</record>
</record>
<menuitem id="base.menu_product" name="Products" parent="base.menu_base_partner" sequence="9"/>
<menuitem action="product.product_normal_action_sell" id="product.menu_products" parent="base.menu_product" sequence="1"/>

View File

@ -26,6 +26,7 @@ import tools
class stock_change_product_qty(osv.osv_memory):
_name = "stock.change.product.qty"
_inherit = ['mail.thread']
_description = "Change Product Quantity"
_columns = {
'product_id' : fields.many2one('product.product', 'Product'),
@ -98,9 +99,19 @@ class stock_change_product_qty(osv.osv_memory):
inventry_obj.action_confirm(cr, uid, [inventory_id], context=context)
inventry_obj.action_done(cr, uid, [inventory_id], context=context)
self.quantity_change_notification(cr, uid, [data.id], context)
return {}
def quantity_change_notification (self, cr, uid, ids, context=None):
prod_obj = self.pool.get('product.product')
location_obj = self.pool.get('stock.location')
for data in self.browse(cr, uid, ids, context=context):
for location in location_obj.browse(cr, uid, [data.location_id.id], context=context):
location_name = location.name
for prod in prod_obj.browse(cr, uid, [data.product_id.id], context=context):
message = _("<b>Quantity is changed</b> to <em>%s</em> for <em>%s</em> location.") % (data.new_quantity,location_name)
prod_obj.message_append_note(cr, uid, [prod.id], '', message)
stock_change_product_qty()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: