예제 #1
0
    def consume_items(self, offer, basket, affected_lines):
        """
        Marks items within the basket lines as consumed so they
        can't be reused in other offers.

        We allow lines to be passed in as sometimes we want them sorted
        in a specific order.
        """
        # Determine value of items already consumed as part of discount
        value_consumed = D('0.00')
        for line, __, qty in affected_lines:
            price = utils.unit_price(offer, line)
            value_consumed += price * qty

        to_consume = max(0, self.value - value_consumed)
        if to_consume == 0:
            return

        for price, line in self.get_applicable_lines(
                offer, basket, most_expensive_first=True):
            quantity_to_consume = min(
                line.quantity_without_offer_discount(offer),
                (to_consume / price).quantize(D(1), ROUND_UP))
            line.consume(quantity_to_consume, offer=offer)
            to_consume -= price * quantity_to_consume
            if to_consume <= 0:
                break
예제 #2
0
    def get_applicable_lines(self, offer, basket, range=None):
        """
        Return the basket lines that are available to be discounted

        :basket: The basket
        :range: The range of products to use for filtering.  The fixed-price
                benefit ignores its range and uses the condition range
        """
        if range is None:
            range = self.range
        line_tuples = []
        for line in basket.all_lines():
            product = line.product

            if (not range.contains(product)
                    or not self.can_apply_benefit(line)):
                continue

            price = utils.unit_price(offer, line)
            if not price:
                # Avoid zero price products
                continue
            if line.quantity_without_discount == 0:
                continue
            line_tuples.append((price, line))

        # We sort lines to be cheapest first to ensure consistent applications
        return sorted(line_tuples, key=operator.itemgetter(0))
예제 #3
0
    def consume_items(self, offer, basket, affected_lines):
        """
        Marks items within the basket lines as consumed so they
        can't be reused in other offers.

        We allow lines to be passed in as sometimes we want them sorted
        in a specific order.
        """
        # Determine value of items already consumed as part of discount
        value_consumed = D('0.00')
        for line, __, qty in affected_lines:
            price = utils.unit_price(offer, line)
            value_consumed += price * qty

        to_consume = max(0, self.value - value_consumed)
        if to_consume == 0:
            return

        for price, line in self.get_applicable_lines(
                offer, basket, most_expensive_first=True):
            quantity_to_consume = min(
                line.quantity_without_discount,
                (to_consume / price).quantize(D(1), ROUND_UP))
            line.consume(quantity_to_consume)
            to_consume -= price * quantity_to_consume
            if to_consume <= 0:
                break
예제 #4
0
    def get_applicable_lines(self, offer, basket, range=None):
        """
        Return the basket lines that are available to be discounted

        :basket: The basket
        :range: The range of products to use for filtering.  The fixed-price
                benefit ignores its range and uses the condition range
        """
        if range is None:
            range = self.range
        line_tuples = []
        for line in basket.all_lines():
            product = line.product

            if (not range.contains(product) or
                    not self.can_apply_benefit(line)):
                continue

            price = utils.unit_price(offer, line)
            if not price:
                # Avoid zero price products
                continue
            if line.quantity_without_offer_discount(offer) == 0:
                continue
            line_tuples.append((price, line))

        # We sort lines to be cheapest first to ensure consistent applications
        return sorted(line_tuples, key=operator.itemgetter(0))
예제 #5
0
 def _get_value_of_matches(self, offer, basket):
     if hasattr(self, "_value_of_matches"):
         return getattr(self, "_value_of_matches")
     value_of_matches = D("0.00")
     for line in basket.all_lines():
         if self.can_apply_condition(line) and line.quantity_without_discount > 0:
             price = utils.unit_price(offer, line)
             value_of_matches += price * int(line.quantity_without_discount)
     self._value_of_matches = value_of_matches
     return value_of_matches
