File: D:/HostingSpaces/SBogers10/honger7.komma.pro/app/KommaApp/Shop/Tests/Unit/DiscountTest.php
<?php
namespace App\KommaApp\Shop\Tests\Unit;
use App\KommaApp\Shop\Cart\ShoppingCartItem;
use App\KommaApp\Shop\Cart\ShoppingCartItemInterface;
use App\KommaApp\Shop\Cart\ShoppingCartService;
use App\KommaApp\Shop\Cart\ShoppingCartServiceInterface;
use App\KommaApp\Shop\Discounts\Actions\ModifyPriceAction;
use App\KommaApp\Shop\Discounts\Conditions\CouponDiscountCondition;
use App\KommaApp\Shop\Discounts\Conditions\DiscountableCondition;
use App\KommaApp\Shop\Discounts\Conditions\QuantityDiscountCondition;
use App\KommaApp\Shop\Discounts\DiscountableTypes;
use App\KommaApp\Shop\Discounts\Discount;
use App\KommaApp\Shop\Discounts\DiscountService;
use App\KommaApp\Shop\Discounts\DiscountTypes;
use App\KommaApp\Shop\Products\Product\Product;
use App\KommaApp\Shop\Tests\TestCase;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class DiscountTest extends TestCase
{
use DatabaseTransactions; //Automatically rolls back database actions after tests
/**
* Runs before each test
*/
public function setup()
{
parent::setup();
}
/**
* Runs after each test
*/
public function teardown()
{
parent::tearDown();
}
/**
* @group Discount
* @test
*/
public function DiscountableDiscountCreationTest()
{
$discount = new Discount();
$condition = new DiscountableCondition(ShoppingCartServiceInterface::class);
$action = new ModifyPriceAction(1000,ModifyPriceAction::MethodAbsolute); //Modify the price by lowering it with 10 euro's, dollars, whatever
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$this->assertInstanceOf(DiscountableCondition::class, $discount->getDiscountCondition());
$this->assertInstanceOf(ModifyPriceAction::class, $discount->getDiscountAction());
$this->assertEquals($discount->action_settings, $discount->getDiscountAction()->getValue());
$this->assertEquals($discount->condition_settings, $discount->getDiscountCondition()->getValue());
//Get the settings from the condition and action. These values are stored in the database so we must check them
$conditionSettings = $discount->getDiscountCondition()->getValue();
$actionSettings = $discount->getDiscountAction()->getValue();
$this->assertEquals(DiscountableTypes::ShoppingCart, $conditionSettings);
$this->assertEquals('1000,'.ModifyPriceAction::MethodAbsolute, $actionSettings);
$discount->save();
$dbModel = Discount::find($discount->id);
$this->assertInstanceOf(Discount::class, $dbModel);
$this->assertEquals($dbModel->action_settings, $discount->getDiscountAction()->getValue());
$this->assertEquals($dbModel->condition_settings, $discount->getDiscountCondition()->getValue());
}
/**
* @group Discount
* @test
*/
public function QuantityDiscountCreationTest()
{
$discount = new Discount();
$condition = new QuantityDiscountCondition(ShoppingCartItemInterface::class, 3, [1]);
$action = new ModifyPriceAction(10,ModifyPriceAction::MethodPercentageWise); //Modify the price by lowering it with 10%
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$this->assertInstanceOf(QuantityDiscountCondition::class, $discount->getDiscountCondition());
$this->assertInstanceOf(ModifyPriceAction::class, $discount->getDiscountAction());
$this->assertEquals($discount->action_settings, $discount->getDiscountAction()->getValue());
$this->assertEquals($discount->condition_settings, $discount->getDiscountCondition()->getValue());
//Get the settings from the condition and action. These values are stored in the database so we must check them
$conditionSettings = $discount->getDiscountCondition()->getValue();
$actionSettings = $discount->getDiscountAction()->getValue();
$this->assertEquals(DiscountableTypes::ShoppingCartItem.',3,1', $conditionSettings);
$this->assertEquals('10,'.ModifyPriceAction::MethodPercentageWise, $actionSettings);
$discount->save();
$dbModel = Discount::find($discount->id);
$this->assertInstanceOf(Discount::class, $dbModel);
$this->assertEquals($dbModel->action_settings, $discount->getDiscountAction()->getValue());
$this->assertEquals($dbModel->condition_settings, $discount->getDiscountCondition()->getValue());
}
/**
* @group Discount
* @test
*/
public function AbsoluteDiscountOnWholeShoppingCartTest()
{
//Create the discount for an absolute discount on the whole shopping cart
$discount = new Discount();
$discount->type = DiscountTypes::Discountable;
$discount->active = 1;
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDays(1);
$condition = new DiscountableCondition(ShoppingCartServiceInterface::class);
$action = new ModifyPriceAction(1000,ModifyPriceAction::MethodAbsolute); //Modify the price by lowering it with 10 euro's / dollars / whatever
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it.
//Create a product that we are going to put in the cart
/** @var Product $product */
$product = factory(Product::class)->create();
//And a cart (that holds the DiscountService)
$cart = new ShoppingCartService();
$cart->addProduct($product->id, 1);
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
$this->assertNotEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertEquals($totalWithoutDiscount - 1000, $totalWithDiscount);
}
/**
* @group Discount
* @test
*/
public function PercentageDiscountOnWholeShoppingCartTest()
{
$discount = new Discount();
$discount->type = DiscountTypes::Discountable;
$discount->active = 1;
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDays(1);
$condition = new DiscountableCondition(ShoppingCartServiceInterface::class);
$action = new ModifyPriceAction(20,ModifyPriceAction::MethodPercentageWise); //Modify the price by lowering it with 10 percent
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it.
//Create a product that we are going to put in the cart
/** @var Product $product */
$product = factory(Product::class)->create();
/** @var Product $product2 */
$product2 = factory(Product::class)->create();
//And a cart (that holds the DiscountService)
$cart = new ShoppingCartService();
$cart->addProduct($product->id, 1);
$cart->addProduct($product2->id, 1);
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
$manuallyCalculatedTotal = $product->getTotal() + $product2->getTotal();
$manuallyCalculatedPercentageValue = ($manuallyCalculatedTotal / 100) * 20;
$manuallyCalculatedExpectedPriceWithDiscount = $manuallyCalculatedTotal - $manuallyCalculatedPercentageValue;
// echo 'Product 1 price: '.$product->getPrice().PHP_EOL;
// echo 'Product 2 price: '.$product2->getPrice().PHP_EOL;
// echo 'Total manually calculated: '.$manuallyCalculatedTotal.PHP_EOL;
// echo 'Percentage value to subtract: '.$manuallyCalculatedPercentageValue.PHP_EOL;
$this->assertEquals($totalWithoutDiscount, $manuallyCalculatedTotal);
$this->assertNotEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertEquals($manuallyCalculatedExpectedPriceWithDiscount, $totalWithDiscount);
}
/**
* @group Discount
* @test
*/
public function AbsoluteDiscountOnShoppingCartItemTest()
{
$discount = new Discount();
$discount->type = DiscountTypes::Quantity;
$discount->active = 1;
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDays(1);
$condition = new QuantityDiscountCondition(ShoppingCartItemInterface::class, 3);
$action = new ModifyPriceAction(20,ModifyPriceAction::MethodAbsolute); //Modify the price by lowering it with 20 euro
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it when it does it's job
//Test that the cart does not have any discounts
$cart = new ShoppingCartService();
$priceOfAllProductsWithDiscounts = 0;
$products = [];
for($index = 0; $index < 3; $index++) {
/** @var Product $product */
$product = factory(Product::class)->create();
$products[] = $product;
$cart->addProduct($product->id);
$priceOfAllProductsWithDiscounts += $product->getTotal();
}
//No discounts should be applied right now. Because the discount says it will be applied to a specific product when that specific products quantity is more then specified. Now we have more then 3 products, but of a different type.
$this->assertEquals($cart->getTotal(true), $priceOfAllProductsWithDiscounts);
//Now test on shoppingCartItem level
$discountService = new DiscountService();
$shoppingCartItem = (new ShoppingCartItem())->setProduct($products[0])->setAmount(2);
$discountService->updateDiscounts($shoppingCartItem);
//We still should not have any discounts applied
$this->assertEquals(0, count($shoppingCartItem->getDiscounts()));
//Setting the amount on 3 must result in an discount to be applied since that is what it is used for
$shoppingCartItem = (new ShoppingCartItem())->setProduct($products[0])->setAmount(3);
$discountService->updateDiscounts($shoppingCartItem);
$priceWithoutDiscounts = $shoppingCartItem->getTotal(false);
$priceWithDiscounts = $shoppingCartItem->getTotal(true);
$this->assertNotEquals($priceWithDiscounts, $priceWithoutDiscounts);
$manuallyDiscountedPrice = $priceWithoutDiscounts - 20;
$this->assertEquals($manuallyDiscountedPrice, $priceWithDiscounts);
}
/**
* @group Discount
* @test
*/
public function PercentageDiscountOnShoppingCartItemTest()
{
$discount = new Discount();
$discount->type = DiscountTypes::Quantity;
$discount->active = 1;
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDays(1);
$condition = new QuantityDiscountCondition(ShoppingCartItemInterface::class, 3);
$action = new ModifyPriceAction(50,ModifyPriceAction::MethodPercentageWise); //Modify the price by lowering it with 20 percent
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it when it does it's job
//Now test on shoppingCartItem level
$discountService = new DiscountService();
$product = factory(Product::class)->create();
//Setting the amount on 3 must result in an discount to be applied since that is what it is used for
$shoppingCartItem = (new ShoppingCartItem())->setProduct($product)->setAmount(6);
$discountService->updateDiscounts($shoppingCartItem);
$priceWithoutDiscounts = $shoppingCartItem->getTotal(false);
$priceWithDiscounts = $shoppingCartItem->getTotal(true);
$this->assertNotEquals($priceWithDiscounts, $priceWithoutDiscounts);
$manuallyDiscountedPrice = $priceWithoutDiscounts - ($priceWithoutDiscounts * .5);
$this->assertEquals($manuallyDiscountedPrice, $priceWithDiscounts);
}
/**
* @group Discount
* @test
*/
public function couponCodeTest()
{
$discount = new Discount();
$discount->type = DiscountTypes::Coupon;
$discount->active = 1;
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDays(1);
$condition = new CouponDiscountCondition('KommAwesome');
$action = new ModifyPriceAction(5,ModifyPriceAction::MethodPercentageWise); //Modify the price by lowering it with 5 percent
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it when it does it's job
$cart = new ShoppingCartService();
$product = factory(Product::class)->create();
$cart->addProduct($product->id, 1);
$totalWithoutDiscounts = $cart->getTotal(false);
$totalWithDiscounts = $cart->getTotal(true);
$this->assertEquals($totalWithDiscounts, $totalWithoutDiscounts);
$cart->addCouponCode('KommAwesome');
$totalWithoutDiscounts = $cart->getTotal(false);
$totalWithDiscounts = $cart->getTotal(true);
$this->assertNotEquals($totalWithDiscounts, $totalWithoutDiscounts);
$this->assertEquals($totalWithoutDiscounts - ($totalWithoutDiscounts * .05), $totalWithDiscounts);
}
/**
* @group Discount
* @test
*/
public function ValidityAndActiveTest()
{
//Create the discount for an absolute discount on the whole shopping cart. Make it not yet valid
$discount = new Discount();
$discount->type = DiscountTypes::Discountable;
$discount->active = 1;
$discount->valid_from = Carbon::now()->addDays(2);
$discount->valid_trough = Carbon::now()->addDays(2);
$condition = new DiscountableCondition(ShoppingCartServiceInterface::class);
$action = new ModifyPriceAction(1000,ModifyPriceAction::MethodAbsolute); //Modify the price by lowering it with 10 euro's / dollars / whatever
$discount->setDiscountCondition($condition)->setDiscountAction($action);
$discount->save(); //Save it to the database so that the discountService knows about it.
//Create a product that we are going to put in the cart
/** @var Product $product */
$product = factory(Product::class)->create();
//And a cart (that holds the DiscountService)
$cart = new ShoppingCartService();
$cart->addProduct($product->id, 1);
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
//No discount should be applied yet since it is not valid yet.
$this->assertEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertNotEquals($totalWithoutDiscount - 1000, $totalWithDiscount);
//Change the discount so that it is valid. Clear the cart and re-add the product
$discount->valid_from = Carbon::now()->subDay(1);
$discount->valid_trough = Carbon::now()->addDay(2);
$discount->save();
$cart->clear();
$cart->addProduct($product->id, 1);
//The discount should be applied since it now is valid
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
$this->assertNotEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertEquals($totalWithoutDiscount - 1000, $totalWithDiscount);
//Change the discount so that it was valid in the past. Clear the cart and re-add the product
$discount->valid_from = Carbon::now()->subDay(5);
$discount->valid_trough = Carbon::now()->subDay(1);
$discount->save();
$cart->clear();
$cart->addProduct($product->id, 1);
//The discount should not be applied since it was valid in the past but not now anymore
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
$this->assertEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertNotEquals($totalWithoutDiscount - 1000, $totalWithDiscount);
//Change the discount so that it has a valid date but isn't active. Clear the cart and re-add the product
$discount->valid_from = Carbon::now();
$discount->valid_trough = Carbon::now()->addDay(1);
$discount->active = 0;
$discount->save();
$cart->clear();
$cart->addProduct($product->id, 1);
//The discount should not be applied since its date is valid but it isn't active
$totalWithoutDiscount = $cart->getTotal(false);
$totalWithDiscount = $cart->getTotal(true);
$this->assertEquals($totalWithDiscount, $totalWithoutDiscount);
$this->assertNotEquals($totalWithoutDiscount - 1000, $totalWithDiscount);
}
}