problem with production lots

Asked by Akshay Jain

I am facing following problem with production lots:
There are 2 Products: A, B
1 BOM defined as: to produce 1 A = 0.34 B needed
Next a purchase order is generated for purchasing 100 B. At the time of packing a production lot (P1) is assigned to product A and picking is done. At this time the stock shows 100 B as real stock.

Next a manufacturing order is made to produce 100 A with BOM as stated above. After confirming production order Consumed products shows 34 B is needed and status is "Waiting". Next I edit this stock move and set production lot as P1 (same as that of purchase order move).

Now when i click "Force Reservation" then i get error that production lot for this product is not set whereas i have already set the production lot. Please guide me what i m doing wrong here.

Question information

Language:
English Edit question
Status:
Answered
For:
Odoo Addons (MOVED TO GITHUB) Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
gpa(OpenERP) (gpa-openerp) said :
#1

Hello,

Can you provide me error trace back which you did get in server terminal?

Thanks.

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#2

Server log file does not show any error and I am using openerp on windows so server terminal goes off after server is started.

Revision history for this message
gpa(OpenERP) (gpa-openerp) said :
#3

Hello Akshay Jain,

Would you please check this link?

https://answers.launchpad.net/openobject-server/+question/104621

Thanks

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#4

Upon further investigation i found this:

Each production order generates an internal packing with a stock move of Stock -> Stock and another stock move as Stock -> Production. Now production order shows the second move of Stock -> Production in Consumed Products tab. Obviously user will set Production Lot in Consumed Products tab and THIS PRODUCTION LOT SHOULD GET AUTOMATICALLY SET IN INTERNAL PACKING MOVE. This is the actual problem. The production lot set in Consumed Products tab should automatically be set in Internal Packing move and IT IS NOT HAPPENING RIGHT NOW.

Please tell me how to fix it.

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#5

Upon further investigation i found this:

Each production order generates an internal packing with a stock move of Stock -> Stock and another stock move as Stock -> Production. Now production order shows the second move of Stock -> Production in Consumed Products tab. Obviously user will set Production Lot in Consumed Products tab and THIS PRODUCTION LOT SHOULD GET AUTOMATICALLY SET IN INTERNAL PACKING MOVE. This is the actual problem. The production lot set in Consumed Products tab should automatically be set in Internal Packing move and IT IS NOT HAPPENING RIGHT NOW.

Please tell me how to fix it.

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#6

Upon further investigation i found this:

Each production order generates an internal packing with a stock move of Stock -> Stock and another stock move as Stock -> Production. Now production order shows the second move of Stock -> Production in Consumed Products tab. Obviously user will set Production Lot in Consumed Products tab and THIS PRODUCTION LOT SHOULD GET AUTOMATICALLY SET IN INTERNAL PACKING MOVE. This is the actual problem. The production lot set in Consumed Products tab should automatically be set in Internal Packing move and IT IS NOT HAPPENING RIGHT NOW.

Please tell me how to fix it.

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#7

ohh sorry for so many posts of same message...some trouble with my browser...

Revision history for this message
gpa(OpenERP) (gpa-openerp) said :
#8

Hello Akshay Jain,

When you confirmed any production order than Internal Move will be generated. Now you will change production order line and assign Production Lot and save those production order than it will not affect to Internal Move.So you need to manually select production Lot in internal move similar like production order.In manual Selection in production lot it will select only the related product lot only.

So I do not know How did you get error ? I think you misunderstand regarding warning message.

Can you please explain me regarding this issue,if i am wrong?

If you want to fill up automatically, it needs customization.

Thank you

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#9

YES i want it to fill up automatically. I believe this should be implemented in future versions of openerp becoz it makes more sense. Why force it on users to set same production lot twice?????

When user says to use production lot, lets say xxx, in production screen then OBVIOUSLY he would want the internal move to use same production lot. Its common sense. example: user says use product A of lot xxx to make product B. then it is obvious that the user wants internal move for lot xxx. So internal move lot should automatically get the production lot of the production order.

An even better thing to do is to allow user to set production lots before confirming production order because it is sensible to allow user to set lots in planning phase itself. Once order is confirmed the moves should get generated with lots set automatically.

What do you think?

Revision history for this message
Vinay Rana (OpenERP) (vra-openerp) said :
#10

Hello Akshay Jain,

You can post a bug with 'Wishlist' state in https://bugs.launchpad.net/openobject-addons/+bugs.

Thanks.

Revision history for this message
Akshay Jain (akshay-jain-7983) said :
#11

Hello vra,

