def get_cost_amount(self, cr, uid, product, product_qty, context=None): price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price') if product.is_kit: bom_obj = self.pool['mrp.bom'] amount = 0.0 for bom in product.bom_lines: bom_product_ids = bom_obj.search(cr, uid, [('bom_id', '=', bom.id)], context=context) bom_products = bom_obj.browse(cr, uid, bom_product_ids, context) for bom_product in bom_products: if not bom_product.product_id.product_tmpl_id.type == 'service': amount += bom_product.product_id.standard_price * bom_product.product_qty return rounding(amount * product_qty, 10 ** - price_unit_precision) else: return rounding(product.standard_price * product_qty, 10 ** - price_unit_precision)
def get_cost_amount(self, cr, uid, product, product_qty, context=None): price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price') if product.is_kit: bom_obj = self.pool['mrp.bom'] amount = 0.0 for bom in product.bom_lines: bom_product_ids = bom_obj.search(cr, uid, [('bom_id', '=', bom.id)], context=context) bom_products = bom_obj.browse(cr, uid, bom_product_ids) for bom_product in bom_products: if not bom_product.product_id.product_tmpl_id.type == 'service': amount += bom_product.product_id.standard_price * bom_product.product_qty return rounding(amount * product_qty, 10 ** - price_unit_precision) else: return rounding(product.standard_price * product_qty, 10 ** - price_unit_precision)
def get_cost_amount(self, cr, uid, product, product_qty, context=None): price_unit_precision = self.pool["decimal.precision"].precision_get(cr, uid, "Sale Price") if product.is_kit: bom_obj = self.pool["mrp.bom"] amount = 0.0 for bom in product.bom_lines: bom_product_ids = bom_obj.search(cr, uid, [("bom_id", "=", bom.id)]) bom_products = bom_obj.browse(cr, uid, bom_product_ids) for bom_product in bom_products: if not bom_product.product_id.product_tmpl_id.type == "service": amount += bom_product.product_id.standard_price * bom_product.product_qty return rounding(amount * product_qty, 10 ** -price_unit_precision) else: return rounding(product.standard_price * product_qty, 10 ** -price_unit_precision)
def split_line(self, cr, uid, ids, context=None): ''' Create a new order line and change the quantity of the old line ''' line_obj = self.pool.get('sale.order.line') if not context: context = {} if isinstance(ids, (int, long)): ids = [ids] context['keepDateAndDistrib'] = True for split in self.browse(cr, uid, ids, context=context): # Check if the sum of new line and old line qty is equal to the original qty if split.new_line_qty > split.original_qty: raise osv.except_osv(_('Error'), _('You cannot have a new quantity greater than the original quantity !')) elif split.new_line_qty <= 0.00: raise osv.except_osv(_('Error'), _('The new quantity must be positive !')) elif split.new_line_qty == split.original_qty: raise osv.except_osv(_('Error'), _('The new quantity must be different than the original quantity !')) elif split.new_line_qty != rounding(split.new_line_qty, split.sale_line_id.product_uom.rounding): raise osv.except_osv(_('Error'), _('The new quantity must be a multiple of %s !') % split.sale_line_id.product_uom.rounding) else: # Change the qty of the old line line_obj.write(cr, uid, [split.sale_line_id.id], {'product_uom_qty': split.original_qty - split.new_line_qty}, context=context) # copy data so_copy_data = {'is_line_split': True, # UTP-972: Indicate that the line is split 'product_uom_qty': split.new_line_qty} # following new sequencing policy, we check if resequencing occur (behavior 1). # if not (behavior 2), the split line keeps the same line number as original line if not line_obj.allow_resequencing(cr, uid, [split.sale_line_id.id], context=context): # set default value for line_number as the same as original line so_copy_data.update({'line_number': split.sale_line_id.line_number}) # Create the new line new_line_id = line_obj.copy(cr, uid, split.sale_line_id.id, so_copy_data, context=context) self.infolog(cr, uid, "The FO/IR line id:%s (%s) has been split" % ( split.sale_line_id.id, split.sale_line_id.line_number, )) return {'type': 'ir.actions.act_window_close'}
def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None): def _create_parent_category_list(id, lst): if not id: return [] parent = product_category_tree.get(id) if parent: lst.append(parent) return _create_parent_category_list(parent, lst) else: return lst # _create_parent_category_list if context is None: context = {} date = time.strftime('%Y-%m-%d') if 'date' in context: date = context['date'] currency_obj = self.pool.get('res.currency') product_obj = self.pool.get('product.product') product_category_obj = self.pool.get('product.category') product_uom_obj = self.pool.get('product.uom') supplierinfo_obj = self.pool.get('product.supplierinfo') price_type_obj = self.pool.get('product.price.type') product_pricelist_version_obj = self.pool.get('product.pricelist.version') # product.pricelist.version: if pricelist_ids: pricelist_version_ids = pricelist_ids else: # all pricelists: pricelist_version_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context) pricelist_version_ids = list(set(pricelist_version_ids)) plversions_search_args = [ ('pricelist_id', 'in', pricelist_version_ids), '|', ('date_start', '=', False), ('date_start', '<=', date), '|', ('date_end', '=', False), ('date_end', '>=', date), ] plversion_ids = product_pricelist_version_obj.search(cr, uid, plversions_search_args) if len(pricelist_version_ids) != len(plversion_ids): msg = "At least one pricelist has no active version !\nPlease create or activate one." raise osv.except_osv(_('Warning !'), _(msg)) # product.product: product_ids = [i[0] for i in products_by_qty_by_partner] #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])]) products = product_obj.browse(cr, uid, product_ids, context=context) products_dict = dict([(item.id, item) for item in products]) # product.category: product_category_ids = product_category_obj.search(cr, uid, []) product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id']) product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']]) results = {} for product_id, qty, partner in products_by_qty_by_partner: for pricelist_id in pricelist_version_ids: price = False tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False categ_ids = _create_parent_category_list(categ_id, [categ_id]) if categ_ids: categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))' else: categ_where = '(categ_id IS NULL)' cr.execute( 'SELECT i.*, pl.currency_id ' 'FROM product_pricelist_item AS i, ' 'product_pricelist_version AS v, product_pricelist AS pl ' 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' 'AND (product_id IS NULL OR product_id = %s) ' 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' 'AND price_version_id = %s ' 'AND (min_quantity IS NULL OR min_quantity <= %s) ' 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' 'ORDER BY sequence', (tmpl_id, product_id, plversion_ids[0], qty)) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: if res: if res['base'] == -1: if not res['base_pricelist_id']: price = 0.0 else: price_tmp = self.price_get(cr, uid, [res['base_pricelist_id']], product_id, qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: where = [] if partner: where = [('name', '=', partner) ] sinfo = supplierinfo_obj.search(cr, uid, [('product_id', '=', tmpl_id)] + where) price = 0.0 if sinfo: qty_in_product_uom = qty product_default_uom = product_obj.read(cr, uid, [tmpl_id], ['uom_id'])[0]['uom_id'][0] seller_uom = supplierinfo_obj.read(cr, uid, sinfo, ['product_uom'])[0]['product_uom'][0] if seller_uom and product_default_uom and product_default_uom != seller_uom: uom_price_already_computed = True qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom) cr.execute('SELECT * ' \ 'FROM pricelist_partnerinfo ' \ 'WHERE suppinfo_id IN %s' \ 'AND min_quantity <= %s ' \ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo),qty_in_product_uom,)) res2 = cr.dictfetchone() if res2: price = res2['price'] #This is added by product_pricelist_fixed_price elif res['base'] == -3: price = res['fixed_price'] #End else: price_type = price_type_obj.browse(cr, uid, int(res['base'])) price = currency_obj.compute(cr, uid, price_type.currency_id.id, res['currency_id'], product_obj.price_get(cr, uid, [product_id], price_type.field,context=context)[product_id], round=False, context=context) if price: price_limit = price price = price * (1.0+(res['price_discount'] or 0.0)) price = rounding(price, res['price_round']) price += (res['price_surcharge'] or 0.0) if res['price_min_margin']: price = max(price, price_limit+res['price_min_margin']) if res['price_max_margin']: price = min(price, price_limit+res['price_max_margin']) break else: # False means no valid line found ! But we may not raise an # exception here because it breaks the search price = False if price: if 'uom' in context and not uom_price_already_computed: product = products_dict[product_id] uom = product.uos_id or product.uom_id price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, price, context['uom']) if results.get(product_id): results[product_id][pricelist_id] = price else: results[product_id] = {pricelist_id: price} return results
def split_line(self, cr, uid, ids, context=None): ''' Create a new order line and change the quantity of the old line ''' # objects wf_service = netsvc.LocalService("workflow") po_line_obj = self.pool.get('purchase.order.line') so_line_obj = self.pool.get('sale.order.line') so_obj = self.pool.get('sale.order') move_obj = self.pool.get('stock.move') proc_obj = self.pool.get('procurement.order') # Some verifications if context is None: context = {} if isinstance(ids, (int, long)): ids = [ids] context.update({'split_line': True}) context.update({'keepDateAndDistrib': True}) for split in self.browse(cr, uid, ids, context=context): # Check if the sum of new line and old line qty is equal to the original qty if split.new_line_qty > split.original_qty: raise osv.except_osv(_('Error'), _('You cannot have a new quantity greater than the original quantity !')) elif split.new_line_qty <= 0.00: raise osv.except_osv(_('Error'), _('The new quantity must be positive !')) elif split.new_line_qty == split.original_qty: raise osv.except_osv(_('Error'), _('The new quantity must be different than the original quantity !')) elif split.new_line_qty != rounding(split.new_line_qty, split.purchase_line_id.product_uom.rounding): raise osv.except_osv(_('Error'), _('The new quantity must be a multiple of %s !') % split.purchase_line_id.product_uom.rounding) else: self.infolog(cr, uid, "The PO line id:%s (line number: %s) has been split" % ( split.purchase_line_id.id, split.purchase_line_id.line_number, )) # Change the qty of the old line po_line_obj.write(cr, uid, [split.purchase_line_id.id], {'product_qty': split.original_qty - split.new_line_qty, 'price_unit': split.purchase_line_id.price_unit,}, context=context) # Change the qty on the linked procurement order #if split.purchase_line_id.procurement_id: # proc_obj.write(cr, uid, [split.purchase_line_id.procurement_id.id], {'product_qty': split.original_qty - split.new_line_qty}) # we treat two different cases # 1) the check box impact corresponding Fo is checked # we create a Fo line by copying related Fo line. we then execute procurement creation function, and process the procurement # the merge into the actual Po is forced # if Internal Request, we do not update corresponding Internal Request link_wiz = split.corresponding_so_line_id_split_po_line_wizard external_ir = link_wiz and link_wiz.order_id and (not link_wiz.order_id.procurement_request or link_wiz.order_id.location_requestor_id.usage == 'customer') if split.corresponding_so_line_id_split_po_line_wizard and split.impact_so_split_po_line_wizard and external_ir: # copy the original sale order line, reset po_cft to 'po' (we don't want a new tender if any) so_copy_data = {'line_number': split.corresponding_so_line_id_split_po_line_wizard.line_number, # the Fo is not draft anyway, following sequencing policy, split Fo line maintains original one 'po_cft': 'po', 'product_uom_qty': split.new_line_qty, 'product_uos_qty': split.new_line_qty, 'so_back_update_dest_po_id_sale_order_line': split.purchase_line_id.order_id.id, 'so_back_update_dest_pol_id_sale_order_line': split.purchase_line_id.id, } new_so_line_id = so_line_obj.copy(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, so_copy_data, context=dict(context, keepDateAndDistrib=True)) so_line_obj.write(cr, uid, new_so_line_id, { 'supplier': split.corresponding_so_line_id_split_po_line_wizard.supplier.id, 'type': 'make_to_order', 'is_line_split': True, }, context=context) # change the initial qty on the initial FO line so_line_obj.write(cr, uid, split.corresponding_so_line_id_split_po_line_wizard.id, { 'product_uom_qty': split.original_qty - split.new_line_qty, 'product_uos_qty': split.original_qty - split.new_line_qty, }, context=dict(context, keepDateAndDistrib=True)) # call the new procurement creation method so_obj.action_ship_proc_create(cr, uid, [split.corresponding_so_id_split_po_line_wizard.id], context=context) # run the procurement, the make_po function detects the link to original po # and force merge the line to this po (even if it is not draft anymore) # run the procurement, the make_po function detects the link to original po # and force merge the line to this po (even if it is not draft anymore) new_data_so = so_line_obj.read(cr, uid, [new_so_line_id], ['procurement_id', 'line_number', 'sync_order_line_db_id'], context=context) new_proc_id = new_data_so[0]['procurement_id'][0] if external_ir and split.purchase_line_id and split.purchase_line_id.move_dest_id: move = move_obj.browse(cr, uid, split.purchase_line_id.move_dest_id.id, context=context) proc_move_id = proc_obj.read(cr, uid, new_proc_id, ['move_id'], context=context)['move_id'][0] new_move_id = move.id if move.product_qty > split.new_line_qty: new_move_id = move_obj.copy(cr, uid, move.id, {'product_qty': split.new_line_qty, 'product_uos_qty': split.new_line_qty, 'line_number': new_data_so[0]['line_number'], 'sale_line_id': new_so_line_id}, context=context) move_obj.action_confirm(cr, uid, [new_move_id], context=context) move_obj.write(cr, uid, [move.id], {'product_qty': move.product_qty - split.new_line_qty, 'product_uos_qty': move.product_qty - split.new_line_qty}, context=context) else: # No update of OUT when IN is received to avoid more qty than expected move_obj.write(cr, uid, [move.id], {'processed_stock_move': True}, context=context) move_obj.write(cr, uid, proc_move_id, {'state': 'draft'}, context=context) proc_obj.write(cr, uid, [new_proc_id], {'close_move': False, 'move_id': new_move_id}, context=context) move_obj.unlink(cr, uid, proc_move_id, context=context) if link_wiz.order_id.partner_id.partner_type != 'external': self.pool.get('sync.sale.order.line.split').create(cr, uid, { 'partner_id': link_wiz.order_id.partner_id.id, 'old_sync_order_line_db_id': link_wiz.sync_order_line_db_id, 'new_sync_order_line_db_id': new_data_so[0]['sync_order_line_db_id'], 'new_line_qty': split.new_line_qty, 'old_line_qty': split.original_qty, }, context=context) wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_check', cr) new_po_ids = po_line_obj.search(cr, uid, [('procurement_id', '=', new_proc_id)], context=context) if context.get('split_sync_order_line_db_id'): po_line_obj.write(cr, uid, new_po_ids, {'sync_order_line_db_id': context.get('split_sync_order_line_db_id')}, context=context) # if original po line is confirmed, we action_confirm new line if split.purchase_line_id.state == 'confirmed': # the correct line number according to new line number policy is set in po_line_values_hook of order_line_number/order_line_number.py/procurement_order po_line_obj.action_confirm(cr, uid, new_po_ids, context=context) if context.get('from_simu_screen'): return new_po_ids[0] else: # 2) the check box impact corresponding Fo is not check or does not apply (po from scratch or from replenishment), # a new line is simply created # Create the new line move_dest_id = split.purchase_line_id.move_dest_id and split.purchase_line_id.move_dest_id.id or False sale_line_id = split.corresponding_so_line_id_split_po_line_wizard and split.corresponding_so_line_id_split_po_line_wizard.id or False proc_id = split.corresponding_so_line_id_split_po_line_wizard.procurement_id and split.corresponding_so_line_id_split_po_line_wizard.procurement_id.id or False if split.purchase_line_id.procurement_id and move_dest_id and not link_wiz.order_id.procurement_request: new_dest_id = move_obj.copy(cr, uid, move_dest_id, {'product_qty': split.new_line_qty}, context=context) move_obj.action_confirm(cr, uid, [new_dest_id]) move_obj.write(cr, uid, [move_dest_id], {'product_qty': split.original_qty - split.new_line_qty}, context=context) move_dest_id = new_dest_id new_proc_id = proc_obj.copy(cr, uid, split.purchase_line_id.procurement_id.id, { 'product_qty': split.new_line_qty, 'purchase_id': split.purchase_line_id.order_id.id, 'move_id': new_dest_id, 'from_splitted_po_line': True, }, context=context) proc_obj.write(cr, uid, [split.purchase_line_id.procurement_id.id], { 'product_qty': split.original_qty - split.new_line_qty, }, context=context) wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_confirm', cr) wf_service.trg_validate(uid, 'procurement.order', new_proc_id, 'button_check', cr) proc_id = new_proc_id po_copy_data = {'is_line_split': True, # UTP-972: Indicate only that the line is a split one 'change_price_manually': split.purchase_line_id.change_price_manually, 'price_unit': split.purchase_line_id.price_unit, 'move_dest_id': move_dest_id, 'sale_line_id': sale_line_id, 'procurement_id': proc_id, 'product_qty': split.new_line_qty} # following new sequencing policy, we check if resequencing occur (behavior 1). # if not (behavior 2), the split line keeps the same line number as original line if not po_line_obj.allow_resequencing(cr, uid, [split.purchase_line_id.id], context=context): # set default value for line_number as the same as original line po_copy_data.update({'line_number': split.purchase_line_id.line_number}) new_line_ids = [] if split.purchase_line_id.procurement_id and move_dest_id and not link_wiz.order_id.procurement_request: new_line_ids = po_line_obj.search(cr, uid, [('procurement_id', '=', new_proc_id)], context=context) po_line_obj.write(cr, uid, new_line_ids, po_copy_data, context=context) else: # copy original line new_line_id = po_line_obj.copy(cr, uid, split.purchase_line_id.id, po_copy_data, context=context) new_line_ids.append(new_line_id) # if original po line is confirmed, we action_confirm new line if split.purchase_line_id.state == 'confirmed': po_line_obj.action_confirm(cr, uid, new_line_ids, context=context) if context.get('from_simu_screen'): return new_line_ids[0] if context.get('from_simu_screen'): return False return {'type': 'ir.actions.act_window_close'}
def update_or_create_line(self, cr, uid, values, context=None): ''' values = { 'name': expense_line.name, 'product': expense_line.product_id, 'product_qty': expense_line.unit_quantity, 'product_uom': expense_line.uom_id, # Optional, is not required. 'account_id': expense_line.analytic_account.id, 'unit_amount': values.get('unit_amount', False), # Optional, is not required 'date': expense_line.date_value + ' 00:00:00', 'ref': hr_expense.name, 'origin_document': expense_line } ''' journals = { 'hr.expense.line': {'journal': 'expense_journal_id', 'name': _('Expense Journal')}, 'stock.move': {'journal': 'delivery_note_journal_id', 'name': _('Delivery Note Journal')} } if values.get('account_id', False): user = self.pool['res.users'].browse(cr, uid, uid, context) journal = getattr(user.company_id, journals[values['origin_document']._name]['journal']) if journal: journal_id = journal.id else: raise orm.except_orm('Error', _('{journal} is not defined for this company').format(journal=journals[values['origin_document']._name]['name'])) product_qty = values.get('product_qty', 1) price_unit_precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Sale Price') if values.get('unit_amount', False): amount = rounding(values['unit_amount'] * product_qty, 10 ** - price_unit_precision) elif values.get('product', False): amount = self.get_cost_amount(cr, uid, values['product'], product_qty, context) else: return False if values.get('product', False): general_account_id = values['product'].product_tmpl_id.property_account_expense.id if not general_account_id: general_account_id = values['product'].categ_id.property_account_expense_categ.id if not general_account_id: raise orm.except_orm(_('Error!'), _('''There is no expense account defined for this product: "{0}" (id:{1})''').format(values['product'].name, values['product'].id,)) else: general_account_id = False line_date = datetime.datetime.strptime(values['date'], DEFAULT_SERVER_DATETIME_FORMAT) line_date = datetime.date(year=line_date.year, month=line_date.month, day=line_date.day) analytic_line_ids = self.search(cr, uid, [('origin_document', '=', '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id))], context=context) if analytic_line_ids: return self.write(cr, uid, analytic_line_ids, { 'amount': -amount, 'user_id': uid, 'name': values['name'], 'unit_amount': product_qty, # What a strange idea to call product_qty unit_amount!!! 'date': line_date, 'company_id': user.company_id.id, 'account_id': values['account_id'], 'general_account_id': general_account_id, 'product_id': values['product'].id, 'product_uom_id': values.get('product_uom', values['product'].uom_id.id), 'journal_id': journal_id, 'amount_currency': 0.0, 'ref': values.get('ref', False), 'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id) }, context) else: return self.create(cr, uid, { 'amount': -amount, 'user_id': uid, 'name': values['name'], 'unit_amount': product_qty, 'date': line_date, 'company_id': user.company_id.id, 'account_id': values['account_id'], 'general_account_id': general_account_id, 'product_id': values['product'].id, 'product_uom_id': values.get('product_uom', values['product'].uom_id.id), 'journal_id': journal_id, 'amount_currency': 0.0, 'ref': values.get('ref', False), 'origin_document': '{model}, {document_id}'.format(model=values['origin_document']._name, document_id=values['origin_document'].id) }, context) else: return False
def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None): """multi products 'price_get'. @param pricelist_ids: @param products_by_qty: @param partner: @param context: { 'date': Date of the pricelist (%Y-%m-%d),} @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value """ def _create_parent_category_list(id, lst): if not id: return [] parent = product_category_tree.get(id) if parent: lst.append(parent) return _create_parent_category_list(parent, lst) else: return lst # _create_parent_category_list if context is None: context = {} date = time.strftime('%Y-%m-%d') if 'date' in context: date = context['date'] currency_obj = self.pool.get('res.currency') product_obj = self.pool.get('product.product') product_category_obj = self.pool.get('product.category') product_uom_obj = self.pool.get('product.uom') supplierinfo_obj = self.pool.get('product.supplierinfo') price_type_obj = self.pool.get('product.price.type') # product.pricelist.version: if not pricelist_ids: pricelist_ids = self.pool.get('product.pricelist').search( cr, uid, [], context=context) pricelist_version_ids = self.pool.get( 'product.pricelist.version').search(cr, uid, [ ('pricelist_id', 'in', pricelist_ids), '|', ('date_start', '=', False), ('date_start', '<=', date), '|', ('date_end', '=', False), ('date_end', '>=', date), ]) if len(pricelist_ids) != len(pricelist_version_ids): raise osv.except_osv( _('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one." )) # product.product: product_ids = [i[0] for i in products_by_qty_by_partner] products = product_obj.browse(cr, uid, product_ids, context=context) products_dict = dict([(item.id, item) for item in products]) # product.category: product_category_ids = product_category_obj.search(cr, uid, []) product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id']) product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']]) results = {} for product_id, qty, partner in products_by_qty_by_partner: for pricelist_id in pricelist_ids: price = False tmpl_id = products_dict[ product_id].product_tmpl_id and products_dict[ product_id].product_tmpl_id.id or False categ_id = products_dict[product_id].categ_id and products_dict[ product_id].categ_id.id or False categ_ids = _create_parent_category_list(categ_id, [categ_id]) if categ_ids: categ_where = '(categ_id IN (' + ','.join( map(str, categ_ids)) + '))' else: categ_where = '(categ_id IS NULL)' if partner: partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) ' partner_args = (partner, tmpl_id) else: partner_where = 'base <> -2 ' partner_args = () pl = self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context) if pl.type == "purchase": product = products_dict[product_id] if 'uom' in context: uom = product.uom_po_id if uom.id != context['uom']: qty = qty * product.uom_po_id.factor / product.uom_id.factor cr.execute( 'SELECT i.*, pl.currency_id ' 'FROM product_pricelist_item AS i, ' 'product_pricelist_version AS v, product_pricelist AS pl ' 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' 'AND (product_id IS NULL OR product_id = %s) ' 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' 'AND (' + partner_where + ') ' 'AND price_version_id = %s ' 'AND (min_quantity IS NULL OR min_quantity <= %s) ' 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' 'ORDER BY sequence', (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty)) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: if res: if res['base'] == -1: if not res['base_pricelist_id']: price = 0.0 else: price_tmp = self.price_get( cr, uid, [res['base_pricelist_id']], product_id, qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse( cr, uid, res['base_pricelist_id']).currency_id.id uom_price_already_computed = True price = currency_obj.compute( cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: where = [] if partner: where = [('name', '=', partner)] sinfo = supplierinfo_obj.search( cr, uid, [('product_id', '=', tmpl_id)] + where) price = 0.0 if sinfo: qty_in_product_uom = qty product_default_uom = product_obj.read( cr, uid, [product_id], ['uom_id'])[0]['uom_id'][0] supplier = supplierinfo_obj.browse( cr, uid, sinfo, context=context)[0] seller_uom = supplier.product_uom and supplier.product_uom.id or False if seller_uom and product_default_uom and product_default_uom != seller_uom: uom_price_already_computed = True qty_in_product_uom = product_uom_obj._compute_qty( cr, uid, product_default_uom, qty, to_uom_id=seller_uom) cr.execute('SELECT * ' \ 'FROM pricelist_partnerinfo ' \ 'WHERE suppinfo_id IN %s' \ 'AND min_quantity <= %s ' \ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,)) res2 = cr.dictfetchone() if res2: price = res2['price'] #Add by Andy elif res['base'] == -3: price = False else: price_type = price_type_obj.browse( cr, uid, int(res['base'])) uom_price_already_computed = True price = currency_obj.compute( cr, uid, price_type.currency_id.id, res['currency_id'], product_obj.price_get( cr, uid, [product_id], price_type.field, context=context)[product_id], round=False, context=context) if price is not False: price_limit = price price = price * (1.0 + (res['price_discount'] or 0.0)) price = rounding( price, res['price_round'] ) #TOFIX: rounding with tools.float_rouding price += (res['price_surcharge'] or 0.0) if res['price_min_margin']: price = max( price, price_limit + res['price_min_margin']) if res['price_max_margin']: price = min( price, price_limit + res['price_max_margin']) break #Add by Andy else: if res['base'] == -3: price = res['price_surcharge'] or 0.0 product = products_dict[product_id] if 'uom' in context: uom = product.uom_po_id if uom.id != context['uom']: price = product_uom_obj._compute_price( cr, uid, uom.id, price, context['uom']) uom_price_already_computed = True #Todo: # Use company currency? if 'currency_id' in context: price = currency_obj.compute( cr, uid, 1, context['currency_id'], price, context=context) if price: break else: # False means no valid line found ! But we may not raise an # exception here because it breaks the search price = False if price: results['item_id'] = res['id'] if 'uom' in context and not uom_price_already_computed: product = products_dict[product_id] uom = product.uos_id or product.uom_id price = product_uom_obj._compute_price( cr, uid, uom.id, price, context['uom']) if results.get(product_id): results[product_id][pricelist_id] = price else: results[product_id] = {pricelist_id: price} return results
def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None): def _create_parent_category_list(id, lst): if not id: return [] parent = product_category_tree.get(id) if parent: lst.append(parent) return _create_parent_category_list(parent, lst) else: return lst # _create_parent_category_list if context is None: context = {} date = time.strftime("%Y-%m-%d") if "date" in context: date = context["date"] currency_obj = self.pool.get("res.currency") product_obj = self.pool.get("product.product") product_category_obj = self.pool.get("product.category") product_uom_obj = self.pool.get("product.uom") supplierinfo_obj = self.pool.get("product.supplierinfo") price_type_obj = self.pool.get("product.price.type") product_pricelist_version_obj = self.pool.get("product.pricelist.version") # product.pricelist.version: if pricelist_ids: pricelist_version_ids = pricelist_ids else: # all pricelists: pricelist_version_ids = self.pool.get("product.pricelist").search(cr, uid, [], context=context) pricelist_version_ids = list(set(pricelist_version_ids)) plversions_search_args = [ ("pricelist_id", "in", pricelist_version_ids), "|", ("date_start", "=", False), ("date_start", "<=", date), "|", ("date_end", "=", False), ("date_end", ">=", date), ] plversion_ids = product_pricelist_version_obj.search(cr, uid, plversions_search_args) if len(pricelist_version_ids) != len(plversion_ids): msg = "At least one pricelist has no active version !\nPlease create or activate one." raise osv.except_osv(_("Warning !"), _(msg)) # product.product: product_ids = [i[0] for i in products_by_qty_by_partner] # products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])]) products = product_obj.browse(cr, uid, product_ids, context=context) products_dict = dict([(item.id, item) for item in products]) # product.category: product_category_ids = product_category_obj.search(cr, uid, []) product_categories = product_category_obj.read(cr, uid, product_category_ids, ["parent_id"]) product_category_tree = dict( [(item["id"], item["parent_id"][0]) for item in product_categories if item["parent_id"]] ) results = {} for product_id, qty, partner in products_by_qty_by_partner: for pricelist_id in pricelist_version_ids: price = False tmpl_id = ( products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False ) categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False categ_ids = _create_parent_category_list(categ_id, [categ_id]) if categ_ids: categ_where = "(categ_id IN (" + ",".join(map(str, categ_ids)) + "))" else: categ_where = "(categ_id IS NULL)" cr.execute( "SELECT i.*, pl.currency_id " "FROM product_pricelist_item AS i, " "product_pricelist_version AS v, product_pricelist AS pl " "WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) " "AND (product_id IS NULL OR product_id = %s) " "AND (" + categ_where + " OR (categ_id IS NULL)) " "AND price_version_id = %s " "AND (min_quantity IS NULL OR min_quantity <= %s) " "AND i.price_version_id = v.id AND v.pricelist_id = pl.id " "ORDER BY sequence", (tmpl_id, product_id, plversion_ids[0], qty), ) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: if res: if res["base"] == -1: if not res["base_pricelist_id"]: price = 0.0 else: price_tmp = self.price_get( cr, uid, [res["base_pricelist_id"]], product_id, qty, context=context )[res["base_pricelist_id"]] ptype_src = self.browse(cr, uid, res["base_pricelist_id"]).currency_id.id price = currency_obj.compute( cr, uid, ptype_src, res["currency_id"], price_tmp, round=False ) elif res["base"] == -2: # this section could be improved by moving the queries outside the loop: where = [] if partner: where = [("name", "=", partner)] sinfo = supplierinfo_obj.search(cr, uid, [("product_id", "=", tmpl_id)] + where) price = 0.0 if sinfo: qty_in_product_uom = qty product_default_uom = product_obj.read(cr, uid, [tmpl_id], ["uom_id"])[0]["uom_id"][0] seller_uom = supplierinfo_obj.read(cr, uid, sinfo, ["product_uom"])[0]["product_uom"][0] if seller_uom and product_default_uom and product_default_uom != seller_uom: uom_price_already_computed = True qty_in_product_uom = product_uom_obj._compute_qty( cr, uid, product_default_uom, qty, to_uom_id=seller_uom ) cr.execute( "SELECT * " "FROM pricelist_partnerinfo " "WHERE suppinfo_id IN %s" "AND min_quantity <= %s " "ORDER BY min_quantity DESC LIMIT 1", (tuple(sinfo), qty_in_product_uom), ) res2 = cr.dictfetchone() if res2: price = res2["price"] # This is added by product_pricelist_fixed_price elif res["base"] == -3: price = res["fixed_price"] break # End else: price_type = price_type_obj.browse(cr, uid, int(res["base"])) price = currency_obj.compute( cr, uid, price_type.currency_id.id, res["currency_id"], product_obj.price_get(cr, uid, [product_id], price_type.field, context=context)[ product_id ], round=False, context=context, ) if price and res["base"] != -3: # Modified by product_pricelist_fixed_price price_limit = price price = price * (1.0 + (res["price_discount"] or 0.0)) price = rounding(price, res["price_round"]) price += res["price_surcharge"] or 0.0 if res["price_min_margin"]: price = max(price, price_limit + res["price_min_margin"]) if res["price_max_margin"]: price = min(price, price_limit + res["price_max_margin"]) break else: # False means no valid line found ! But we may not raise an # exception here because it breaks the search price = False if price: if "uom" in context and not uom_price_already_computed: product = products_dict[product_id] uom = product.uos_id or product.uom_id price = self.pool.get("product.uom")._compute_price(cr, uid, uom.id, price, context["uom"]) if results.get(product_id): results[product_id][pricelist_id] = price else: results[product_id] = {pricelist_id: price} return results
def update_or_create_line(self, cr, uid, values, context=None): """ values = { 'name': expense_line.name, 'product': expense_line.product_id, 'product_qty': expense_line.unit_quantity, 'product_uom': expense_line.uom_id, # Optional, is not required. 'account_id': expense_line.analytic_account.id, 'unit_amount': values.get('unit_amount', False), # Optional, is not required 'date': expense_line.date_value + ' 00:00:00', 'ref': hr_expense.name, 'origin_document': expense_line } """ journals = { "hr.expense.line": {"journal": "expense_journal_id", "name": _("Expense Journal")}, "stock.move": {"journal": "delivery_note_journal_id", "name": _("Delivery Note Journal")}, } if values.get("account_id", False): user = self.pool["res.users"].browse(cr, uid, uid, context) journal = getattr(user.company_id, journals[values["origin_document"]._name]["journal"]) if journal: journal_id = journal.id else: raise orm.except_orm( "Error", _("{journal} is not defined for this company").format( journal=journals[values["origin_document"]._name]["name"] ), ) product_qty = values.get("product_qty", 1) price_unit_precision = self.pool["decimal.precision"].precision_get(cr, uid, "Sale Price") if values.get("unit_amount", False): amount = rounding(values["unit_amount"] * product_qty, 10 ** -price_unit_precision) elif values.get("product", False): amount = self.get_cost_amount(cr, uid, values["product"], product_qty, context) else: return False if values.get("product", False): general_account_id = values["product"].product_tmpl_id.property_account_expense.id if not general_account_id: general_account_id = values["product"].categ_id.property_account_expense_categ.id if not general_account_id: raise orm.except_orm( _("Error!"), _( """There is no expense account defined for this product: "{0}" (id:{1})""" ).format(values["product"].name, values["product"].id), ) else: general_account_id = False line_date = datetime.datetime.strptime(values["date"], DEFAULT_SERVER_DATETIME_FORMAT) line_date = datetime.date(year=line_date.year, month=line_date.month, day=line_date.day) analytic_line_ids = self.search( cr, uid, [ ( "origin_document", "=", "{model}, {document_id}".format( model=values["origin_document"]._name, document_id=values["origin_document"].id ), ) ], context, ) if analytic_line_ids: return self.write( cr, uid, analytic_line_ids, { "amount": -amount, "user_id": uid, "name": values["name"], "unit_amount": product_qty, # What a strange idea to call product_qty unit_amount!!! "date": line_date, "company_id": user.company_id.id, "account_id": values["account_id"], "general_account_id": general_account_id, "product_id": values["product"].id, "product_uom_id": values.get("product_uom", values["product"].uom_id.id), "journal_id": journal_id, "amount_currency": 0.0, "ref": values.get("ref", False), "origin_document": "{model}, {document_id}".format( model=values["origin_document"]._name, document_id=values["origin_document"].id ), }, context, ) else: return self.create( cr, uid, { "amount": -amount, "user_id": uid, "name": values["name"], "unit_amount": product_qty, "date": line_date, "company_id": user.company_id.id, "account_id": values["account_id"], "general_account_id": general_account_id, "product_id": values["product"].id, "product_uom_id": values.get("product_uom", values["product"].uom_id.id), "journal_id": journal_id, "amount_currency": 0.0, "ref": values.get("ref", False), "origin_document": "{model}, {document_id}".format( model=values["origin_document"]._name, document_id=values["origin_document"].id ), }, context, ) else: return False
def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None): def _create_parent_category_list(id, lst): if not id: return [] parent = product_category_tree.get(id) if parent: lst.append(parent) return _create_parent_category_list(parent, lst) else: return lst # _create_parent_category_list if context is None: context = {} date = time.strftime('%Y-%m-%d') if 'date' in context: date = context['date'] currency_obj = self.pool.get('res.currency') product_obj = self.pool.get('product.product') product_category_obj = self.pool.get('product.category') product_uom_obj = self.pool.get('product.uom') supplierinfo_obj = self.pool.get('product.supplierinfo') price_type_obj = self.pool.get('product.price.type') product_pricelist_version_obj = self.pool.get( 'product.pricelist.version') # product.pricelist.version: if pricelist_ids: pricelist_version_ids = pricelist_ids else: # all pricelists: pricelist_version_ids = self.pool.get('product.pricelist').search( cr, uid, [], context=context) pricelist_version_ids = list(set(pricelist_version_ids)) plversions_search_args = [ ('pricelist_id', 'in', pricelist_version_ids), '|', ('date_start', '=', False), ('date_start', '<=', date), '|', ('date_end', '=', False), ('date_end', '>=', date), ] plversion_ids = product_pricelist_version_obj.search( cr, uid, plversions_search_args) if len(pricelist_version_ids) != len(plversion_ids): msg = "At least one pricelist has no active version !\nPlease create or activate one." raise osv.except_osv(_('Warning !'), _(msg)) # product.product: product_ids = [i[0] for i in products_by_qty_by_partner] #products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])]) products = product_obj.browse(cr, uid, product_ids, context=context) products_dict = dict([(item.id, item) for item in products]) # product.category: product_category_ids = product_category_obj.search(cr, uid, []) product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id']) product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']]) results = {} for product_id, qty, partner in products_by_qty_by_partner: for pricelist_id in pricelist_version_ids: price = False tmpl_id = products_dict[ product_id].product_tmpl_id and products_dict[ product_id].product_tmpl_id.id or False categ_id = products_dict[product_id].categ_id and products_dict[ product_id].categ_id.id or False categ_ids = _create_parent_category_list(categ_id, [categ_id]) if categ_ids: categ_where = '(categ_id IN (' + ','.join( map(str, categ_ids)) + '))' else: categ_where = '(categ_id IS NULL)' cr.execute( 'SELECT i.*, pl.currency_id ' 'FROM product_pricelist_item AS i, ' 'product_pricelist_version AS v, product_pricelist AS pl ' 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' 'AND (product_id IS NULL OR product_id = %s) ' 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' 'AND price_version_id = %s ' 'AND (min_quantity IS NULL OR min_quantity <= %s) ' 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' 'ORDER BY sequence', (tmpl_id, product_id, plversion_ids[0], qty)) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: if res: if res['base'] == -1: if not res['base_pricelist_id']: price = 0.0 else: price_tmp = self.price_get( cr, uid, [res['base_pricelist_id']], product_id, qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse( cr, uid, res['base_pricelist_id']).currency_id.id price = currency_obj.compute( cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: where = [] if partner: where = [('name', '=', partner)] sinfo = supplierinfo_obj.search( cr, uid, [('product_id', '=', tmpl_id)] + where) price = 0.0 if sinfo: qty_in_product_uom = qty product_default_uom = product_obj.read( cr, uid, [tmpl_id], ['uom_id'])[0]['uom_id'][0] seller_uom = supplierinfo_obj.read( cr, uid, sinfo, ['product_uom'])[0]['product_uom'][0] if seller_uom and product_default_uom and product_default_uom != seller_uom: uom_price_already_computed = True qty_in_product_uom = product_uom_obj._compute_qty( cr, uid, product_default_uom, qty, to_uom_id=seller_uom) cr.execute('SELECT * ' \ 'FROM pricelist_partnerinfo ' \ 'WHERE suppinfo_id IN %s' \ 'AND min_quantity <= %s ' \ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo),qty_in_product_uom,)) res2 = cr.dictfetchone() if res2: price = res2['price'] #This is added by product_pricelist_fixed_price elif res['base'] == -3: price = res['fixed_price'] #End else: price_type = price_type_obj.browse( cr, uid, int(res['base'])) price = currency_obj.compute( cr, uid, price_type.currency_id.id, res['currency_id'], product_obj.price_get( cr, uid, [product_id], price_type.field, context=context)[product_id], round=False, context=context) if price: price_limit = price price = price * (1.0 + (res['price_discount'] or 0.0)) price = rounding(price, res['price_round']) price += (res['price_surcharge'] or 0.0) if res['price_min_margin']: price = max( price, price_limit + res['price_min_margin']) if res['price_max_margin']: price = min( price, price_limit + res['price_max_margin']) break else: # False means no valid line found ! But we may not raise an # exception here because it breaks the search price = False if price: if 'uom' in context and not uom_price_already_computed: product = products_dict[product_id] uom = product.uos_id or product.uom_id price = self.pool.get('product.uom')._compute_price( cr, uid, uom.id, price, context['uom']) if results.get(product_id): results[product_id][pricelist_id] = price else: results[product_id] = {pricelist_id: price} return results
def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom, partner_id, date_order=False, fiscal_position=False, date_planned=False, name=False, price_unit=False, notes=False): if not pricelist: raise osv.except_osv(_('No Pricelist !'), _('You have to select a pricelist or a supplier in the purchase form !\nPlease set one before choosing a product.')) if not partner_id: raise osv.except_osv(_('No Partner!'), _('You have to select a partner in the purchase form !\nPlease set one partner before choosing a product.')) if not product: return {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'notes': notes or'', 'product_uom' : uom or False}, 'domain':{'product_uom':[]}} res = {} prod= self.pool.get('product.product').browse(cr, uid, product) product_uom_pool = self.pool.get('product.uom') lang=False if partner_id: lang=self.pool.get('res.partner').read(cr, uid, partner_id, ['lang'])['lang'] context = self.pool.get('res.users').context_get(cr, uid) context_partner = {'lang':lang, 'partner_id': partner_id} prod = self.pool.get('product.product').browse(cr, uid, product, context=context) prod_uom_po = prod.uom_po_id.id if not uom: uom = prod_uom_po if not date_order: date_order = time.strftime('%Y-%m-%d') qty = qty or 1.0 seller_delay = 0 prod_name = self.pool.get('product.product').name_get(cr, uid, [prod.id], context=context_partner)[0][1] res = {} for s in prod.seller_ids: if s.name.id == partner_id: seller_delay = s.delay if s.product_uom: temp_qty = product_uom_pool._compute_qty(cr, uid, s.product_uom.id, s.min_qty, to_uom_id=prod.uom_id.id) uom = s.product_uom.id #prod_uom_po temp_qty = s.min_qty # supplier _qty assigned to temp if qty < temp_qty: # If the supplier quantity is greater than entered from user, set minimal. qty = temp_qty res.update({'warning': {'title': _('Warning'), 'message': _('The selected supplier has a minimal quantity set to %s, you cannot purchase less.') % qty}}) qty_in_product_uom = product_uom_pool._compute_qty(cr, uid, uom, qty, to_uom_id=prod.uom_id.id) price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], product, qty_in_product_uom or 1.0, partner_id, { 'uom': uom, 'date': date_order, })[pricelist] # at end, round price depending of 'Purchase Price' decimal precision price_unit_precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Purchase Price') price = rounding(price, 10**-price_unit_precision) if price is False: warning = { 'title': 'No valid pricelist line found !', 'message': "Couldn't find a pricelist line matching this product and quantity.\n" "You have to change either the product, the quantity or the pricelist." } res.update({'warning': warning}) dt = (datetime.now() + relativedelta(days=int(seller_delay) or 0.0)).strftime('%Y-%m-%d %H:%M:%S') res.update({'value': {'price_unit': price, 'name': prod_name, 'taxes_id':map(lambda x: x.id, prod.supplier_taxes_id), 'date_planned': date_planned or dt,'notes': notes or prod.description_purchase, 'product_qty': qty, 'product_uom': uom}}) domain = {} taxes = self.pool.get('account.tax').browse(cr, uid,map(lambda x: x.id, prod.supplier_taxes_id)) fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False res['value']['taxes_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, taxes) res2 = self.pool.get('product.uom').read(cr, uid, [uom], ['category_id']) res3 = prod.uom_id.category_id.id domain = {'product_uom':[('category_id','=',res2[0]['category_id'][0])]} if res2[0]['category_id'][0] != res3: raise osv.except_osv(_('Wrong Product UOM !'), _('You have to select a product UOM in the same category than the purchase UOM of the product')) res['domain'] = domain return res
def price_get_multi(self, cr, uid, pricelist_ids, products_by_qty_by_partner, context=None): """multi products 'price_get'. @param pricelist_ids: @param products_by_qty: @param partner: @param context: { 'date': Date of the pricelist (%Y-%m-%d),} @return: a dict of dict with product_id as key and a dict 'price by pricelist' as value """ def _create_parent_category_list(id, lst): if not id: return [] parent = product_category_tree.get(id) if parent: lst.append(parent) return _create_parent_category_list(parent, lst) else: return lst # _create_parent_category_list if context is None: context = {} date = time.strftime('%Y-%m-%d') if 'date' in context: date = context['date'] currency_obj = self.pool.get('res.currency') product_obj = self.pool.get('product.product') product_category_obj = self.pool.get('product.category') product_uom_obj = self.pool.get('product.uom') supplierinfo_obj = self.pool.get('product.supplierinfo') price_type_obj = self.pool.get('product.price.type') # product.pricelist.version: if not pricelist_ids: pricelist_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context) pricelist_version_ids = self.pool.get('product.pricelist.version').search(cr, uid, [ ('pricelist_id', 'in', pricelist_ids), '|', ('date_start', '=', False), ('date_start', '<=', date), '|', ('date_end', '=', False), ('date_end', '>=', date), ]) if len(pricelist_ids) != len(pricelist_version_ids): raise osv.except_osv(_('Warning!'), _("At least one pricelist has no active version !\nPlease create or activate one.")) # product.product: product_ids = [i[0] for i in products_by_qty_by_partner] products = product_obj.browse(cr, uid, product_ids, context=context) products_dict = dict([(item.id, item) for item in products]) # product.category: product_category_ids = product_category_obj.search(cr, uid, []) product_categories = product_category_obj.read(cr, uid, product_category_ids, ['parent_id']) product_category_tree = dict([(item['id'], item['parent_id'][0]) for item in product_categories if item['parent_id']]) results = {} for product_id, qty, partner in products_by_qty_by_partner: for pricelist_id in pricelist_ids: price = False tmpl_id = products_dict[product_id].product_tmpl_id and products_dict[product_id].product_tmpl_id.id or False categ_id = products_dict[product_id].categ_id and products_dict[product_id].categ_id.id or False categ_ids = _create_parent_category_list(categ_id, [categ_id]) if categ_ids: categ_where = '(categ_id IN (' + ','.join(map(str, categ_ids)) + '))' else: categ_where = '(categ_id IS NULL)' if partner: partner_where = 'base <> -2 OR %s IN (SELECT name FROM product_supplierinfo WHERE product_id = %s) ' partner_args = (partner, tmpl_id) else: partner_where = 'base <> -2 ' partner_args = () pl = self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context) if pl.type == "purchase": product = products_dict[product_id] if 'uom' in context: uom = product.uom_po_id if uom.id != context['uom']: qty = qty * product.uom_po_id.factor / product.uom_id.factor cr.execute( 'SELECT i.*, pl.currency_id ' 'FROM product_pricelist_item AS i, ' 'product_pricelist_version AS v, product_pricelist AS pl ' 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s) ' 'AND (product_id IS NULL OR product_id = %s) ' 'AND (' + categ_where + ' OR (categ_id IS NULL)) ' 'AND (' + partner_where + ') ' 'AND price_version_id = %s ' 'AND (min_quantity IS NULL OR min_quantity <= %s) ' 'AND i.price_version_id = v.id AND v.pricelist_id = pl.id ' 'ORDER BY sequence', (tmpl_id, product_id) + partner_args + (pricelist_version_ids[0], qty)) res1 = cr.dictfetchall() uom_price_already_computed = False for res in res1: if res: if res['base'] == -1: if not res['base_pricelist_id']: price = 0.0 else: price_tmp = self.price_get(cr, uid, [res['base_pricelist_id']], product_id, qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id uom_price_already_computed = True price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: where = [] if partner: where = [('name', '=', partner) ] sinfo = supplierinfo_obj.search(cr, uid, [('product_id', '=', tmpl_id)] + where) price = 0.0 if sinfo: qty_in_product_uom = qty product_default_uom = product_obj.read(cr, uid, [product_id], ['uom_id'])[0]['uom_id'][0] supplier = supplierinfo_obj.browse(cr, uid, sinfo, context=context)[0] seller_uom = supplier.product_uom and supplier.product_uom.id or False if seller_uom and product_default_uom and product_default_uom != seller_uom: uom_price_already_computed = True qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, product_default_uom, qty, to_uom_id=seller_uom) cr.execute('SELECT * ' \ 'FROM pricelist_partnerinfo ' \ 'WHERE suppinfo_id IN %s' \ 'AND min_quantity <= %s ' \ 'ORDER BY min_quantity DESC LIMIT 1', (tuple(sinfo), qty_in_product_uom,)) res2 = cr.dictfetchone() if res2: price = res2['price'] #Add by Andy elif res['base'] == -3: price = False else: price_type = price_type_obj.browse(cr, uid, int(res['base'])) uom_price_already_computed = True price = currency_obj.compute(cr, uid, price_type.currency_id.id, res['currency_id'], product_obj.price_get(cr, uid, [product_id], price_type.field, context=context)[product_id], round=False, context=context) if price is not False: price_limit = price price = price * (1.0 + (res['price_discount'] or 0.0)) price = rounding(price, res['price_round']) #TOFIX: rounding with tools.float_rouding price += (res['price_surcharge'] or 0.0) if res['price_min_margin']: price = max(price, price_limit + res['price_min_margin']) if res['price_max_margin']: price = min(price, price_limit + res['price_max_margin']) break #Add by Andy else: if res['base'] == -3: price = res['price_surcharge'] or 0.0 product = products_dict[product_id] if 'uom' in context: uom = product.uom_po_id if uom.id != context['uom']: price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom']) uom_price_already_computed = True #Todo: # Use company currency? if 'currency_id' in context: price = currency_obj.compute(cr, uid, 1, context['currency_id'], price, context=context) if price: break else: # False means no valid line found ! But we may not raise an # exception here because it breaks the search price = False if price: results['item_id'] = res['id'] if 'uom' in context and not uom_price_already_computed: product = products_dict[product_id] uom = product.uos_id or product.uom_id price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom']) if results.get(product_id): results[product_id][pricelist_id] = price else: results[product_id] = {pricelist_id: price} return results