File: D:/HostingSpaces/SBogers10/stafa.komma.pro/app/Komma/Shop/Tests/Unit/CheckoutTest.php
<?php
namespace App\Komma\Shop\Tests\Unit;
use App\Komma\Addresses\Models\Address;
use App\Komma\Shop\Cart\ShoppingCartItem;
use App\Komma\Shop\Cart\ShoppingCartService;
use App\Komma\Shop\Checkout\CheckoutServiceInterface;
use App\Komma\Shop\Orders\Kms\OrderMailServiceInterface;
use App\Komma\Shop\Orders\Mail\OrderStatusUpdatedCustomer;
use App\Komma\Shop\Orders\Mail\OrderStatusUpdatedStaff;
use App\Komma\Shop\Orders\Product\OrderedProduct;
use App\Komma\Shop\Orders\ProductComposite\OrderedProductComposite;
use App\Komma\Shop\Orders\ProductGroup\OrderedProductGroup;
use App\Komma\Shop\Products\Product\Product;
use App\Komma\Shop\Products\ProductComposite\ProductComposite;
use App\Komma\Shop\Products\ProductGroup\ProductGroup;
use App\Komma\Shop\Tests\TestCase;
use App\Komma\Sites\SiteServiceInterface;
use App\Komma\Users\Models\KmsUser;
use App\Komma\Users\Models\KmsUserRole;
use App\Komma\Users\Models\SiteUser;
use App\Komma\Users\Models\SiteUserRole;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
class CheckoutTest extends TestCase
{
/** @var ShoppingCartService $shoppingCart */
private $shoppingCart;
/** @var CheckoutServiceInterface $checkoutService */
private $checkoutService;
/** @var OrderMailServiceInterface $orderMailService */
private $orderMailService;
/**
* Runs before each test
*/
public function setup(): void
{
parent::setup();
/** @var SiteServiceInterface $siteService */
$siteService = app(SiteServiceInterface::class); //Singleton
$siteService->setCurrentSiteToDefault();
$this->shoppingCart = new ShoppingCartService();
$this->checkoutService = app(CheckoutServiceInterface::class);
$this->orderMailService = app(OrderMailServiceInterface::class);
}
/**
* @test
* @group Checkout
* @throws \Throwable
*/
public function testCheckoutOrderCreationWithProduct()
{
//Get a random customer user to test with
/** @var SiteUser $customer */
$customer = factory(SiteUser::class)->create();
$this->assertInstanceOf(SiteUser::class, $customer);
//Give it an address
/** @var Address $address */
$address = factory(Address::class)->create();
$customer->addresses()->save($address);
//Put some random products in the shopping cart
/** @var Collection $products */
$products = Product::inRandomOrder()->take(2)->get();
$this->assertCount(2, $products);
$this->shoppingCart->addProductable($products[0], 2);
$this->shoppingCart->addProductable($products[1], 1);
$this->assertEquals(3, $this->shoppingCart->getItemsCount());
$order = $this->checkoutService->createOrderFromShoppingCartItems($this->shoppingCart->getItems(), $customer, $customer->addresses()->first(), $customer->addresses()->first());
//Check that the created order is related to the customer and vice versa
$this->assertEquals($order->customer()->first()->id, $customer->id);
$orderFromCustomer = $customer->orders()->where('id', '=', $order->id)->first();
$this->assertEquals($order->id, $orderFromCustomer->id);
//Check that the product ids are in the orderedProduct product id's
$productIds = $products->pluck('id');
echo 'Product id\'s to find in the order: '.$productIds->implode(', ').PHP_EOL;
$orderedProductProductIds = $order->orderedProducts()->with('product')->get()->map(function(OrderedProduct $orderOrderedProduct) {
return $orderOrderedProduct->product->id;
});
echo 'Product id\'s that are in the order: '.$orderedProductProductIds->implode(', ').PHP_EOL;
// echo PHP_EOL;
$productIds->each(function(int $id) use ($orderedProductProductIds) {
$this->assertTrue($orderedProductProductIds->search($id) !== false); //Check that the product id is in the collection of OrderedProduct product ids
});
}
/**
* @test
* @group Checkout
* @throws \Throwable
*/
public function testCheckoutOrderCreationWithGroup()
{
//Get a random customer user to test with
/** @var SiteUser $customer */
$customer = factory(SiteUser::class)->create();
$this->assertInstanceOf(SiteUser::class, $customer);
//Give it an address
/** @var Address $address */
$address = factory(Address::class)->create();
$customer->addresses()->save($address);
//Create a product group and add products
/** @var ProductGroup $productGroup */
$productGroup = factory(ProductGroup::class)->create();
$this->assertNotNull($productGroup);
$products = factory(Product::class, 2)->create();
$this->assertNotNull($products);
$productGroup->products()->saveMany($products);
$this->assertEquals(2, $productGroup->products()->count());
$this->shoppingCart->addProductable($productGroup, 1);
$this->assertEquals(1, $this->shoppingCart->getItemsCount());
$order = $this->checkoutService->createOrderFromShoppingCartItems($this->shoppingCart->getItems(), $customer, $customer->addresses()->first(), $customer->addresses()->first());
//Check that the product group ids are in the orderedProduct product id's
echo 'Product group id\'s to find in the order: '.$productGroup->id.PHP_EOL;
/** @var OrderedProductGroup $orderedProductGroup */
$orderedProductGroup = $order->orderedGroups()->with(['productGroup', 'productGroup.products'])->first();
echo 'Product group id\'s that are in the order: '.$orderedProductGroup->productGroup->id.PHP_EOL;
$this->assertTrue($productGroup->id === $orderedProductGroup->productGroup->id);
//Check that the ordered product group does have all the products that the product group has
$this->assertNotNull($productGroup->products()->get());
/** @var Collection $productGroupProductIds */
$productGroupProductIds = $productGroup->products->pluck('id');
echo 'Product id\'s to find in ordered product group: '.$productGroupProductIds->implode(', ').PHP_EOL;
$this->assertEquals(2, $orderedProductGroup->orderedProducts()->count());
$this->assertEquals($orderedProductGroup->products()->count(), $orderedProductGroup->orderedProducts()->count());
$orderedProductIds = $orderedProductGroup->orderedProducts()->get()->map(function(OrderedProduct $orderedProduct) {
return $orderedProduct->product->id;
});
echo 'Product id\'s that are in the ordered product group: '.$orderedProductIds->implode(', ').PHP_EOL;
$productGroupProductIds->each(function(int $productGroupProductId) use($orderedProductIds) {
$this->assertTrue($orderedProductIds->contains($productGroupProductId));
});
}
/**
* @test
* @group Checkout
* @throws \Throwable
*/
public function testCheckoutOrderCreationWithComposite()
{
//Get a random customer user to test with
/** @var SiteUser $customer */
$customer = factory(SiteUser::class)->create();
$this->assertInstanceOf(SiteUser::class, $customer);
//Give it an address
/** @var Address $address */
$address = factory(Address::class)->create();
$customer->addresses()->save($address);
//Create a product composite with a product group and add products
/** @var ProductComposite $productComposite */
$productComposite = factory(ProductComposite::class)->create();
/** @var ProductGroup $productGroup */
$productGroup = factory(ProductGroup::class)->create();
$this->assertNotNull($productGroup);
$products = factory(Product::class, 2)->create();
$this->assertNotNull($products);
$productGroup->products()->saveMany($products);
$productComposite->groups()->saveMany(collect([$productGroup]));
$this->assertEquals(2, $productGroup->products()->count());
$this->assertEquals(1, $productComposite->groups()->count());
$this->assertEquals(2, $productComposite->groups()->first()->products()->count());
$this->shoppingCart->addProductable($productComposite, 1);
$this->assertEquals(1, $this->shoppingCart->getItemsCount());
$order = $this->checkoutService->createOrderFromShoppingCartItems($this->shoppingCart->getItems(), $customer, $customer->addresses()->first(), $customer->addresses()->first());
//Check that the product group ids are in the orderedProduct product id's
echo 'Product composite id\'s to find in the order: '.$productComposite->id.PHP_EOL;
/** @var OrderedProductComposite $orderedProductComposite */
$orderedProductComposite = $order->orderedProductComposites()->with(['productComposite'])->first();
echo 'Product composite id\'s that are in the order: '.$orderedProductComposite->productComposite->id.PHP_EOL;
$this->assertTrue($productComposite->id === $orderedProductComposite->productComposite->id);
//Check that the ordered product group does have all the products that the product group has
$this->assertNotNull($productComposite->groups->first()->products()->get());
/** @var Collection $productGroupProductIds */
$productGroupProductIds = $productGroup->products->pluck('id');
echo 'Product id\'s to find in ordered product composite: '.$productGroupProductIds->implode(', ').PHP_EOL;
$this->assertEquals(2, $orderedProductComposite->orderedGroups->first()->orderedProducts()->count());
$this->assertEquals($orderedProductComposite->groups->first()->products()->count(), $orderedProductComposite->orderedGroups->first()->orderedProducts()->count());
$orderedProductIds = $orderedProductComposite->orderedGroups->first()->orderedProducts()->get()->map(function(OrderedProduct $orderedProduct) {
return $orderedProduct->product->id;
});
echo 'Product id\'s that are in the ordered product composite: '.$orderedProductIds->implode(', ').PHP_EOL;
$productGroupProductIds->each(function(int $productGroupProductId) use($orderedProductIds) {
$this->assertTrue($orderedProductIds->contains($productGroupProductId));
});
}
/**
* @test
* @group Checkout
* @throws \Throwable
*/
public function testCheckoutUserAddress()
{
//Get a random customer user to test with
/** @var SiteUser $customer */
$customer = factory(SiteUser::class)->create();
$this->assertInstanceOf(SiteUser::class, $customer);
//Give it an address
/** @var Address $address */
$address = factory(Address::class)->create();
$customer->addresses()->save($address);
//Put some random products in the shopping cart
$products = Product::inRandomOrder()->take(3)->get();
$this->assertCount(3, $products);
$products->each(function(Product $product) {
/** @var ShoppingCartItem $shoppingCartItem */
$shoppingCartItem = $this->shoppingCart->addProductable($product, mt_rand(1, 3));
// echo get_class($shoppingCartItem->getProductable()) .' => '. $shoppingCartItem->getProductable()->id.' ('.$shoppingCartItem->getItemsCount().' pc(s))'.PHP_EOL;
});
$order = $this->checkoutService->createOrderFromShoppingCartItems($this->shoppingCart->getItems(), $customer, $customer->addresses()->first(), $customer->addresses()->first());
//Check if customers address attributes are in the order itself (to preserve history)
$this->assertEquals($customer->first_name, $order->customer->first_name);
$this->assertEquals($customer->last_name, $order->customer->last_name);
$this->assertEquals($customer->email, $order->customer->email);
$this->assertEquals($customer->addresses[0]->postal_code, $order->invoice_postal_code);
$this->assertEquals($customer->addresses[0]->city, $order->invoice_city);
$this->assertEquals($customer->addresses[0]->street, $order->invoice_street);
$this->assertEquals($customer->addresses[0]->house_number, $order->invoice_house_number);
$this->assertEquals($customer->addresses[0]->telephone, $order->invoice_telephone);
$this->assertEquals($customer->addresses[0]->postal_code, $order->shipping_postal_code);
$this->assertEquals($customer->addresses[0]->city, $order->shipping_city);
$this->assertEquals($customer->addresses[0]->street, $order->shipping_street);
$this->assertEquals($customer->addresses[0]->house_number, $order->shipping_house_number);
$this->assertEquals($customer->addresses[0]->telephone, $order->shipping_telephone);
}
/**
* @test
* @group Checkout
* @throws \Throwable
*/
public function testCheckoutMails()
{
Mail::fake();
/** @var SiteUser $customer */
$customer = factory(SiteUser::class)->create();
$customer->role = SiteUserRole::Customer;
$address = factory(Address::class)->create();
$customer->addresses()->save($address);
/** @var KmsUser $customer */
$staff = factory(KmsUser::class, 3)->create();
$staff->each(function(KmsUser $staffMember) {
$staffMember->role = KmsUserRole::Admin;
$staffMember->save();
$address = factory(Address::class)->create();
$staffMember->addresses()->save($address);
});
$this->shoppingCart->addProductable(ProductComposite::inRandomOrder()->take(1)->first());
$address = $customer->addresses()->first();
$order = $this->checkoutService->createOrderFromShoppingCartItems($this->shoppingCart->getItems(), $customer, $address, $address);
$this->orderMailService->mailStaffAboutCurrentOrderStatus($order);
$staffEmails = $staff->pluck('email');
Mail::assertSent(OrderStatusUpdatedStaff::class, function (Mailable $mail) use ($staffEmails){
$found = false;
foreach($staffEmails as $staffEmail)
{
if($mail->hasTo($staffEmail)) {
$found = true;
break;
}
}
// echo 'An OrderStatusUpdatedStaff mail '.(($found) ? 'was': 'was not').' queued for a staff member with e-mail: '.$staffEmail.PHP_EOL;
return $found;
});
$this->orderMailService->mailCustomerAboutCurrentOrderStatus($order, $customer);
Mail::assertSent(OrderStatusUpdatedCustomer::class, function (Mailable $mail) use ($customer){
$found = $mail->hasTo($customer->email);
// echo 'An OrderStatusUpdatedCustomer mail '.(($found) ? 'was': 'was not').' queued for a customer with e-mail: '.$customer->email.PHP_EOL;
return $found;
});
}
}