[REF] product: do not use selected_seller_id
The function field selected_seller_id is removed and must be replaced by a direct call to method `_select_seller`. This is more conventional than the previous 'browse with context' way of doing.
This commit is contained in:
+22
-22
@@ -904,28 +904,29 @@ class product_product(osv.osv):
|
||||
result[product.id] = price_extra
|
||||
return result
|
||||
|
||||
def _select_seller(self, cr, uid, ids, name, arg, context=None):
|
||||
def _select_seller(self, cr, uid, product_id, partner_id=False, quantity=0.0, date=time.strftime(DEFAULT_SERVER_DATE_FORMAT), uom_id=False, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
res = {}
|
||||
partner = context.get('partner_id')
|
||||
minimal_quantity = context.get('quantity', 0.0)
|
||||
date = context.get('date', time.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
res[product.id] = False
|
||||
for seller in product.seller_ids:
|
||||
if seller.date_start and seller.date_start > date:
|
||||
continue
|
||||
if seller.date_end and seller.date_end < date:
|
||||
continue
|
||||
if partner and seller.name.id != partner:
|
||||
continue
|
||||
if minimal_quantity and minimal_quantity < seller.qty:
|
||||
continue
|
||||
if seller.product_id and seller.product_id != product:
|
||||
continue
|
||||
res[product.id] = seller
|
||||
break
|
||||
res = self.pool.get('product.supplierinfo').browse(cr, uid, [])
|
||||
for seller in product_id.seller_ids:
|
||||
# Set quantity in UoM of seller
|
||||
quantity_uom_seller = quantity
|
||||
if quantity_uom_seller and uom_id and uom_id != seller.product_uom:
|
||||
quantity_uom_seller = uom_id._compute_qty_obj(uom_id, quantity_uom_seller, seller.product_uom)
|
||||
|
||||
if seller.date_start and seller.date_start > date:
|
||||
continue
|
||||
if seller.date_end and seller.date_end < date:
|
||||
continue
|
||||
if partner_id and seller.name != partner_id:
|
||||
continue
|
||||
if quantity_uom_seller and quantity_uom_seller < seller.qty:
|
||||
continue
|
||||
if seller.product_id and seller.product_id != product_id:
|
||||
continue
|
||||
|
||||
res |= seller
|
||||
break
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
@@ -964,7 +965,6 @@ class product_product(osv.osv):
|
||||
groups="base.group_user", string="Cost"),
|
||||
'volume': fields.float('Volume', help="The volume in m3."),
|
||||
'weight': fields.float('Gross Weight', digits_compute=dp.get_precision('Stock Weight'), help="The weight of the contents in Kg, not including any packaging, etc."),
|
||||
'selected_seller_id': fields.function(_select_seller, type='many2one', relation='product.supplierinfo', string='Selected Seller', help='Technical field that selects a seller based on priority (sequence) and an optional partner and/or a minimal quantity in the context'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -1236,7 +1236,7 @@ class product_supplierinfo(osv.osv):
|
||||
'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', select=True, oldname='product_id'),
|
||||
'delay': fields.integer('Delivery Lead Time', required=True, help="Lead time in days between the confirmation of the purchase order and the receipt of the products in your warehouse. Used by the scheduler for automatic computation of the purchase order planning."),
|
||||
'company_id': fields.many2one('res.company', string='Company', select=1),
|
||||
'product_id': fields.many2one('product.product', string='Product Variant'),
|
||||
'product_id': fields.many2one('product.product', string='Product Variant', help="When this field is filled in, the vendor data will only apply to the variant."),
|
||||
}
|
||||
_defaults = {
|
||||
'min_qty': 0.0,
|
||||
|
||||
@@ -51,17 +51,17 @@
|
||||
-
|
||||
!python {model: product.product}: |
|
||||
from openerp.tools import float_compare
|
||||
context.update({'quantity':1, 'date': False, 'partner_id': ref('base.res_partner_4')})
|
||||
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
||||
assert float_compare(product.selected_seller_id.price, 790, precision_digits=2) == 0, "Wrong cost price: LCD Monitor."
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, ref('base.res_partner_4'), context=context)
|
||||
assert float_compare(product._select_seller(product, partner_id=partner, quantity=1.0).price, 790, precision_digits=2) == 0, "Wrong cost price: LCD Monitor."
|
||||
-
|
||||
I check cost price of LCD Monitor if more than 3 Unit.
|
||||
-
|
||||
!python {model: product.product}: |
|
||||
from openerp.tools import float_compare
|
||||
context.update({'quantity':3})
|
||||
product = self.browse(cr, uid, ref("product_product_6"), context=context)
|
||||
assert float_compare(product.selected_seller_id.price, 785, precision_digits=2) == 0, "Wrong cost price: LCD Monitor if more than 3 Unit."
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, ref('base.res_partner_4'), context=context)
|
||||
assert float_compare(product._select_seller(product, partner_id=partner, quantity=3.0).price, 785, precision_digits=2) == 0, "Wrong cost price: LCD Monitor if more than 3 Unit."
|
||||
-
|
||||
I print the sale prices report.
|
||||
-
|
||||
|
||||
+63
-109
@@ -531,7 +531,7 @@ class PurchaseOrderLine(models.Model):
|
||||
return super(PurchaseOrderLine, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _get_date_planned(self, product, po=False):
|
||||
def _get_date_planned(self, seller, po=False):
|
||||
"""Return the datetime value to use as Schedule Date (``date_planned``) for
|
||||
PO Lines that correspond to the given product.seller_ids,
|
||||
when ordered at `date_order_str`.
|
||||
@@ -543,15 +543,11 @@ class PurchaseOrderLine(models.Model):
|
||||
:rtype: datetime
|
||||
:return: desired Schedule Date for the PO line
|
||||
"""
|
||||
supplier_delay = int(product.selected_seller_id.delay) if product else 0
|
||||
if po:
|
||||
date_order = po.date_order
|
||||
else:
|
||||
date_order = self.order_id.date_order
|
||||
date_order = po.date_order if po else self.order_id.date_order
|
||||
if date_order:
|
||||
return datetime.strptime(date_order, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=supplier_delay)
|
||||
return datetime.strptime(date_order, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=seller.delay if seller else 0)
|
||||
else:
|
||||
return datetime.today() + relativedelta(days=supplier_delay)
|
||||
return datetime.today() + relativedelta(days=seller.delay if seller else 0)
|
||||
|
||||
@api.onchange('product_id', 'product_qty', 'product_uom')
|
||||
def onchange_product_id(self):
|
||||
@@ -563,18 +559,27 @@ class PurchaseOrderLine(models.Model):
|
||||
self.product_uom = self.product_id.uom_po_id
|
||||
result['domain'] = {'product_uom': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
||||
|
||||
res = self._get_name_price_quantity_date(
|
||||
seller = self.product_id._select_seller(
|
||||
self.product_id,
|
||||
self.partner_id,
|
||||
self.order_id.date_order and self.order_id.date_order[:10],
|
||||
self.product_qty,
|
||||
self.product_uom,
|
||||
self.order_id.currency_id)
|
||||
partner_id=self.partner_id,
|
||||
quantity=self.product_qty,
|
||||
date=self.order_id.date_order and self.order_id.date_order[:10],
|
||||
uom_id=self.product_uom)
|
||||
|
||||
self.name = res['name']
|
||||
self.product_qty = res['quantity'] if not res['quantity'] else max(self.product_qty, res['quantity'])
|
||||
self.price_unit = res['price_unit']
|
||||
self.date_planned = res['date_planned']
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and self.order_id.currency_id and seller.currency_id != self.order_id.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, self.order_id.currency_id)
|
||||
self.price_unit = price_unit
|
||||
|
||||
self.date_planned = self._get_date_planned(seller).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
product_lang = self.product_id.with_context({
|
||||
'lang': self.partner_id.lang,
|
||||
'partner_id': self.partner_id.id,
|
||||
})
|
||||
self.name = product_lang.display_name
|
||||
if product_lang.description_purchase:
|
||||
self.name += '\n' + product_lang.description_purchase
|
||||
|
||||
taxes = self.product_id.supplier_taxes_id
|
||||
fpos = self.order_id.fiscal_position_id
|
||||
@@ -591,67 +596,6 @@ class PurchaseOrderLine(models.Model):
|
||||
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def _get_name_price_quantity_date(self, product_id, partner_id, date, quantity, product_uom, currency_id, order_id=False):
|
||||
"""Return the name of the product, the seller quantity, the unit price and
|
||||
the date planned of a given product.
|
||||
|
||||
:param browse_record product_id: product.product, for which we want to
|
||||
get the information
|
||||
:param browse_record partner_id: res.partner, supplier of the product
|
||||
:param str date: order date
|
||||
:param float quantity: quantity of product in product_uom UoM
|
||||
:param browse_record product_uom: product.uom, product_uom UoM in which is
|
||||
expressed the quantity
|
||||
:param browse_record currency_id: res.currency, currency in which we want the price
|
||||
:param browse_record | False order_id: purchase.order, purchase order in case we
|
||||
try to get the data for a PO line not yet attached to a PO.
|
||||
:rtype: dict
|
||||
:return: name, seller quantity, seller price, date planned
|
||||
"""
|
||||
# This is useful in case partner is not registered supplier
|
||||
if not product_id or not partner_id or not product_uom or not currency_id:
|
||||
return {
|
||||
'name': False,
|
||||
'quantity': 0.0,
|
||||
'price_unit': 0.0,
|
||||
'date_planned': False,
|
||||
}
|
||||
|
||||
# The first browse is used to know the uom_id and the currency_id for the given vendor
|
||||
product = product_id.with_context({'partner_id': partner_id.id})
|
||||
seller_currency_id = product.selected_seller_id.currency_id if product.selected_seller_id else partner_id.currency_id
|
||||
seller_product_uom = product.selected_seller_id.product_uom if product.selected_seller_id else product_id.uom_id
|
||||
|
||||
# Switch quantity to uom_id
|
||||
quantity_seller_uom_id = quantity
|
||||
if quantity_seller_uom_id and seller_product_uom != product_uom:
|
||||
quantity_seller_uom_id = product_uom._compute_qty_obj(product_uom, quantity_seller_uom_id, seller_product_uom)
|
||||
|
||||
product = product_id.with_context({
|
||||
'lang': partner_id.lang,
|
||||
'partner_id': partner_id.id,
|
||||
'date': date,
|
||||
'quantity': quantity_seller_uom_id,
|
||||
})
|
||||
|
||||
price_unit = product.selected_seller_id.price
|
||||
if price_unit and seller_currency_id != currency_id:
|
||||
price_unit = seller_currency_id.compute(price_unit, currency_id)
|
||||
|
||||
date_planned = self._get_date_planned(product, po=order_id).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
name = product.display_name
|
||||
if product.description_purchase:
|
||||
name += '\n' + product.description_purchase
|
||||
|
||||
return {
|
||||
'name': name,
|
||||
'quantity': quantity,
|
||||
'price_unit': price_unit,
|
||||
'date_planned': date_planned,
|
||||
}
|
||||
|
||||
|
||||
class ProcurementRule(models.Model):
|
||||
_inherit = 'procurement.rule'
|
||||
@@ -684,16 +628,16 @@ class ProcurementOrder(models.Model):
|
||||
|
||||
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
if not float_is_zero(product_qty, precision_digits=precision):
|
||||
res = self.env['purchase.order.line']._get_name_price_quantity_date(
|
||||
seller = procurement.product_id._select_seller(
|
||||
procurement.product_id,
|
||||
procurement.purchase_line_id.partner_id,
|
||||
procurement.purchase_line_id.order_id.date_order and procurement.purchase_line_id.order_id.date_order[:10],
|
||||
product_qty,
|
||||
procurement.product_uom,
|
||||
procurement.purchase_line_id.order_id.currency_id)
|
||||
partner_id=procurement.purchase_line_id.partner_id,
|
||||
quantity=product_qty,
|
||||
date=procurement.purchase_line_id.order_id.date_order and procurement.purchase_line_id.order_id.date_order[:10],
|
||||
uom_id=procurement.product_uom)
|
||||
|
||||
product_qty = res['quantity']
|
||||
price_unit = res['price_unit']
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and procurement.purchase_line_id.order_id.currency_id and seller.currency_id != procurement.purchase_line_id.order_id.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, procurement.purchase_line_id.order_id.currency_id)
|
||||
|
||||
procurement.purchase_line_id.product_qty = product_qty
|
||||
procurement.purchase_line_id.price_unit = price_unit
|
||||
@@ -736,7 +680,7 @@ class ProcurementOrder(models.Model):
|
||||
@api.v8
|
||||
def _get_purchase_order_date(self, schedule_date):
|
||||
self.ensure_one()
|
||||
seller_delay = int(self.product_id.selected_seller_id.delay)
|
||||
seller_delay = int(self.product_id._select_seller(self.product_id).delay)
|
||||
return schedule_date - relativedelta(days=seller_delay)
|
||||
|
||||
@api.v7
|
||||
@@ -750,26 +694,33 @@ class ProcurementOrder(models.Model):
|
||||
:rtype: datetime
|
||||
:return: the desired Order Date for the PO
|
||||
"""
|
||||
seller_delay = int(procurement.product_id.selected_seller_id.delay)
|
||||
seller_delay = int(procurement.product_id._select_seller(procurement.product_id).delay)
|
||||
return schedule_date - relativedelta(days=seller_delay)
|
||||
|
||||
@api.multi
|
||||
def _prepare_purchase_order_line(self, po, supplier):
|
||||
self.ensure_one()
|
||||
|
||||
res = self.env['purchase.order.line']._get_name_price_quantity_date(
|
||||
seller = self.product_id._select_seller(
|
||||
self.product_id,
|
||||
supplier.name,
|
||||
po.date_order and po.date_order[:10],
|
||||
self.product_qty,
|
||||
self.product_uom,
|
||||
po.currency_id,
|
||||
order_id=po)
|
||||
partner_id=supplier.name,
|
||||
quantity=self.product_qty,
|
||||
date=po.date_order and po.date_order[:10],
|
||||
uom_id=self.product_uom)
|
||||
|
||||
name = res['name']
|
||||
product_qty = res['quantity']
|
||||
price_unit = res['price_unit']
|
||||
date_planned = res['date_planned']
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, po.currency_id)
|
||||
|
||||
product_lang = self.product_id.with_context({
|
||||
'lang': supplier.name.lang,
|
||||
'partner_id': supplier.name.id,
|
||||
})
|
||||
name = product_lang.display_name
|
||||
if product_lang.description_purchase:
|
||||
name += '\n' + product_lang.description_purchase
|
||||
|
||||
date_planned = self.env['purchase.order.line']._get_date_planned(seller, po=po).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
taxes = self.product_id.supplier_taxes_id
|
||||
fpos = po.fiscal_position_id
|
||||
@@ -777,7 +728,7 @@ class ProcurementOrder(models.Model):
|
||||
|
||||
return {
|
||||
'name': name,
|
||||
'product_qty': product_qty,
|
||||
'product_qty': self.product_qty,
|
||||
'product_id': self.product_id.id,
|
||||
'product_uom': self.product_uom.id,
|
||||
'price_unit': price_unit,
|
||||
@@ -844,17 +795,20 @@ class ProcurementOrder(models.Model):
|
||||
po_line = False
|
||||
for line in po.order_line:
|
||||
if line.product_id == procurement.product_id and line.product_uom == procurement.product_uom:
|
||||
res = self.env['purchase.order.line']._get_name_price_quantity_date(
|
||||
seller = self.product_id._select_seller(
|
||||
self.product_id,
|
||||
partner,
|
||||
po.date_order and po.date_order[:10],
|
||||
line.product_qty + procurement.product_qty,
|
||||
self.product_uom,
|
||||
po.currency_id)
|
||||
partner_id=partner,
|
||||
quantity=line.product_qty + procurement.product_qty,
|
||||
date=po.date_order and po.date_order[:10],
|
||||
uom_id=self.product_uom)
|
||||
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, po.currency_id)
|
||||
|
||||
po_line = line.write({
|
||||
'product_qty': res['quantity'],
|
||||
'price_unit': res['price_unit'],
|
||||
'product_qty': line.product_qty + procurement.product_qty,
|
||||
'price_unit': price_unit,
|
||||
'procurement_ids': [(4, procurement.id)]
|
||||
})
|
||||
if not po_line:
|
||||
|
||||
@@ -62,8 +62,12 @@ class TestPurchaseOrder(AccountingTestCase):
|
||||
self.assertEqual(self.po.invoice_status, 'to invoice', 'Purchase: PO invoice_status should be "Waiting Invoices"')
|
||||
|
||||
self.assertTrue(self.product_id_2.seller_ids.filtered(lambda r: r.name == self.partner_id), 'Purchase: the partner should be in the list of the product suppliers')
|
||||
res = self.PurchaseOrderLine._get_name_price_quantity_date(self.product_id_2, self.partner_id, self.po.date_planned, 2.0, self.product_id_2.uom_po_id, self.po.currency_id)
|
||||
self.assertEqual(res['price_unit'], 250.0, 'Purchase: the price of the product for the suppleir should be 250.0.')
|
||||
|
||||
seller = self.product_id_2._select_seller(self.product_id_2, partner_id=self.partner_id, quantity=2.0, date=self.po.date_planned, uom_id=self.product_id_2.uom_po_id)
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and self.po.currency_id and seller.currency_id != self.po.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, self.po.currency_id)
|
||||
self.assertEqual(price_unit, 250.0, 'Purchase: the price of the product for the supplier should be 250.0.')
|
||||
|
||||
self.assertEqual(self.po.picking_count, 1, 'Purchase: one picking should be created"')
|
||||
self.picking = self.po.picking_ids[0]
|
||||
|
||||
@@ -147,24 +147,35 @@ class purchase_requisition(osv.osv):
|
||||
taxes_id = fpos.map_tax(taxes) if fpos else []
|
||||
|
||||
po = po_obj.browse(cr, uid, [purchase_id], context=context)
|
||||
res = po_line_obj._get_name_price_quantity_date(cr, uid,
|
||||
seller = requisition_line.product_id._select_seller(
|
||||
requisition_line.product_id,
|
||||
supplier,
|
||||
date_order and date_order[:10],
|
||||
qty,
|
||||
product.uom_po_id,
|
||||
po.currency_id,
|
||||
order_id=po,
|
||||
context=context)
|
||||
partner_id=supplier,
|
||||
quantity=qty,
|
||||
date=date_order and date_order[:10],
|
||||
uom_id=product.uom_po_id)
|
||||
|
||||
price_unit = seller.price if seller else 0.0
|
||||
if price_unit and seller and po.currency_id and seller.currency_id != po.currency_id:
|
||||
price_unit = seller.currency_id.compute(price_unit, po.currency_id)
|
||||
|
||||
date_planned = po_line_obj._get_date_planned(cr, uid, seller, po=po, context=context).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
product_lang = requisition_line.product_id.with_context({
|
||||
'lang': supplier.lang,
|
||||
'partner_id': supplier.id,
|
||||
})
|
||||
name = product_lang.display_name
|
||||
if product_lang.description_purchase:
|
||||
name += '\n' + product_lang.description_purchase
|
||||
|
||||
vals = {
|
||||
'name': res['name'],
|
||||
'name': name,
|
||||
'order_id': purchase_id,
|
||||
'product_qty': res['quantity'],
|
||||
'product_qty': qty,
|
||||
'product_id': product.id,
|
||||
'product_uom': default_uom_po_id,
|
||||
'price_unit': res['price_unit'],
|
||||
'date_planned': res['date_planned'],
|
||||
'price_unit': price_unit,
|
||||
'date_planned': date_planned,
|
||||
'taxes_id': [(6, 0, taxes_id)],
|
||||
'account_analytic_id': requisition_line.account_analytic_id.id,
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ class procurement_order(osv.osv):
|
||||
days = orderpoint.lead_days or 0.0
|
||||
if orderpoint.lead_type=='purchase':
|
||||
# These days will be substracted when creating the PO
|
||||
days += orderpoint.product_id.selected_seller_id.delay or 0.0
|
||||
days += orderpoint.product_id._select_seller(orderpoint.product_id).delay or 0.0
|
||||
date_planned = start_date + relativedelta(days=days)
|
||||
return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user