I coded this myself but i am facing one problem. What i did was this:
-------
class mrp_production(osv.osv):
    _name = 'mrp.production'
    _inherit = 'mrp.production'
    _description = 'Production'

    def action_confirm(self, cr, uid, ids):
        picking_id=False
        proc_ids = []
        for production in self.browse(cr, uid, ids):
            if not production.product_lines:
                self.action_compute(cr, uid, [production.id])
                production = self.browse(cr, uid, [production.id])[0]
            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 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
            picking_id = self.pool.get('stock.picking').create(cr, uid, {
                'origin': (production.origin or '').split(':')[0] +':'+production.name,
                'type': pick_type,
                'move_type': 'one',
                'state': 'auto',
                'address_id': address_id,
                'auto_picking': self._get_auto_picking(cr, uid, production),
            })

            source = production.product_id.product_tmpl_id.property_stock_production.id
            data = {
                'name':'PROD:'+production.name,
                'date_planned': production.date_planned,
                'product_id': production.product_id.id,
                'product_qty': production.product_qty,
                'product_uom': production.product_uom.id,
                'product_uos_qty': production.product_uos and production.product_uos_qty or False,
                'product_uos': production.product_uos and production.product_uos.id or False,
                'location_id': source,
                'location_dest_id': production.location_dest_id.id,
                'move_dest_id': production.move_prod_id.id,
                'state': 'waiting'
            }
            res_final_id = self.pool.get('stock.move').create(cr, uid, data)

            self.write(cr, uid, [production.id], {'move_created_ids': [(6, 0, [res_final_id])]})
            moves = []
            for line in production.product_lines:
                move_id=False
                newdate = production.date_planned
                if line.product_id.type in ('product', 'consu'):
                    res_dest_id = self.pool.get('stock.move').create(cr, uid, {
                        'name':'PROD:'+production.name,
                        'date_planned': production.date_planned,
                        'product_id': line.product_id.id,
                        'product_qty': line.product_qty,
                        'product_uom': line.product_uom.id,
                        'product_uos_qty': line.product_uos and line.product_uos_qty or False,
                        'product_uos': line.product_uos and line.product_uos.id or False,
                        'location_id': routing_loc or line.location_id.id or production.location_src_id.id,
                        'location_dest_id': source,
                        'move_dest_id': res_final_id,
                        'state': 'waiting',
                        'prodlot_id': line.prodlot_id.id or False,
                    })
                    moves.append(res_dest_id)
                    move_id = self.pool.get('stock.move').create(cr, uid, {
                        'name':'PROD:'+production.name,
                        'picking_id':picking_id,
                        'product_id': line.product_id.id,
                        'product_qty': line.product_qty,
                        'product_uom': line.product_uom.id,
                        'product_uos_qty': line.product_uos and line.product_uos_qty or False,
                        'product_uos': line.product_uos and line.product_uos.id or False,
                        'date_planned': newdate,
                        'move_dest_id': res_dest_id,
                        'location_id': line.location_id.id or production.location_src_id.id,
                        'location_dest_id': routing_loc or production.location_src_id.id,
                        'state': 'waiting',
                        'prodlot_id': line.prodlot_id.id or False,
                    })
                proc_id = self.pool.get('mrp.procurement').create(cr, uid, {
                    'name': (production.origin or '').split(':')[0] + ':' + production.name,
                    'origin': (production.origin or '').split(':')[0] + ':' + production.name,
                    'date_planned': newdate,
                    'product_id': line.product_id.id,
                    'product_qty': line.product_qty,
                    'product_uom': line.product_uom.id,
                    'product_uos_qty': line.product_uos and line.product_qty or False,
                    'product_uos': line.product_uos and line.product_uos.id or False,
                    'location_id': production.location_src_id.id,
                    'procure_method': line.product_id.procure_method,
                    'move_id': move_id,
                })
                wf_service = netsvc.LocalService("workflow")
                wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)
                proc_ids.append(proc_id)
            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
            self.write(cr, uid, [production.id], {'picking_id':picking_id, 'move_lines': [(6,0,moves)], 'state':'confirmed'})
        return picking_id

mrp_production()

class mrp_production_product_line(osv.osv):
    _name = 'mrp.production.product.line'
    _inherit = 'mrp.production.product.line'
    _description = 'Production scheduled products'

    def _check_tracking(self, cr, uid, ids):
        for line in self.browse(cr, uid, ids):
            if not line.prodlot_id and (line.production_id.state == 'confirmed') and line.product_id.track_production:
                return False
        return True

    def _check_product_lot(self, cr, uid, ids):
        for line in self.browse(cr, uid, ids):
            if line.prodlot_id and (line.prodlot_id.product_id.id != line.product_id.id):
                return False
        return True

    _columns = {
 'prodlot_id': fields.many2one('stock.production.lot', 'Production Lot', help="Production lot is used to put a serial number on the production"),
    'location_id': fields.many2one('stock.location', 'Source Location'),
    }

    _constraints = [
        (_check_tracking,
            'You must assign a production lot for this product',
            ['prodlot_id']),
        (_check_product_lot,
            'You try to assign a lot which is not from the same product',
            ['prodlot_id'])]

    def onchange_lot_id(self, cr, uid, ids, prodlot_id=False, product_qty=False, loc_id=False, context=None):
        if not prodlot_id or not loc_id:
            return {}
        ctx = context and context.copy() or {}
        ctx['location_id'] = loc_id
        prodlot = self.pool.get('stock.production.lot').browse(cr, uid, prodlot_id, ctx)
        location = self.pool.get('stock.location').browse(cr, uid, loc_id)
        warning = {}
        if (location.usage == 'internal') and (product_qty > (prodlot.stock_available or 0.0)):
            warning = {
                'title': 'Bad Lot Assignment !',
                'message': 'You are moving %.2f products but only %.2f available in this lot.' % (product_qty, prodlot.stock_available or 0.0)
            }
        return {'warning': warning}
mrp_production_product_line()

-----------
Now users are able to set the production lot and source location right from Scheduled Products tab and that gets set automatically into Consumed Goods and Internal Packing. The problem I am facing is that the constraints in above code does not seem to work. Any help on this would be appreciable.

Revision history for this message
Vinay Rana (OpenERP) (vra-openerp) said :
#12

Hello Akshay Jain,

You can post a separate bug with suggested patch.

Thanks.

Revision history for this message
Claire (cjin) said :
#13

any solution for this situation yet? Thanks

Can you help with this problem?

Provide an answer of your own, or ask Akshay Jain for more information if necessary.

To post a message you must log in.