def apply(self, basket, condition, offer, discount_amount=None, max_total_discount=None): if discount_amount is None: discount_amount = self.value # Fetch basket lines that are in the range and available to be used in # an offer. line_tuples = self.get_applicable_lines(offer, basket) # Determine which lines can have the discount applied to them max_affected_items = self._effective_max_affected_items() num_affected_items = 0 affected_items_total = D('0.00') lines_to_discount = [] for price, line in line_tuples: if num_affected_items >= max_affected_items: break qty = min(line.quantity_without_discount, max_affected_items - num_affected_items) lines_to_discount.append((line, price, qty)) num_affected_items += qty affected_items_total += qty * price # Ensure we don't try to apply a discount larger than the total of the # matching items. discount = min(discount_amount, affected_items_total) if max_total_discount is not None: discount = min(discount, max_total_discount) if discount == 0: return results.ZERO_DISCOUNT # Apply discount equally amongst them affected_lines = [] applied_discount = D('0.00') for i, (line, price, qty) in enumerate(lines_to_discount): if i == len(lines_to_discount) - 1: # If last line, then take the delta as the discount to ensure # the total discount is correct and doesn't mismatch due to # rounding. line_discount = discount - applied_discount else: # Calculate a weighted discount for the line line_discount = self.round( ((price * qty) / affected_items_total) * discount) apply_discount(line, line_discount, qty) affected_lines.append((line, line_discount, qty)) applied_discount += line_discount condition.consume_items(offer, basket, affected_lines) return results.BasketDiscount(discount)
def apply(self, basket, condition, offer): line_tuples = self.get_applicable_lines(offer, basket) if not line_tuples: return results.ZERO_DISCOUNT # Cheapest line gives free product discount, line = line_tuples[0] apply_discount(line, discount, 1) affected_lines = [(line, discount, 1)] condition.consume_items(offer, basket, affected_lines) return results.BasketDiscount(discount)
def apply(self, basket, condition, offer): # noqa (too complex (10)) if isinstance(condition, conditions.ValueCondition): return results.ZERO_DISCOUNT # Fetch basket lines that are in the range and available to be used in # an offer. line_tuples = self.get_applicable_lines(offer, basket, range=condition.range) if not line_tuples: return results.ZERO_DISCOUNT # Determine the lines to consume num_permitted = int(condition.value) num_affected = 0 value_affected = D('0.00') covered_lines = [] for price, line in line_tuples: if isinstance(condition, conditions.CoverageCondition): quantity_affected = 1 else: quantity_affected = min( line.quantity_without_offer_discount(offer), num_permitted - num_affected) num_affected += quantity_affected value_affected += quantity_affected * price covered_lines.append((price, line, quantity_affected)) if num_affected >= num_permitted: break discount = max(value_affected - self.value, D('0.00')) if not discount: return results.ZERO_DISCOUNT # Apply discount to the affected lines discount_applied = D('0.00') last_line = covered_lines[-1][1] for price, line, quantity in covered_lines: if line == last_line: # If last line, we just take the difference to ensure that # rounding doesn't lead to an off-by-one error line_discount = discount - discount_applied else: line_discount = self.round(discount * (price * quantity) / value_affected) apply_discount(line, line_discount, quantity, offer) discount_applied += line_discount return results.BasketDiscount(discount)
def apply(self, basket, condition, offer, discount_percent=None, max_total_discount=None): if discount_percent is None: discount_percent = self.value discount_amount_available = max_total_discount line_tuples = self.get_applicable_lines(offer, basket) discount_percent = min(discount_percent, D('100.0')) discount = D('0.00') affected_items = 0 max_affected_items = self._effective_max_affected_items() affected_lines = [] for price, line in line_tuples: if affected_items >= max_affected_items: break if discount_amount_available == 0: break quantity_affected = min( line.quantity_without_offer_discount(offer), max_affected_items - affected_items) line_discount = self.round(discount_percent / D('100.0') * price * int(quantity_affected)) if discount_amount_available is not None: line_discount = min(line_discount, discount_amount_available) discount_amount_available -= line_discount apply_discount(line, line_discount, quantity_affected, offer) affected_lines.append((line, line_discount, quantity_affected)) affected_items += quantity_affected discount += line_discount if discount > 0: condition.consume_items(offer, basket, affected_lines) return results.BasketDiscount(discount)