|
|
@@ -14,12 +14,13 @@ from django.utils.translation import gettext_lazy as _
|
|
14
|
14
|
from oscar.core.compat import AUTH_USER_MODEL
|
|
15
|
15
|
from oscar.core.loading import get_class, get_classes
|
|
16
|
16
|
from oscar.core.utils import get_default_currency, round_half_up
|
|
|
17
|
+from oscar.core.decorators import deprecated
|
|
17
|
18
|
from oscar.models.fields.slugfield import SlugField
|
|
18
|
19
|
from oscar.templatetags.currency_filters import currency
|
|
19
|
20
|
|
|
20
|
21
|
OfferApplications = get_class("offer.results", "OfferApplications")
|
|
21
|
22
|
Unavailable = get_class("partner.availability", "Unavailable")
|
|
22
|
|
-LineOfferConsumer = get_class("basket.utils", "LineOfferConsumer")
|
|
|
23
|
+LineDiscountRegistry = get_class("basket.utils", "LineDiscountRegistry")
|
|
23
|
24
|
OpenBasketManager, SavedBasketManager = get_classes(
|
|
24
|
25
|
"basket.managers", ["OpenBasketManager", "SavedBasketManager"]
|
|
25
|
26
|
)
|
|
|
@@ -727,10 +728,9 @@ class AbstractLine(models.Model):
|
|
727
|
728
|
def __init__(self, *args, **kwargs):
|
|
728
|
729
|
super().__init__(*args, **kwargs)
|
|
729
|
730
|
# Instance variables used to persist discount information
|
|
730
|
|
- self.discounts = []
|
|
731
|
731
|
# self._discount_excl_tax = D("0.00")
|
|
732
|
732
|
# self._discount_incl_tax = D("0.00")
|
|
733
|
|
- self.consumer = LineOfferConsumer(self)
|
|
|
733
|
+ self.discounts = LineDiscountRegistry(self)
|
|
734
|
734
|
|
|
735
|
735
|
class Meta:
|
|
736
|
736
|
abstract = True
|
|
|
@@ -741,6 +741,11 @@ class AbstractLine(models.Model):
|
|
741
|
741
|
verbose_name = _("Basket line")
|
|
742
|
742
|
verbose_name_plural = _("Basket lines")
|
|
743
|
743
|
|
|
|
744
|
+ @property
|
|
|
745
|
+ @deprecated
|
|
|
746
|
+ def consumer(self):
|
|
|
747
|
+ return self.discounts
|
|
|
748
|
+
|
|
744
|
749
|
def __str__(self):
|
|
745
|
750
|
return _(
|
|
746
|
751
|
"Basket #%(basket_id)d, Product #%(product_id)d, quantity %(quantity)d"
|
|
|
@@ -765,10 +770,7 @@ class AbstractLine(models.Model):
|
|
765
|
770
|
"""
|
|
766
|
771
|
Remove any discounts from this line.
|
|
767
|
772
|
"""
|
|
768
|
|
- self.discounts = []
|
|
769
|
|
- # self._discount_excl_tax = D("0.00")
|
|
770
|
|
- # self._discount_incl_tax = D("0.00")
|
|
771
|
|
- self.consumer = LineOfferConsumer(self)
|
|
|
773
|
+ self.discounts = LineDiscountRegistry(self)
|
|
772
|
774
|
|
|
773
|
775
|
def discount(self, discount_value, affected_quantity, incl_tax=True, offer=None):
|
|
774
|
776
|
"""
|
|
|
@@ -786,8 +788,9 @@ class AbstractLine(models.Model):
|
|
786
|
788
|
"Attempting to discount the tax-exclusive price of a line "
|
|
787
|
789
|
"when tax-inclusive discounts are already applied"
|
|
788
|
790
|
)
|
|
789
|
|
- self.discounts.append((discount_value, affected_quantity, incl_tax, offer))
|
|
790
|
|
- self.consume(affected_quantity, offer=offer)
|
|
|
791
|
+ self.discounts.discount(discount_value, affected_quantity, incl_tax, offer)
|
|
|
792
|
+ # self.discounts.append((discount_value, affected_quantity, incl_tax, offer))
|
|
|
793
|
+ # self.consume(affected_quantity, offer=offer)
|
|
791
|
794
|
|
|
792
|
795
|
def consume(self, quantity, offer=None):
|
|
793
|
796
|
"""
|
|
|
@@ -795,7 +798,7 @@ class AbstractLine(models.Model):
|
|
795
|
798
|
|
|
796
|
799
|
Consumed items are no longer available to be used in offers.
|
|
797
|
800
|
"""
|
|
798
|
|
- return self.consumer.consume(quantity, offer=offer)
|
|
|
801
|
+ return self.discounts.consume(quantity, offer=offer)
|
|
799
|
802
|
|
|
800
|
803
|
def get_price_breakdown(self):
|
|
801
|
804
|
"""
|
|
|
@@ -816,14 +819,16 @@ class AbstractLine(models.Model):
|
|
816
|
819
|
else:
|
|
817
|
820
|
# Need to split the discount among the affected quantity
|
|
818
|
821
|
# of products.
|
|
819
|
|
- item_incl_tax_discount = self.discount_value / int(self.consumer.consumed())
|
|
|
822
|
+ item_incl_tax_discount = self.discount_value / int(
|
|
|
823
|
+ self.discounts.num_consumed()
|
|
|
824
|
+ )
|
|
820
|
825
|
item_excl_tax_discount = item_incl_tax_discount * self._tax_ratio
|
|
821
|
826
|
item_excl_tax_discount = round_half_up(item_excl_tax_discount)
|
|
822
|
827
|
prices.append(
|
|
823
|
828
|
(
|
|
824
|
829
|
self.unit_price_incl_tax - item_incl_tax_discount,
|
|
825
|
830
|
self.unit_price_excl_tax - item_excl_tax_discount,
|
|
826
|
|
- self.consumer.consumed(),
|
|
|
831
|
+ self.discounts.num_consumed(),
|
|
827
|
832
|
)
|
|
828
|
833
|
)
|
|
829
|
834
|
if self.quantity_without_discount:
|
|
|
@@ -851,16 +856,16 @@ class AbstractLine(models.Model):
|
|
851
|
856
|
# ===============
|
|
852
|
857
|
|
|
853
|
858
|
def has_offer_discount(self, offer):
|
|
854
|
|
- return self.consumer.consumed(offer) > 0
|
|
|
859
|
+ return self.discounts.num_consumed(offer) > 0
|
|
855
|
860
|
|
|
856
|
861
|
def quantity_with_offer_discount(self, offer):
|
|
857
|
|
- return self.consumer.consumed(offer)
|
|
|
862
|
+ return self.discounts.num_consumed(offer)
|
|
858
|
863
|
|
|
859
|
864
|
def quantity_without_offer_discount(self, offer):
|
|
860
|
|
- return self.consumer.available(offer)
|
|
|
865
|
+ return self.discounts.available(offer)
|
|
861
|
866
|
|
|
862
|
867
|
def is_available_for_offer_discount(self, offer):
|
|
863
|
|
- return self.consumer.available(offer) > 0
|
|
|
868
|
+ return self.discounts.available(offer) > 0
|
|
864
|
869
|
|
|
865
|
870
|
def quantity_available_for_offer(self, offer):
|
|
866
|
871
|
return self.quantity_without_offer_discount(
|
|
|
@@ -872,16 +877,18 @@ class AbstractLine(models.Model):
|
|
872
|
877
|
# ==========
|
|
873
|
878
|
|
|
874
|
879
|
@property
|
|
|
880
|
+ @deprecated
|
|
875
|
881
|
def _discount_incl_tax(self):
|
|
876
|
|
- return sum([discount[0] for discount in self.discounts if discount[2]], 0)
|
|
|
882
|
+ return self.discounts.incl_tax
|
|
877
|
883
|
|
|
878
|
884
|
@_discount_incl_tax.setter
|
|
879
|
885
|
def _discount_incl_tax(self, value):
|
|
880
|
886
|
raise Exception("_discount_incl_tax kan je niet setten")
|
|
881
|
887
|
|
|
882
|
888
|
@property
|
|
|
889
|
+ @deprecated
|
|
883
|
890
|
def _discount_excl_tax(self):
|
|
884
|
|
- return sum([discount[0] for discount in self.discounts if not discount[2]], 0)
|
|
|
891
|
+ return self.discounts.excl_tax
|
|
885
|
892
|
|
|
886
|
893
|
@_discount_excl_tax.setter
|
|
887
|
894
|
def _discount_excl_tax(self, value):
|
|
|
@@ -889,19 +896,20 @@ class AbstractLine(models.Model):
|
|
889
|
896
|
|
|
890
|
897
|
@property
|
|
891
|
898
|
def has_discount(self):
|
|
892
|
|
- return bool(self.consumer.consumed())
|
|
|
899
|
+ return bool(self.discounts.num_consumed())
|
|
893
|
900
|
|
|
894
|
901
|
@property
|
|
895
|
902
|
def quantity_with_discount(self):
|
|
896
|
|
- return self.consumer.consumed()
|
|
|
903
|
+ return self.discounts.num_consumed()
|
|
897
|
904
|
|
|
898
|
905
|
@property
|
|
899
|
906
|
def quantity_without_discount(self):
|
|
900
|
|
- return self.consumer.available()
|
|
|
907
|
+ return self.discounts.available()
|
|
901
|
908
|
|
|
902
|
909
|
@property
|
|
903
|
910
|
def discount_value(self):
|
|
904
|
|
- return sum([discount[0] for discount in self.discounts], 0)
|
|
|
911
|
+ return self.discounts.total
|
|
|
912
|
+ # return sum([discount[0] for discount in self.discounts], 0)
|
|
905
|
913
|
# Only one of the incl- and excl- discounts should be non-zero
|
|
906
|
914
|
# return max(self._discount_incl_tax, self._discount_excl_tax)
|
|
907
|
915
|
|
|
|
@@ -949,12 +957,8 @@ class AbstractLine(models.Model):
|
|
949
|
957
|
if self.line_price_excl_tax is None:
|
|
950
|
958
|
return None
|
|
951
|
959
|
|
|
952
|
|
- excl_tax_discounts = sum(
|
|
953
|
|
- [discount[0] for discount in self.discounts if not discount[2]], 0
|
|
954
|
|
- )
|
|
955
|
|
- incl_tax_discounts = sum(
|
|
956
|
|
- [discount[0] for discount in self.discounts if discount[2]], 0
|
|
957
|
|
- )
|
|
|
960
|
+ excl_tax_discounts = self.discounts.excl_tax
|
|
|
961
|
+ incl_tax_discounts = self.discounts.incl_tax
|
|
958
|
962
|
|
|
959
|
963
|
if excl_tax_discounts and self.line_price_excl_tax is not None:
|
|
960
|
964
|
return max(0, self.line_price_excl_tax - excl_tax_discounts)
|
|
|
@@ -970,12 +974,8 @@ class AbstractLine(models.Model):
|
|
970
|
974
|
|
|
971
|
975
|
@property
|
|
972
|
976
|
def line_price_incl_tax_incl_discounts(self):
|
|
973
|
|
- excl_tax_discounts = sum(
|
|
974
|
|
- [discount[0] for discount in self.discounts if not discount[2]], 0
|
|
975
|
|
- )
|
|
976
|
|
- incl_tax_discounts = sum(
|
|
977
|
|
- [discount[0] for discount in self.discounts if discount[2]], 0
|
|
978
|
|
- )
|
|
|
977
|
+ excl_tax_discounts = self.discounts.excl_tax
|
|
|
978
|
+ incl_tax_discounts = self.discounts.incl_tax
|
|
979
|
979
|
|
|
980
|
980
|
# We use whichever discount value is set. If the discount value was
|
|
981
|
981
|
# calculated against the tax-exclusive prices, then the line price
|