def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): context = context or {} product_uom_obj = self.pool.get('product.uom') partner_obj = self.pool.get('res.partner') product_obj = self.pool.get('product.product') warning = {} res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context) if not product: res['value'].update({'product_packaging': False}) return res #update of result obtained in super function res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context) res['value'].update(res_packing.get('value', {})) warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or '' product_obj = product_obj.browse(cr, uid, product, context=context) res['value']['delay'] = (product_obj.sale_delay or 0.0) res['value']['type'] = product_obj.procure_method #check if product is available, and if not: raise an error uom2 = False if uom: uom2 = product_uom_obj.browse(cr, uid, uom) if product_obj.uom_id.category_id.id != uom2.category_id.id: uom = False if not uom2: uom2 = product_obj.uom_id compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding) if (product_obj.type=='product') and int(compare_qty) == -1 \ and (product_obj.procure_method=='make_to_stock'): warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \ (qty, uom2 and uom2.name or product_obj.uom_id.name, max(0,product_obj.virtual_available), product_obj.uom_id.name, max(0,product_obj.qty_available), product_obj.uom_id.name) warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n" #update of warning messages if warning_msgs: warning = { 'title': _('Configuration Error!'), 'message' : warning_msgs } res.update({'warning': warning}) return res
def action_wait(self, cr, uid, ids, context=None): """ Check if price unit for each lines is lower than block price if True and user not in the group on company, raise an error """ if context is None: context = self.pool.get('res.users').context_get(cr, uid) user = self.pool.get('res.users').browse(cr, uid, uid) have_group = user.company_id.unblock_group_id.id in [z.id for z in user.groups_id] precision_digits = self.pool.get('decimal.precision').precision_get(cr, uid, 'Sale Price') for so in self.browse(cr, uid, ids): if not have_group and [x.id for x in so.order_line if float_compare(x.price_subtotal, x.block_price_subtotal, precision_digits=precision_digits) < 0]: raise osv.except_osv(_('Validation Error'), _('You cannot validate the sale order, some lines have a unit price lower than minimal price')) return super(sale_order, self).action_wait(cr, uid, ids, context)
def compare_amounts(self, cr, uid, currency, amount1, amount2): """Compare ``amount1`` and ``amount2`` after rounding them according to the given currency's precision.. An amount is considered lower/greater than another amount if their rounded value is different. This is not the same as having a non-zero difference! For example 1.432 and 1.431 are equal at 2 digits precision, so this method would return 0. However 0.006 and 0.002 are considered different (returns 1) because they respectively round to 0.01 and 0.0, even though 0.006-0.002 = 0.004 which would be considered zero at 2 digits precision. :param browse_record currency: currency for which we are rounding :param float amount1: first amount to compare :param float amount2: second amount to compare :return: (resp.) -1, 0 or 1, if ``amount1`` is (resp.) lower than, equal to, or greater than ``amount2``, according to ``currency``'s rounding. """ return float_compare(amount1, amount2, precision_rounding=currency.rounding)
def compare_amounts(self, cr, uid, currency, amount1, amount2): """Compare ``amount1`` and ``amount2`` after rounding them according to the given currency's precision.. An amount is considered lower/greater than another amount if their rounded value is different. This is not the same as having a non-zero difference! For example 1.432 and 1.431 are equal at 2 digits precision, so this method would return 0. However 0.006 and 0.002 are considered different (returns 1) because they respectively round to 0.01 and 0.0, even though 0.006-0.002 = 0.004 which would be considered zero at 2 digits precision. :param browse_record currency: currency for which we are rounding :param float amount1: first amount to compare :param float amount2: second amount to compare :return: (resp.) -1, 0 or 1, if ``amount1`` is (resp.) lower than, equal to, or greater than ``amount2``, according to ``currency``'s rounding. """ return float_compare(amount1, amount2, precision_rounding=currency.rounding)
def check_container_availability(self, cr, uid, ids, context=None): """ Check if there is enough products available in selected containers """ if context is None: context = {} container_obj = self.pool.get('stock.container') product_uom_obj = self.pool.get('product.uom') for line in self.browse(cr, uid, ids, context=context): if not line.container_id or not line.product_id: continue # Retrieve quantity available in container ctx = dict(context, product_id=line.product_id.id) container = container_obj.browse(cr, uid, line.container_id.id, context=ctx) qty = product_uom_obj._compute_qty(cr, uid, line.product_uom.id, line.product_uom_qty, line.product_id.uom_id.id) # Stock virtual is negative compare_qty = float_compare(container.stock_real + container.stock_virtual, qty, precision_rounding=line.product_id.uom_id.rounding) if container.stock_virtual > 0 and compare_qty == -1: raise osv.except_osv(_('Not enough quantity'), _('%s\nNot enough quantity in container %s') % (line.product_id.name, line.container_id.name)) return True
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): context = context or {} lang = lang or context.get('lang', False) if not partner_id: raise osv.except_osv( _('No Customer Defined !'), _('You have to select a customer in the sales form !\nPlease set one customer before choosing a product.' )) warning = {} product_uom_obj = self.pool.get('product.uom') partner_obj = self.pool.get('res.partner') product_obj = self.pool.get('product.product') context = {'lang': lang, 'partner_id': partner_id} if partner_id: lang = partner_obj.browse(cr, uid, partner_id).lang context_partner = {'lang': lang, 'partner_id': partner_id} if not product: return { 'value': { 'th_weight': 0, 'product_packaging': False, 'product_uos_qty': qty }, 'domain': { 'product_uom': [], 'product_uos': [] } } if not date_order: date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT) res = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context) result = res.get('value', {}) warning_msgs = res.get('warning') and res['warning']['message'] or '' product_obj = product_obj.browse(cr, uid, product, context=context) uom2 = False if uom: uom2 = product_uom_obj.browse(cr, uid, uom) if product_obj.uom_id.category_id.id != uom2.category_id.id: uom = False if uos: if product_obj.uos_id: uos2 = product_uom_obj.browse(cr, uid, uos) if product_obj.uos_id.category_id.id != uos2.category_id.id: uos = False else: uos = False if product_obj.description_sale: result['notes'] = product_obj.description_sale fpos = fiscal_position and self.pool.get( 'account.fiscal.position').browse(cr, uid, fiscal_position) or False if update_tax: #The quantity only have changed result['delay'] = (product_obj.sale_delay or 0.0) result['tax_id'] = self.pool.get( 'account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id) result.update({'type': product_obj.procure_method}) if not flag: result['name'] = self.pool.get('product.product').name_get( cr, uid, [product_obj.id], context=context_partner)[0][1] domain = {} if (not uom) and (not uos): result['product_uom'] = product_obj.uom_id.id if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff uos_category_id = product_obj.uos_id.category_id.id else: result['product_uos'] = False result['product_uos_qty'] = qty uos_category_id = False result['th_weight'] = qty * product_obj.weight domain = { 'product_uom': [('category_id', '=', product_obj.uom_id.category_id.id)], 'product_uos': [('category_id', '=', uos_category_id)] } elif uos and not uom: # only happens if uom is False result[ 'product_uom'] = product_obj.uom_id and product_obj.uom_id.id result['product_uom_qty'] = qty_uos / product_obj.uos_coeff result[ 'th_weight'] = result['product_uom_qty'] * product_obj.weight elif uom: # whether uos is set or not default_uom = product_obj.uom_id and product_obj.uom_id.id q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom) if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff else: result['product_uos'] = False result['product_uos_qty'] = qty result[ 'th_weight'] = q * product_obj.weight # Round the quantity up if not uom2: uom2 = product_obj.uom_id compare_qty = float_compare( product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding) if (product_obj.type=='product') and int(compare_qty) == -1 \ and (product_obj.procure_method=='make_to_stock'): warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \ (qty, uom2 and uom2.name or product_obj.uom_id.name, max(0,product_obj.virtual_available), product_obj.uom_id.name, max(0,product_obj.qty_available), product_obj.uom_id.name) warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n" # get the insulation flag and the r-value if product_obj.insulation: result['product_insulation'] = product_obj.insulation result['product_rvalue'] = product_obj.rvalue result['product_sprayfoam'] = product_obj.sprayfoam result['product_uos'] = product_obj.uos_id.id if not product_obj.sprayfoam: result['rvalue'] = product_obj.rvalue # get unit price if not pricelist: warn_msg = _( 'You have to select a pricelist or a customer in the sales form !\n' 'Please set one before choosing a product.') warning_msgs += _("No Pricelist ! : ") + warn_msg + "\n\n" else: price = self.pool.get('product.pricelist').price_get( cr, uid, [pricelist], product, qty or 1.0, partner_id, { 'uom': uom or result.get('product_uom'), 'date': date_order, })[pricelist] if price is False: warn_msg = _( "Couldn't find a pricelist line matching this product and quantity.\n" "You have to change either the product, the quantity or the pricelist." ) warning_msgs += _( "No valid pricelist line found ! :") + warn_msg + "\n\n" else: result.update({'price_unit': price}) if warning_msgs: warning = { 'title': _('Configuration Error !'), 'message': warning_msgs } return {'value': result, 'domain': domain, 'warning': warning}
def action_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): # Taken from original mrp addon """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed and stock move lines of final product will be also done/produced. @param production_id: the ID of mrp.production object @param production_qty: specify qty to produce @param production_mode: specify production mode (consume/consume&produce). @return: True """ stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) produced_qty = 0 for produced_product in production.move_created_ids2: 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 = {} # Calculate already consumed qtys for consumed in production.move_lines2: if consumed.scrapped: continue if not consumed_data.get(consumed.product_id.id, False): consumed_data[consumed.product_id.id] = 0 consumed_data[consumed.product_id.id] += consumed.product_qty # Find product qty to be consumed and consume it for scheduled in production.product_lines: # total qty of consumed product we need after this consumption total_consume = ((production_qty + produced_qty) * scheduled.product_qty / production.product_qty) # qty available for consume and produce qty_avail = scheduled.product_qty - consumed_data.get(scheduled.product_id.id, 0.0) if qty_avail <= 0.0: # there will be nothing to consume for this raw material continue raw_product = [move for move in production.move_lines if move.product_id.id == scheduled.product_id.id] if raw_product: # qtys we have to consume qty = total_consume - consumed_data.get(scheduled.product_id.id, 0.0) if float_compare(qty, qty_avail, precision_rounding=scheduled.product_id.uom_id.rounding) == 1: # if qtys we have to consume is more than qtys available to consume # => must consume the difference, move from warehouse _logger.info( 'action_produce: Manufacturing Order {prod.name}, Consuming {requested}, more than initial {prod.product_qty}' .format(prod=production, requested=production_qty)) if qty <= 0.0: # we already have more qtys consumed than we need continue consumed = 0 rounding = raw_product[0].product_uom.rounding # sort the list by quantity, to consume smaller quantities first and avoid splitting if possible raw_product.sort(key=attrgetter('product_qty')) # search for exact quantity for consume_line in raw_product: if tools.float_compare(consume_line.product_qty, qty, precision_rounding=rounding) == 0: # consume this line consume_line.action_consume(qty, consume_line.location_id.id, context=context) consumed = qty break index = 0 # consume the smallest quantity while we have not consumed enough while tools.float_compare(consumed, qty, precision_rounding=rounding) == -1 and index < len(raw_product): consume_line = raw_product[index] to_consume = min(consume_line.product_qty, qty - consumed) consume_line.action_consume(to_consume, consume_line.location_id.id, context=context) consumed += to_consume index += 1 if production_mode == 'consume_produce': # To produce remaining qty of final product #vals = {'state':'confirmed'} #final_product_todo = [x.id for x in production.move_created_ids] #stock_mov_obj.write(cr, uid, final_product_todo, vals) #stock_mov_obj.action_confirm(cr, uid, final_product_todo, context) produced_products = {} produced_products_qty = 0 if production.move_created_ids2: produced_products_qty = production.move_created_ids2[0].product_qty for produced_product in production.move_created_ids2: if produced_product.scrapped: continue if not produced_products.get(produced_product.product_id.id, False): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id.id] += produced_product.product_qty for produce_product in production.move_created_ids: produced_qty = produced_products.get(produce_product.product_id.id, 0) subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) rest_qty = (subproduct_factor * production.product_qty) - produced_qty if rest_qty < production_qty: _logger.info( 'action_produce: Manufacturing Order {prod.name}, Producing {requested}, more than initial {prod.product_qty}' .format(prod=production, requested=production_qty)) # Add and Reload production = self.add_prod_qty(cr, uid, production.id, production_qty, produced_products_qty, context) if rest_qty > 0: stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty), context=context) for raw_product in production.move_lines2: new_parent_ids = [] parent_move_ids = [x.id for x in raw_product.move_history_ids] for final_product in production.move_created_ids2: if final_product.id not in parent_move_ids: new_parent_ids.append(final_product.id) for new_parent_id in new_parent_ids: stock_mov_obj.write(cr, uid, [raw_product.id], {'move_history_ids': [(4, new_parent_id)]}) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr) return True
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): context = context or {} lang = lang or context.get('lang',False) if not partner_id: raise osv.except_osv(_('No Customer Defined !'), _('You have to select a customer in the sales form !\nPlease set one customer before choosing a product.')) warning = {} product_uom_obj = self.pool.get('product.uom') partner_obj = self.pool.get('res.partner') product_obj = self.pool.get('product.product') context = {'lang': lang, 'partner_id': partner_id} if partner_id: lang = partner_obj.browse(cr, uid, partner_id).lang context_partner = {'lang': lang, 'partner_id': partner_id} if not product: return {'value': {'th_weight': 0, 'product_packaging': False, 'product_uos_qty': qty}, 'domain': {'product_uom': [], 'product_uos': []}} if not date_order: date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT) res = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context) result = res.get('value', {}) warning_msgs = res.get('warning') and res['warning']['message'] or '' product_obj = product_obj.browse(cr, uid, product, context=context) uom2 = False if uom: uom2 = product_uom_obj.browse(cr, uid, uom) if product_obj.uom_id.category_id.id != uom2.category_id.id: uom = False if uos: if product_obj.uos_id: uos2 = product_uom_obj.browse(cr, uid, uos) if product_obj.uos_id.category_id.id != uos2.category_id.id: uos = False else: uos = False fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False if update_tax: #The quantity only have changed result['delay'] = (product_obj.sale_delay or 0.0) result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id) result.update({'type': product_obj.procure_method}) if not flag: result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1] domain = {} if (not uom) and (not uos): result['product_uom'] = product_obj.uom_id.id if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff uos_category_id = product_obj.uos_id.category_id.id else: result['product_uos'] = False result['product_uos_qty'] = qty uos_category_id = False result['th_weight'] = qty * product_obj.weight domain = {'product_uom': [('category_id', '=', product_obj.uom_id.category_id.id)], 'product_uos': [('category_id', '=', uos_category_id)]} elif uos and not uom: # only happens if uom is False result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id result['product_uom_qty'] = qty_uos / product_obj.uos_coeff result['th_weight'] = result['product_uom_qty'] * product_obj.weight elif uom: # whether uos is set or not default_uom = product_obj.uom_id and product_obj.uom_id.id q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom) if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff else: result['product_uos'] = False result['product_uos_qty'] = qty result['th_weight'] = q * product_obj.weight # Round the quantity up if not uom2: uom2 = product_obj.uom_id compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding) if (product_obj.type=='product') and int(compare_qty) == -1 \ and (product_obj.procure_method=='make_to_stock'): warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \ (qty, uom2 and uom2.name or product_obj.uom_id.name, max(0,product_obj.virtual_available), product_obj.uom_id.name, max(0,product_obj.qty_available), product_obj.uom_id.name) warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n" # get the insulation flag and the r-value if product_obj.insulation: result['product_insulation'] = product_obj.insulation result['product_rvalue'] = product_obj.rvalue result['product_sprayfoam'] = product_obj.sprayfoam result['product_uos'] = product_obj.uos_id.id if not product_obj.sprayfoam: result['rvalue'] = product_obj.rvalue # get unit price if not pricelist: warn_msg = _('You have to select a pricelist or a customer in the sales form !\n' 'Please set one before choosing a product.') warning_msgs += _("No Pricelist ! : ") + warn_msg +"\n\n" else: price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], product, qty or 1.0, partner_id, { 'uom': uom or result.get('product_uom'), 'date': date_order, })[pricelist] if price is False: warn_msg = _("Couldn't find a pricelist line matching this product and quantity.\n" "You have to change either the product, the quantity or the pricelist.") warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n" else: result.update({'price_unit': price}) if warning_msgs: warning = { 'title': _('Configuration Error !'), 'message' : warning_msgs } return {'value': result, 'domain': domain, 'warning': warning}
def action_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed and stock move lines of final product will be also done/produced. @param production_id: the ID of mrp.production object @param production_qty: specify qty to produce @param production_mode: specify production mode (consume/consume&produce). @return: True """ stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) produced_qty = 0 for produced_product in production.move_created_ids2: 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 = {} # Calculate already consumed qtys for consumed in production.move_lines2: if consumed.scrapped: continue if not consumed_data.get(consumed.product_id.id, False): consumed_data[consumed.product_id.id] = 0 consumed_data[consumed.product_id.id] += consumed.product_qty # Find product qty to be consumed and consume it for scheduled in production.product_lines: # total qty of consumed product we need after this consumption total_consume = ((production_qty + produced_qty) * scheduled.product_qty / production.product_qty) # qty available for consume and produce qty_avail = scheduled.product_qty - consumed_data.get(scheduled.product_id.id, 0.0) if qty_avail <= 0.0: # there will be nothing to consume for this raw material continue raw_product = [move for move in production.move_lines if move.product_id.id==scheduled.product_id.id] if raw_product: # qtys we have to consume qty = total_consume - consumed_data.get(scheduled.product_id.id, 0.0) if float_compare(qty, qty_avail, precision_rounding=scheduled.product_id.uom_id.rounding) == 1: # if qtys we have to consume is more than qtys available to consume 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 continue consumed = 0 rounding = raw_product[0].product_uom.rounding # sort the list by quantity, to consume smaller quantities first and avoid splitting if possible raw_product.sort(key=attrgetter('product_qty')) # search for exact quantity for consume_line in raw_product: if tools.float_compare(consume_line.product_qty, qty, precision_rounding=rounding) == 0: # consume this line consume_line.action_consume(qty, consume_line.location_id.id, context=context) consumed = qty break index = 0 # consume the smallest quantity while we have not consumed enough while tools.float_compare(consumed, qty, precision_rounding=rounding) == -1 and index < len(raw_product): consume_line = raw_product[index] to_consume = min(consume_line.product_qty, qty - consumed) consume_line.action_consume(to_consume, consume_line.location_id.id, context=context) consumed += to_consume index += 1 if production_mode == 'consume_produce': # To produce remaining qty of final product #vals = {'state':'confirmed'} #final_product_todo = [x.id for x in production.move_created_ids] #stock_mov_obj.write(cr, uid, final_product_todo, vals) #stock_mov_obj.action_confirm(cr, uid, final_product_todo, context) produced_products = {} for produced_product in production.move_created_ids2: if produced_product.scrapped: continue if not produced_products.get(produced_product.product_id.id, False): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id.id] += produced_product.product_qty for produce_product in production.move_created_ids: produced_qty = produced_products.get(produce_product.product_id.id, 0) subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) rest_qty = (subproduct_factor * production.product_qty) - produced_qty if rest_qty < production_qty: self.write(cr,uid,[production_id],{'product_qty': production_qty}) move_ids = stock_mov_obj.search(cr, uid,[('production_id','=', production.id)],limit=1,context=context) if move_ids: stock_mov_obj.write(cr,uid,move_ids,{'product_qty': production_qty}) move_ids = stock_mov_obj.search(cr, uid,[('move_dest_id','=', move_ids[0])],context=context) if move_ids: for move in stock_mov_obj.browse(cr,uid,move_ids,context=context): new_qty = (production_qty * move.product_qty) / rest_qty stock_mov_obj.write(cr,uid,[move.id],{'product_qty': new_qty}) move2_ids = stock_mov_obj.search(cr, uid,[('move_dest_id','=', move.id)],limit=1,context=context) if move2_ids: move2 = stock_mov_obj.browse(cr,uid,move2_ids[0],context=context) new_qty = (production_qty * move2.product_qty) / rest_qty stock_mov_obj.write(cr,uid,[move2.id],{'product_qty': new_qty}) return super(mrp_production, self).action_produce(cr, uid, production_id, production_qty, production_mode, context=context)
def action_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed and stock move lines of final product will be also done/produced. @param production_id: the ID of mrp.production object @param production_qty: specify qty to produce @param production_mode: specify production mode (consume/consume&produce). @return: True """ stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) produced_qty = 0 for produced_product in production.move_created_ids2: 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 = {} # Calculate already consumed qtys for consumed in production.move_lines2: if consumed.scrapped: continue if not consumed_data.get(consumed.product_id.id, False): consumed_data[consumed.product_id.id] = 0 consumed_data[consumed.product_id.id] += consumed.product_qty # Find product qty to be consumed and consume it for scheduled in production.product_lines: # total qty of consumed product we need after this consumption total_consume = ((production_qty + produced_qty) * scheduled.product_qty / production.product_qty) # qty available for consume and produce qty_avail = scheduled.product_qty - consumed_data.get( scheduled.product_id.id, 0.0) if qty_avail <= 0.0: # there will be nothing to consume for this raw material continue raw_product = [ move for move in production.move_lines if move.product_id.id == scheduled.product_id.id ] if raw_product: # qtys we have to consume qty = total_consume - consumed_data.get( scheduled.product_id.id, 0.0) if float_compare(qty, qty_avail, precision_rounding=scheduled.product_id. uom_id.rounding) == 1: # if qtys we have to consume is more than qtys available to consume 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 continue consumed = 0 rounding = raw_product[0].product_uom.rounding # sort the list by quantity, to consume smaller quantities first and avoid splitting if possible raw_product.sort(key=attrgetter('product_qty')) # search for exact quantity for consume_line in raw_product: if tools.float_compare( consume_line.product_qty, qty, precision_rounding=rounding) == 0: # consume this line consume_line.action_consume( qty, consume_line.location_id.id, context=context) consumed = qty break index = 0 # consume the smallest quantity while we have not consumed enough while tools.float_compare( consumed, qty, precision_rounding=rounding ) == -1 and index < len(raw_product): consume_line = raw_product[index] to_consume = min(consume_line.product_qty, qty - consumed) consume_line.action_consume( to_consume, consume_line.location_id.id, context=context) consumed += to_consume index += 1 if production_mode == 'consume_produce': # To produce remaining qty of final product #vals = {'state':'confirmed'} #final_product_todo = [x.id for x in production.move_created_ids] #stock_mov_obj.write(cr, uid, final_product_todo, vals) #stock_mov_obj.action_confirm(cr, uid, final_product_todo, context) produced_products = {} for produced_product in production.move_created_ids2: if produced_product.scrapped: continue if not produced_products.get(produced_product.product_id.id, False): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id. id] += produced_product.product_qty for produce_product in production.move_created_ids: produced_qty = produced_products.get( produce_product.product_id.id, 0) subproduct_factor = self._get_subproduct_factor( cr, uid, production.id, produce_product.id, context=context) rest_qty = (subproduct_factor * production.product_qty) - produced_qty if rest_qty < production_qty: self.write(cr, uid, [production_id], {'product_qty': production_qty}) move_ids = stock_mov_obj.search( cr, uid, [('production_id', '=', production.id)], limit=1, context=context) if move_ids: stock_mov_obj.write(cr, uid, move_ids, {'product_qty': production_qty}) move_ids = stock_mov_obj.search( cr, uid, [('move_dest_id', '=', move_ids[0])], context=context) if move_ids: for move in stock_mov_obj.browse(cr, uid, move_ids, context=context): new_qty = (production_qty * move.product_qty) / rest_qty stock_mov_obj.write(cr, uid, [move.id], {'product_qty': new_qty}) move2_ids = stock_mov_obj.search( cr, uid, [('move_dest_id', '=', move.id)], limit=1, context=context) if move2_ids: move2 = stock_mov_obj.browse( cr, uid, move2_ids[0], context=context) new_qty = (production_qty * move2.product_qty) / rest_qty stock_mov_obj.write( cr, uid, [move2.id], {'product_qty': new_qty}) return super(mrp_production, self).action_produce(cr, uid, production_id, production_qty, production_mode, context=context)
def action_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): # Taken from original mrp addon """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed and stock move lines of final product will be also done/produced. @param production_id: the ID of mrp.production object @param production_qty: specify qty to produce @param production_mode: specify production mode (consume/consume&produce). @return: True """ stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) produced_qty = 0 for produced_product in production.move_created_ids2: 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 = {} # Calculate already consumed qtys for consumed in production.move_lines2: if consumed.scrapped: continue if not consumed_data.get(consumed.product_id.id, False): consumed_data[consumed.product_id.id] = 0 consumed_data[consumed.product_id.id] += consumed.product_qty # Find product qty to be consumed and consume it for scheduled in production.product_lines: # total qty of consumed product we need after this consumption total_consume = ((production_qty + produced_qty) * scheduled.product_qty / production.product_qty) # qty available for consume and produce qty_avail = scheduled.product_qty - consumed_data.get( scheduled.product_id.id, 0.0) if qty_avail <= 0.0: # there will be nothing to consume for this raw material continue raw_product = [ move for move in production.move_lines if move.product_id.id == scheduled.product_id.id ] if raw_product: # qtys we have to consume qty = total_consume - consumed_data.get( scheduled.product_id.id, 0.0) if float_compare(qty, qty_avail, precision_rounding=scheduled.product_id. uom_id.rounding) == 1: # if qtys we have to consume is more than qtys available to consume # => must consume the difference, move from warehouse _logger.info( 'action_produce: Manufacturing Order {prod.name}, Consuming {requested}, more than initial {prod.product_qty}' .format(prod=production, requested=production_qty)) if qty <= 0.0: # we already have more qtys consumed than we need continue consumed = 0 rounding = raw_product[0].product_uom.rounding # sort the list by quantity, to consume smaller quantities first and avoid splitting if possible raw_product.sort(key=attrgetter('product_qty')) # search for exact quantity for consume_line in raw_product: if tools.float_compare( consume_line.product_qty, qty, precision_rounding=rounding) == 0: # consume this line consume_line.action_consume( qty, consume_line.location_id.id, context=context) consumed = qty break index = 0 # consume the smallest quantity while we have not consumed enough while tools.float_compare( consumed, qty, precision_rounding=rounding ) == -1 and index < len(raw_product): consume_line = raw_product[index] to_consume = min(consume_line.product_qty, qty - consumed) consume_line.action_consume( to_consume, consume_line.location_id.id, context=context) consumed += to_consume index += 1 if production_mode == 'consume_produce': # To produce remaining qty of final product #vals = {'state':'confirmed'} #final_product_todo = [x.id for x in production.move_created_ids] #stock_mov_obj.write(cr, uid, final_product_todo, vals) #stock_mov_obj.action_confirm(cr, uid, final_product_todo, context) produced_products = {} produced_products_qty = 0 if production.move_created_ids2: produced_products_qty = production.move_created_ids2[ 0].product_qty for produced_product in production.move_created_ids2: if produced_product.scrapped: continue if not produced_products.get(produced_product.product_id.id, False): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id. id] += produced_product.product_qty for produce_product in production.move_created_ids: produced_qty = produced_products.get( produce_product.product_id.id, 0) subproduct_factor = self._get_subproduct_factor( cr, uid, production.id, produce_product.id, context=context) rest_qty = (subproduct_factor * production.product_qty) - produced_qty if rest_qty < production_qty: _logger.info( 'action_produce: Manufacturing Order {prod.name}, Producing {requested}, more than initial {prod.product_qty}' .format(prod=production, requested=production_qty)) # Add and Reload production = self.add_prod_qty(cr, uid, production.id, production_qty, produced_products_qty, context) if rest_qty > 0: stock_mov_obj.action_consume( cr, uid, [produce_product.id], (subproduct_factor * production_qty), context=context) for raw_product in production.move_lines2: new_parent_ids = [] parent_move_ids = [x.id for x in raw_product.move_history_ids] for final_product in production.move_created_ids2: if final_product.id not in parent_move_ids: new_parent_ids.append(final_product.id) for new_parent_id in new_parent_ids: stock_mov_obj.write(cr, uid, [raw_product.id], {'move_history_ids': [(4, new_parent_id)]}) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr) return True