github.com/ismailbayram/bigpicture@v0.0.0-20231225173155-e4b21f5efcff/internal/browser/pyproject/baskets/service.py (about) 1 from decimal import Decimal 2 from django.utils.translation import ugettext_lazy as _ 3 4 from django.db.models import Q, F 5 from django.db.transaction import atomic 6 7 from baskets.models import Basket, BasketItem, Campaign 8 from baskets.enums import BasketStatus 9 from baskets.exceptions import (PrimaryProductsQuantityMustOne, 10 BasketInvalidException, 11 BasketEmptyException, 12 BasketAmountLessThanZeroException) 13 from cars.exceptions import CustomerHasNoSelectedCarException 14 import cars.* 15 16 17 class BasketService: 18 def get_or_create_basket(self, customer_profile): 19 """ 20 :param customer_profile: CustomerProfile 21 :return: Basket 22 """ 23 if not customer_profile.selected_car: 24 raise CustomerHasNoSelectedCarException 25 try: 26 basket = Basket.objects.get(customer_profile=customer_profile, 27 status=BasketStatus.active, 28 car=customer_profile.selected_car) 29 self._check_basket_items(basket) 30 except Basket.DoesNotExist: 31 basket = Basket.objects.create(customer_profile=customer_profile, 32 status=BasketStatus.active, 33 car=customer_profile.selected_car) 34 return basket 35 36 def apply_discounts(self, basket): 37 """ 38 :param basket: Basket 39 :return: Basket 40 """ 41 self.clean_discounts(basket) 42 campaigns = Campaign.objects.actives() 43 for campaign in campaigns: 44 strategy = campaign.promotion_type.get_strategy(campaign=campaign, 45 basket=basket) 46 if strategy.check(): 47 strategy.apply() 48 else: 49 message = campaign.message.format(**{'remaining': strategy.remaining}) 50 basket.campaign_messages.append(message) 51 return basket 52 53 def _check_basket_items(self, basket): 54 """ 55 :param basket: Basket 56 :return: bool 57 """ 58 invalid_items = basket.basketitem_set.exclude(product__is_active=True, 59 product__store__is_active=True, 60 product__store__is_approved=True) 61 if invalid_items: 62 msg = _('Some services that are invalid have been removed from your basket: ') 63 64 for bi in invalid_items: 65 msg += bi.product.name + ', ' 66 bi.delete() 67 68 basket.warning_messages.append(msg) 69 70 return not invalid_items.exists() 71 72 def add_basket_item(self, basket, product): 73 """ 74 :param basket: Basket 75 :param product: Product 76 :return: BasketItem 77 """ 78 if not basket.is_empty and basket.basketitem_set.filter(~Q(product__store=product.store)).exists(): 79 self.clean_basket(basket) 80 81 try: 82 basket_item = basket.basketitem_set.get(product=product) 83 if basket_item.product.is_primary: 84 raise PrimaryProductsQuantityMustOne 85 basket_item.quantity = F('quantity') + 1 86 basket_item.save() 87 except BasketItem.DoesNotExist: 88 primary_count = basket.basketitem_set.filter(product__is_primary=True).count() 89 if primary_count > 0 and product.is_primary: 90 raise PrimaryProductsQuantityMustOne 91 basket_item = BasketItem.objects.create(basket=basket, product=product) 92 93 self._check_basket_items(basket) 94 return basket_item 95 96 def clean_discounts(self, basket): 97 """ 98 :param basket: Basket 99 :return: basket 100 """ 101 basket.campaign_messages = [] 102 basket.discountitem_set.all().delete() 103 return basket 104 105 def clean_basket(self, basket): 106 """ 107 :param basket: Basket 108 :return: Basket 109 """ 110 basket.basketitem_set.all().delete() 111 self.clean_discounts(basket) 112 return basket 113 114 def delete_basket_item(self, basket, product): 115 """ 116 :param basket: Basket 117 :param product: Product 118 :return: None 119 """ 120 basket.basketitem_set.filter(product=product).delete() 121 self._check_basket_items(basket) 122 123 @atomic 124 def complete_basket(self, basket): 125 """ 126 :param basket: Basket 127 :return: Basket 128 """ 129 if basket.is_empty: 130 raise BasketEmptyException 131 is_basket_valid = self._check_basket_items(basket) 132 if not is_basket_valid: 133 raise BasketInvalidException 134 if basket.get_net_amount() < Decimal('0.00'): 135 raise BasketAmountLessThanZeroException 136 137 for bi in basket.basketitem_set.all(): 138 bi.amount = bi.get_price() 139 bi.save() 140 basket.status = BasketStatus.completed 141 basket.save() 142 143 return basket 144 145 def _create_quotation_items(self, quotation: Quotation | Order, basket_items: list[BasketItem]) -> None: 146 QuotationItem.objects.bulk_create( 147 [ 148 QuotationItem( 149 quotation=quotation, 150 product_remote_id=bi.product_remote_id, 151 quantity=bi.quantity, 152 division=bi.division, 153 price=bi.price, 154 data=bi.data, 155 currency=bi.currency, 156 ) 157 for bi in basket_items 158 ] 159 )