Skip to content
This repository was archived by the owner on Apr 26, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions features/add_discount_to_cart.feature
Original file line number Diff line number Diff line change
@@ -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
13 changes: 1 addition & 12 deletions src/application/CartDiscountAdder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 19 additions & 1 deletion src/entity/Cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
24 changes: 24 additions & 0 deletions src/tests/steps/CartSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Cart> {
return this.cartRepository.findOneByOrFail({id: this.currentCartId})
}
Expand Down