Pārlūkot izejas kodu

Implemented LineDiscountRegistry

master
Lars van de Kerkhof 2 gadus atpakaļ
vecāks
revīzija
9902021aad

+ 34
- 34
src/oscar/apps/basket/abstract_models.py Parādīt failu

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

+ 53
- 1
src/oscar/apps/basket/utils.py Parādīt failu

1
-from collections import defaultdict
1
+from collections import defaultdict, namedtuple
2
 
2
 
3
 from django.contrib import messages
3
 from django.contrib import messages
4
 from django.template.loader import render_to_string
4
 from django.template.loader import render_to_string
5
 
5
 
6
 from oscar.core.loading import get_class, get_model
6
 from oscar.core.loading import get_class, get_model
7
+from oscar.core.decorators import deprecated
7
 
8
 
8
 Applicator = get_class("offer.applicator", "Applicator")
9
 Applicator = get_class("offer.applicator", "Applicator")
9
 ConditionalOffer = get_model("offer", "ConditionalOffer")
10
 ConditionalOffer = get_model("offer", "ConditionalOffer")
126
             self._consumptions[offer.pk] += num_consumed
127
             self._consumptions[offer.pk] += num_consumed
127
         return num_consumed
128
         return num_consumed
128
 
129
 
130
+    @deprecated
129
     def consumed(self, offer=None):
131
     def consumed(self, offer=None):
132
+        return self.num_consumed(offer)
133
+
134
+    def num_consumed(self, offer=None):
130
         """
135
         """
131
         check how many items on this line have been
136
         check how many items on this line have been
132
         consumed by an offer
137
         consumed by an offer
193
                     return 0
198
                     return 0
194
 
199
 
195
         return max_affected_items - self.consumed(offer)
200
         return max_affected_items - self.consumed(offer)
201
+
202
+
203
+DiscountApplication = namedtuple(
204
+    "DiscountApplication", ["amount", "quantity", "incl_tax", "offer"]
205
+)
206
+
207
+
208
+class LineDiscountRegistry(LineOfferConsumer):
209
+    def __init__(self, line):
210
+        super().__init__(line)
211
+        self._discounts = []
212
+        self._discount_excl_tax = None
213
+        self._discount_incl_tax = None
214
+
215
+    def discount(self, amount, quantity, incl_tax=True, offer=None):
216
+        self._discounts.append(DiscountApplication(amount, quantity, incl_tax, offer))
217
+        self.consume(quantity, offer=offer)
218
+        if incl_tax:
219
+            self._discount_incl_tax = None
220
+        else:
221
+            self._discount_excl_tax = None
222
+
223
+    @property
224
+    def excl_tax(self):
225
+        if self._discount_excl_tax is None:
226
+            self._discount_excl_tax = sum(
227
+                [d.amount for d in self._discounts if not d.incl_tax], 0
228
+            )
229
+        return self._discount_excl_tax
230
+
231
+    @property
232
+    def incl_tax(self):
233
+        if self._discount_incl_tax is None:
234
+            self._discount_incl_tax = sum(
235
+                [d.amount for d in self._discounts if d.incl_tax], 0
236
+            )
237
+        return self._discount_incl_tax
238
+
239
+    @property
240
+    def total(self):
241
+        return sum([d.amount for d in self._discounts], 0)
242
+
243
+    def all(self):
244
+        return self._discounts
245
+
246
+    def __iter__(self):
247
+        return iter(self._discounts)

Notiek ielāde…
Atcelt
Saglabāt