flectra/addons/sale_advance_pricelist/models/pricelist.py

260 lines
11 KiB
Python

# -*- 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
from flectra.tools import pycompat
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)
def get_product_price_rule_advance(
self, product, quantity, partner,
date=False, uom_id=False):
self.ensure_one()
return self._compute_price_rule_advance(
[(product, quantity, partner)],
date=date, uom_id=uom_id)[product.id]
@api.multi
def _compute_price_rule_advance(self, products_qty_partner,
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)'
'ORDER BY item.sequence,item.id,categ.parent_left desc',
(prod_tmpl_ids, self.rule_ids.ids, prod_ids,
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':
price_unit = self._context.get('price_unit')
if price_unit and price != price_unit \
and self.discount_policy == 'without_discount':
price = price_unit
if price <= rule.discount_amount \
and self.apply_method != 'smallest_discount':
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)
# 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
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)
if cart_price > 0.0:
price -= cart_price
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
# 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