예제 #6
0
 def get_value_of_satisfying_items(self, offer, basket):
     covered_ids = []
     value = D("0.00")
     for line in basket.all_lines():
         if self.can_apply_condition(line) and line.product.id not in covered_ids:
             covered_ids.append(line.product.id)
             value += utils.unit_price(offer, line)
         if len(covered_ids) >= self.value:
             return value
     return value
예제 #7
0
 def get_value_of_satisfying_items(self, offer, basket):
     covered_ids = []
     value = D('0.00')
     for line in basket.all_lines():
         if (self.can_apply_condition(line)
                 and line.product.id not in covered_ids):
             covered_ids.append(line.product.id)
             value += utils.unit_price(offer, line)
         if len(covered_ids) >= self.value:
             return value
     return value
예제 #8
0
 def _get_value_of_matches(self, offer, basket):
     if hasattr(self, '_value_of_matches'):
         return getattr(self, '_value_of_matches')
     value_of_matches = D('0.00')
     for line in basket.all_lines():
         if (self.can_apply_condition(line)
                 and line.quantity_without_discount > 0):
             price = utils.unit_price(offer, line)
             value_of_matches += price * int(line.quantity_without_discount)
     self._value_of_matches = value_of_matches
     return value_of_matches
예제 #9
0
    def is_satisfied(self, offer, basket):
        """
        Determine whether a given basket meets this condition
        """
        value_of_matches = D('0.00')
        for line in basket.all_lines():
            if (self.can_apply_condition(line)
                    and line.quantity_without_discount > 0):
                price = utils.unit_price(offer, line)
                value_of_matches += price * int(line.quantity_without_discount)

        return value_of_matches <= self.value
예제 #10
0
 def is_satisfied(self, offer, basket):
     """
     Determine whether a given basket meets this condition
     """
     value_of_matches = D("0.00")
     for line in basket.all_lines():
         if self.can_apply_condition(line) and line.quantity_without_discount > 0:
             price = utils.unit_price(offer, line)
             value_of_matches += price * int(line.quantity_without_discount)
         if value_of_matches >= self.value:
             return True
     return False
예제 #11
0
    def get_applicable_lines(self, offer, basket, most_expensive_first=True):
        """ Return line data for the lines that can be consumed by this condition. """
        line_tuples = []
        for line in basket.all_lines():
            if not self.can_apply_condition(line):
                continue

            price = oscar_utils.unit_price(offer, line)
            if not price:
                continue
            line_tuples.append((price, line))

        return sorted(line_tuples, reverse=most_expensive_first, key=operator.itemgetter(0))
예제 #12
0
 def _get_value_of_matches(self, offer, basket):
     if hasattr(self, '_value_of_matches'):
         return getattr(self, '_value_of_matches')
     value_of_matches = D('0.00')
     for line in basket.all_lines():
         if (self.can_apply_condition(line) and
                 line.quantity_without_offer_discount(offer) > 0):
             price = utils.unit_price(offer, line)
             value_of_matches += price * int(
                 line.quantity_without_offer_discount(offer)
             )
     self._value_of_matches = value_of_matches
     return value_of_matches
예제 #13
0
    def get_applicable_lines(self, offer, basket, most_expensive_first=True):
        """
        Return line data for the lines that can be consumed by this condition
        """
        line_tuples = []
        for line in basket.all_lines():
            if not self.can_apply_condition(line):
                continue

            price = utils.unit_price(offer, line)
            if not price:
                continue
            line_tuples.append((price, line))
        key = operator.itemgetter(0)
        if most_expensive_first:
            return sorted(line_tuples, reverse=True, key=key)
        return sorted(line_tuples, key=key)
예제 #14
0
 def _get_unit_price(self, offer, line):
     price = utils.unit_price(offer, line)
     if self._tax_inclusive and line.is_tax_known:
         price += line.unit_tax
     return price
예제 #15
0
 def _get_unit_price(self, offer, line):
     price = utils.unit_price(offer, line)
     if self._tax_inclusive and line.is_tax_known:
         price += line.unit_tax
     return price