def test_five_for_five_can_use(self): b = Balance() b.add_balance(1_20, Category.DAIRY) b.add_balance(4_34, Category.DRINKS) self.assertFalse(FiveForFive.can_use(b)) b.add_balance(0, Category.VEGGIES, "carrot") b.add_balance(0, Category.FRUITS, "grapes") self.assertFalse(FiveForFive.can_use(b)) b.add_balance(3_50, Category.FRUITS, "apple") b.add_balance(3_50, Category.FRUITS, "banana") self.assertTrue(FiveForFive.can_use(b))
class Sale: """ A single sale to a customer. The steps for a sale are as follows: 1. Scanning individual items 2. (Optional) using coupons to reduce the price 3. Calculating and charging the amount 4. Rewarding coupons based on items purchased """ def __init__( self, customer: Customer, store: Store, store_manager: StoresManager = StoresManager()) -> None: self.customer = customer self.store = store self.balance = Balance() self.store_manager = store_manager def start_sale(self) -> None: print( "=" * DISPLAY_WIDTH + f"\n{f'{self.store.name} digital checkout'.center(DISPLAY_WIDTH)}\n" + "=" * DISPLAY_WIDTH + "\n") print("LOGS") print("~" * DISPLAY_WIDTH) print(f"[Sale] Customer {self.customer.name} started checkout with {format_money(self.customer.balance.amount())}" \ + f" and {len(self.customer.coupons)} coupons") def scan_item(self, barcode: int) -> bool: # Problem 1.2: YOUR CODE HERE if barcode in self.store.database.items.keys(): new_item = self.store.database.items[barcode] self.balance.add_balance(new_item.price, new_item.category, new_item.name) return True return False def use_coupons(self, coupons: List[Coupon]) -> None: for coupon in self.sorted_coupons(coupons): if not coupon.rule.can_use(self.balance): print( f"[Coupon] Invalid - coupon {coupon.code} does not apply to this purchase" ) elif not self.customer.use_coupon(coupon): print( f"[Coupon] Invalid - coupon {coupon.code} was already used" ) else: self.balance.subtract_balance( coupon.rule.apply_discount(self.balance), category=Category.COUPON, description= f"Coupon {coupon.code} - {coupon.rule.description()}") def sorted_coupons(self, coupons: List[Coupon]) -> List[Coupon]: priority_dict = { coupon_rule: index for index, coupon_rule in enumerate(COUPON_PRIORITY) } return sorted(coupons, key=lambda coupon: priority_dict.get(coupon.rule, 0)) def reward_coupons(self) -> List[Coupon]: # Problem 1.3: YOUR CODE HERE available_coupons = self.store.available_coupon_types() coupons_rewarded = [] for coupon_type in available_coupons: num_coupons = coupon_type.number_to_reward(self.balance) coupons_rewarded += self.store.reward_coupons( self.customer, coupon_type, num_coupons) return coupons_rewarded def finish_sale(self) -> None: sale_price = self.balance.amount() if self.customer.balance.amount() < sale_price: raise Exception(f"Not enough money to complete purchase") self.customer.balance.subtract_balance( sale_price, description="Purchase at ____ store") self.balance.group_balance_items() print(f"\n\nSALE RESULT\n" + "~" * DISPLAY_WIDTH + "\n" + str(self.balance) + "\n") coupons = self.reward_coupons() print(f"Rewarding {len(coupons)} coupons:") for c in coupons: print(f"-> {c.rule.description()}") print(f"\nCustomer now has {format_money(self.customer.balance.amount())}" \ + f" and {len(self.customer.coupons)} coupon(s) remaining") print( f"\nThanks for shopping at {self.store.name}. Please come again!\n" )