2018-04-11 13:36:23 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Part of flectra. See LICENSE file for full copyright and licensing details.
|
|
|
|
|
|
|
|
from flectra import api, fields, models
|
|
|
|
from flectra.exceptions import UserError
|
|
|
|
from itertools import chain
|
2018-05-10 14:21:12 +02:00
|
|
|
from flectra.tools import pycompat
|
2018-04-11 13:36:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Pricelist(models.Model):
|
|
|
|
_inherit = "product.pricelist"
|
|
|
|
|
|
|
|
pricelist_type = fields.Selection(
|
|
|
|
[('basic', 'Basic'),
|
|
|
|
('advance', 'Advanced'),
|
|
|
|
], 'Pricelist Type', default='basic', required=True)
|
|
|
|
apply_method = fields.Selection(
|
|
|
|
[('first_matched_rule', 'Apply First Matched Rule'),
|
|
|
|
('all_matched_rules', 'Apply All Matched Rules'),
|
|
|
|
('smallest_discount', 'Apply Smallest Matched Discount'),
|
|
|
|
('biggest_discount', 'Apply Biggest Matched Discount')
|
|
|
|
], 'Apply Method', default='first_matched_rule', required=True)
|
|
|
|
rule_ids = fields.One2many(
|
|
|
|
'price.rule', 'pricelist_id', 'Price Rules',
|
|
|
|
copy=True)
|
|
|
|
cart_rule_ids = fields.One2many(
|
|
|
|
'cart.rule', 'pricelist_id', 'Cart Rules Items',
|
|
|
|
copy=True)
|
|
|
|
apply_coupon_code = fields.Boolean('Apply Coupon Code?')
|
|
|
|
coupon_code_lines = fields.One2many(
|
|
|
|
'coupon.code', 'pricelist_id', 'Coupon Code Items',
|
|
|
|
copy=True)
|
|
|
|
|
2018-05-10 14:21:12 +02:00
|
|
|
def get_product_price_rule_advance(
|
2018-04-11 13:36:23 +02:00
|
|
|
self, product, quantity, partner,
|
2018-05-10 14:21:12 +02:00
|
|
|
date=False, uom_id=False):
|
2018-04-11 13:36:23 +02:00
|
|
|
self.ensure_one()
|
2018-05-10 14:21:12 +02:00
|
|
|
return self._compute_price_rule_advance(
|
2018-04-11 13:36:23 +02:00
|
|
|
[(product, quantity, partner)],
|
2018-05-10 14:21:12 +02:00
|
|
|
date=date, uom_id=uom_id)[product.id]
|
2018-04-11 13:36:23 +02:00
|
|
|
|
|
|
|
@api.multi
|
2018-05-10 14:21:12 +02:00
|
|
|
def _compute_price_rule_advance(self, products_qty_partner,
|
2018-04-11 13:36:23 +02:00
|
|
|
date=False, uom_id=False):
|
|
|
|
self.ensure_one()
|
|
|
|
if not date:
|
|
|
|
date = fields.Datetime.now()
|
|
|
|
if not uom_id and self._context.get('uom'):
|
|
|
|
uom_id = self._context['uom']
|
|
|
|
if uom_id:
|
|
|
|
products = [item[0].with_context(
|
|
|
|
uom=uom_id) for item in products_qty_partner]
|
|
|
|
products_qty_partner = [(products[index], data_struct[1],
|
|
|
|
data_struct[2])
|
|
|
|
for index, data_struct in
|
|
|
|
enumerate(products_qty_partner)]
|
|
|
|
else:
|
|
|
|
products = [item[0] for item in products_qty_partner]
|
|
|
|
|
|
|
|
if not products:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
categ_ids = {}
|
|
|
|
for p in products:
|
|
|
|
categ = p.categ_id
|
|
|
|
while categ:
|
|
|
|
categ_ids[categ.id] = True
|
|
|
|
categ = categ.parent_id
|
|
|
|
categ_ids = list(categ_ids)
|
|
|
|
|
|
|
|
is_product_template = products[0]._name == "product.template"
|
|
|
|
if is_product_template:
|
|
|
|
prod_tmpl_ids = [tmpl.id for tmpl in products]
|
|
|
|
prod_ids = [p.id for p in
|
|
|
|
list(chain.from_iterable(
|
|
|
|
[t.product_variant_ids for t in products]))]
|
|
|
|
else:
|
|
|
|
prod_ids = [product.id for product in products]
|
|
|
|
prod_tmpl_ids = [
|
|
|
|
product.product_tmpl_id.id for product in products]
|
|
|
|
self._cr.execute(
|
|
|
|
'SELECT item.id '
|
|
|
|
'FROM rule_line AS item '
|
|
|
|
'LEFT JOIN product_category AS categ '
|
|
|
|
'ON item.categ_id = categ.id '
|
|
|
|
'WHERE (item.product_tmpl_id IS NULL '
|
|
|
|
'OR item.product_tmpl_id = any(%s))'
|
|
|
|
'AND (item.price_rule_id = any(%s))'
|
|
|
|
'AND (item.product_id IS NULL OR item.product_id = any(%s))'
|
|
|
|
'AND (item.categ_id IS NULL OR item.categ_id = any(%s)) '
|
|
|
|
'AND (item.pricelist_id = %s) '
|
|
|
|
'AND (item.start_date IS NULL OR item.start_date<=%s) '
|
|
|
|
'AND (item.end_date IS NULL OR item.end_date>=%s)'
|
2018-05-10 14:21:12 +02:00
|
|
|
'ORDER BY item.sequence,item.id,categ.parent_left desc',
|
|
|
|
(prod_tmpl_ids, self.rule_ids.ids, prod_ids,
|
2018-04-11 13:36:23 +02:00
|
|
|
categ_ids, self.id, date, date))
|
|
|
|
item_ids = [x[0] for x in self._cr.fetchall()]
|
|
|
|
items = self.env['rule.line'].browse(item_ids)
|
|
|
|
results = {}
|
|
|
|
coupon_obj = self.env['coupon.code']
|
|
|
|
partner_obj = self.env['res.partner']
|
|
|
|
for product, qty, partner in products_qty_partner:
|
|
|
|
results[product.id] = 0.0
|
|
|
|
suitable_rule = False
|
|
|
|
qty_uom_id = self._context.get('uom') or product.uom_id.id
|
|
|
|
qty_in_product_uom = qty
|
|
|
|
if qty_uom_id != product.uom_id.id:
|
|
|
|
try:
|
|
|
|
qty_in_product_uom = \
|
|
|
|
self.env['product.uom'].browse(
|
|
|
|
[self._context['uom']])._compute_quantity(
|
|
|
|
qty, product.uom_id)
|
|
|
|
except UserError:
|
|
|
|
pass
|
|
|
|
price = product.price_compute('list_price')[product.id]
|
|
|
|
one_dis_price = all_dis_price = 0.0
|
|
|
|
max_dis_price = []
|
|
|
|
min_dis_price = []
|
|
|
|
partner_id = partner
|
|
|
|
if isinstance(partner, int):
|
|
|
|
partner_id = partner_obj.browse(partner)
|
|
|
|
for rule in items:
|
|
|
|
if rule.min_qty and qty_in_product_uom < rule.min_qty:
|
|
|
|
continue
|
|
|
|
if rule.max_qty and qty_in_product_uom > rule.max_qty:
|
|
|
|
continue
|
|
|
|
if rule.model_id:
|
|
|
|
check = coupon_obj.check_condition(rule, partner_id)
|
|
|
|
if check:
|
|
|
|
continue
|
|
|
|
if is_product_template:
|
|
|
|
if rule.product_tmpl_id and \
|
|
|
|
product.id != rule.product_tmpl_id.id:
|
|
|
|
continue
|
|
|
|
if rule.product_id and not (
|
|
|
|
product.product_variant_count == 1 and
|
|
|
|
product.product_variant_id.id ==
|
|
|
|
rule.product_id.id):
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
if rule.product_tmpl_id and \
|
|
|
|
product.product_tmpl_id.id != \
|
|
|
|
rule.product_tmpl_id.id:
|
|
|
|
continue
|
|
|
|
if rule.product_id and product.id != rule.product_id.id:
|
|
|
|
continue
|
|
|
|
if rule.categ_id:
|
|
|
|
cat = product.categ_id
|
|
|
|
while cat:
|
|
|
|
if cat.id == rule.categ_id.id:
|
|
|
|
break
|
|
|
|
cat = cat.parent_id
|
|
|
|
if not cat:
|
|
|
|
continue
|
|
|
|
dis_price = 0.0
|
|
|
|
if price is not False:
|
|
|
|
if rule.rule_type == 'fixed_amount':
|
2018-05-10 14:21:12 +02:00
|
|
|
price_unit = self._context.get('price_unit')
|
|
|
|
if price_unit and price != price_unit \
|
|
|
|
and self.discount_policy == 'without_discount':
|
2018-04-11 13:36:23 +02:00
|
|
|
price = price_unit
|
2018-05-10 14:21:12 +02:00
|
|
|
if price <= rule.discount_amount \
|
|
|
|
and self.apply_method != 'smallest_discount':
|
2018-04-11 13:36:23 +02:00
|
|
|
price = 0
|
|
|
|
suitable_rule = rule
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
dis_price = price - rule.discount_amount
|
|
|
|
elif rule.rule_type == 'percent':
|
|
|
|
dis_price = (price - (price * (
|
|
|
|
rule.discount_amount / 100))) or 0.0
|
|
|
|
suitable_rule = rule
|
|
|
|
if self.apply_method == 'first_matched_rule':
|
|
|
|
one_dis_price = dis_price
|
|
|
|
break
|
|
|
|
elif self.apply_method == 'all_matched_rules':
|
|
|
|
all_dis_price += price - dis_price
|
|
|
|
elif self.apply_method == 'smallest_discount':
|
|
|
|
min_dis_price.append(price - dis_price)
|
|
|
|
else:
|
|
|
|
max_dis_price.append(price - dis_price)
|
2018-05-10 14:21:12 +02:00
|
|
|
|
|
|
|
# Used context for add Cart Rules Discount
|
|
|
|
cart_price = 0.0
|
|
|
|
if self._context.get('order_id', False):
|
|
|
|
order_id = self._context.get('order_id')
|
|
|
|
cart_per = order_id.get_cart_rules_discount(
|
|
|
|
order_id.get_values())
|
|
|
|
cart_price = price * (cart_per / 100) or 0.0
|
2018-04-11 13:36:23 +02:00
|
|
|
if one_dis_price > 0.0:
|
|
|
|
price = one_dis_price
|
|
|
|
elif all_dis_price > 0.0:
|
|
|
|
price = price - all_dis_price
|
|
|
|
elif min_dis_price:
|
|
|
|
price = price - min(min_dis_price)
|
|
|
|
elif max_dis_price:
|
|
|
|
price = price - max(max_dis_price)
|
2018-05-10 14:21:12 +02:00
|
|
|
if cart_price > 0.0:
|
|
|
|
price -= cart_price
|
2018-04-11 13:36:23 +02:00
|
|
|
price = product.currency_id.compute(
|
|
|
|
price, self.currency_id, round=False)
|
|
|
|
results[product.id] = (price,
|
|
|
|
suitable_rule and suitable_rule.id or False)
|
|
|
|
return results
|
2018-05-10 14:21:12 +02:00
|
|
|
|
|
|
|
# Used context for add Cart Rules Discount
|
|
|
|
def get_products_price_advance(self, products, quantities,
|
|
|
|
partners, date=False, uom_id=False):
|
|
|
|
""" For a given pricelist, return price for products
|
|
|
|
Returns: dict{product_id: product price}, in the given pricelist """
|
|
|
|
self.ensure_one()
|
|
|
|
vals = {
|
|
|
|
product_id: res_tuple[0]
|
|
|
|
for product_id, res_tuple in self._compute_price_rule_advance(
|
|
|
|
list(pycompat.izip(products, quantities, partners)),
|
|
|
|
date=date, uom_id=uom_id).items()
|
|
|
|
}
|
|
|
|
return vals
|
|
|
|
|
|
|
|
|
|
|
|
class ProductProduct(models.Model):
|
|
|
|
_inherit = "product.product"
|
|
|
|
|
|
|
|
# Overrides Function
|
|
|
|
# Used context for add Cart Rules Discount
|
|
|
|
def _compute_product_price(self):
|
|
|
|
prices = {}
|
|
|
|
pricelist_id_or_name = self._context.get('pricelist')
|
|
|
|
if pricelist_id_or_name:
|
|
|
|
pricelist = None
|
|
|
|
partner = self._context.get('partner', False)
|
|
|
|
quantity = self._context.get('quantity', 1.0)
|
|
|
|
if isinstance(pricelist_id_or_name, pycompat.string_types):
|
|
|
|
pricelist_name_search = \
|
|
|
|
self.env['product.pricelist'].name_search(
|
|
|
|
pricelist_id_or_name, operator='=', limit=1)
|
|
|
|
if pricelist_name_search:
|
|
|
|
pricelist = \
|
|
|
|
self.env['product.pricelist'].browse(
|
|
|
|
[pricelist_name_search[0][0]])
|
|
|
|
elif isinstance(pricelist_id_or_name, pycompat.integer_types):
|
|
|
|
pricelist = self.env['product.pricelist'].browse(
|
|
|
|
pricelist_id_or_name)
|
|
|
|
|
|
|
|
if pricelist:
|
|
|
|
quantities = [quantity] * len(self)
|
|
|
|
partners = [partner] * len(self)
|
|
|
|
if pricelist.pricelist_type == 'basic':
|
|
|
|
prices = pricelist.get_products_price(
|
|
|
|
self, quantities, partners)
|
|
|
|
else:
|
|
|
|
prices = pricelist.with_context(
|
|
|
|
{'order_id': self._context.get('order_id')}
|
|
|
|
).get_products_price_advance(
|
|
|
|
self, quantities, partners)
|
|
|
|
for product in self:
|
|
|
|
product.price = prices.get(product.id, 0.0)
|
|
|
|
if self._context.get('order_id', False):
|
|
|
|
return product.price
|