From 62dfee21d091d88ff104d38c0da0e424c2f6ab28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20G=2E=20Rodr=C3=ADguez?= Date: Mon, 13 Jun 2022 12:32:06 +0200 Subject: [PATCH] discount codes (step3) --- features/add_discount_to_cart.feature | 39 +++++++++++++++++++++++++++ src/application/CartDiscountAdder.ts | 13 +-------- src/entity/Cart.ts | 20 +++++++++++++- src/tests/steps/CartSteps.ts | 24 +++++++++++++++++ 4 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 features/add_discount_to_cart.feature diff --git a/features/add_discount_to_cart.feature b/features/add_discount_to_cart.feature new file mode 100644 index 0000000..bb4b756 --- /dev/null +++ b/features/add_discount_to_cart.feature @@ -0,0 +1,39 @@ +Feature: Add discount to cart + As a Rohlik customer + I want to apply discounts to my cart + so that I can save some money + + Background: + Given the following products exist: + | sku | name | price | + | 001 | potatoes | 2.5 | + | 002 | water | 0.95 | + And there is a cart discount "free shipping" for 1 euros with code "FREE-SHIPPING" + And there is a cart discount "special offer" for 10 euros with code "SPECIAL-OFFER" + And I have a cart + + Scenario: No discounts + When I add 2 units of product "001" to my cart + Then the cart's total cost should be 5.0 euros + But there shouldn't be discounts in my cart + + Scenario: Add discount + Given I add 2 units of product "001" to my cart + When I apply "FREE-SHIPPING" discount to my cart + Then the cart's total cost should be 4.0 euros + And there should be discount "free shipping" in my cart + + Scenario: Add discount only apply once + Given I add 2 units of product "001" to my cart + And I apply "FREE-SHIPPING" discount to my cart + When I apply "FREE-SHIPPING" discount to my cart + Then the cart's total cost should be 4.0 euros + And there should be discount "free shipping" in my cart + + Scenario: Cart total should be always positive + Given I add 2 units of product "001" to my cart + And I apply "FREE-SHIPPING" discount to my cart + When I apply "SPECIAL-OFFER" discount to my cart + Then the cart's total cost should be 0.0 euros + And there should be discount "free shipping" in my cart + And there should be discount "special offer" in my cart \ No newline at end of file diff --git a/src/application/CartDiscountAdder.ts b/src/application/CartDiscountAdder.ts index 01f1a3e..c7f5e8e 100644 --- a/src/application/CartDiscountAdder.ts +++ b/src/application/CartDiscountAdder.ts @@ -15,21 +15,10 @@ class CartDiscountAdder { const cart: Cart = await this.cartRepository.findOneByOrFail({id: cartId}) const discount: Discount = await this.discountRepository.findOneByOrFail({code: code}) - this.applyDiscount(cart, discount) + cart.applyDiscount(discount) await this.cartRepository.save(cart) } - - private applyDiscount(cart: Cart, discount: Discount): void { - //@todo suspicious code - should we move this logic to cart entity? - const foundDiscount: Discount|undefined = cart.discounts.find((currentDiscount: Discount) => currentDiscount.id == discount.id) - - if (foundDiscount) { - throw "Discount already applied" - } - - cart.discounts.push(discount) - } } export default CartDiscountAdder \ No newline at end of file diff --git a/src/entity/Cart.ts b/src/entity/Cart.ts index 64bd97a..7db7426 100644 --- a/src/entity/Cart.ts +++ b/src/entity/Cart.ts @@ -62,13 +62,31 @@ class Cart { } public totalPrice(): number { - return Math.round((this.totalLinesPrice() - this.totalDiscountsPrice()) * 100) / 100 + return Math.max( + 0, + Math.round((this.totalLinesPrice() - this.totalDiscountsPrice()) * 100) / 100 + ) } public quantityOfProduct(sku: string): number { const cartLine: CartLine|undefined = this.lines.find((cartLine: CartLine) => cartLine.product.sku == sku) return cartLine ? cartLine.quantity : 0 } + + public hasDiscount(name: string): boolean { + const discount: Discount|undefined = this.discounts.find((discount: Discount) => discount.name == name) + return discount ? true : false + } + + public applyDiscount(discount: Discount): void { + const foundDiscount: Discount|undefined = this.discounts.find((currentDiscount: Discount) => currentDiscount.id == discount.id) + + if (foundDiscount) { + throw "Discount already applied" + } + + this.discounts.push(discount) + } } export default Cart diff --git a/src/tests/steps/CartSteps.ts b/src/tests/steps/CartSteps.ts index e823664..724b3a3 100644 --- a/src/tests/steps/CartSteps.ts +++ b/src/tests/steps/CartSteps.ts @@ -63,6 +63,30 @@ class CartSteps { assert.equal(cart.quantityOfProduct(sku), 0) } + @then("there should be discount {string} in my cart") + public async thereShouldBeDiscountInCart(name: string) { + const cart: Cart = await this.currentCart() + assert.equal(cart.hasDiscount(name), true, `Discount ${name} should be present`) + } + + @then("there shouldn't be discounts in my cart") + public async thereShouldNotBeDiscountsInCart() { + const cart: Cart = await this.currentCart() + assert.equal(0, cart.discounts.length); + } + + @when("I apply {string} discount to my cart") + public async iApplyDiscountToMyCart(code: string) { + await this.axios.post( + `http://${process.env.WEB_HOST}:${process.env.WEB_PORT}/carts/${this.currentCartId}/discounts`, + { code: code }, + { + headers: {'Content-Type': 'application/json'}, + validateStatus: (status: number) => { return true } + } + ) + } + private currentCart(): Promise { return this.cartRepository.findOneByOrFail({id: this.currentCartId}) }