HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/ReturnIndustries/return-industries.nl/app/Komma/Shop/Checkout/CheckoutService.php
<?php


namespace App\Komma\Shop\Checkout;


use App\Komma\Addresses\AddressService;
use App\Komma\Addresses\Models\Address;
use App\Komma\Shop\Cart\ShoppingCartItemInterface;
use App\Komma\Shop\Orders\Kms\OrderServiceInterface;
use App\Komma\Shop\Orders\Models\Order;
use App\Komma\Shop\Orders\OrderNumberSequence;
use App\Komma\Shop\Orders\OrderStatus;
use App\Komma\Shop\Payment\PaymentServiceInterface;
use App\Komma\Shop\Products\Product\Product;
use App\Komma\Shop\Products\Product\ProductServiceInterface;
use App\Komma\Shop\Products\ProductComposite\ProductComposite;
use App\Komma\Shop\Products\ProductComposite\ProductCompositeServiceInterface;
use App\Komma\Shop\Products\ProductGroup\ProductGroup;
use App\Komma\Shop\Products\ProductGroup\ProductGroupServiceInterface;
use App\Komma\Users\Models\SiteUser;
use Illuminate\Http\RedirectResponse;

/**
 * Class CheckoutService
 *
 * The checkout service sits between Order related, product related and payment related code.
 * It directs those domains to work together.
 *
 * @package App\Komma\Shop\Checkout
 */
class CheckoutService implements CheckoutServiceInterface
{
    /** @var OrderServiceInterface $orderService */
    private $orderService;

    /** @var ProductServiceInterface $productService */
    private $productService;

    /** @var ProductGroupServiceInterface $productGroupService */
    private $productGroupService;

    /** @var ProductCompositeServiceInterface $productCompositeService */
    private $productCompositeService;

    /** @var PaymentServiceInterface $paymentService */
    private $paymentService;

    /** @var AddressService $addressService */
    private $addressService;

    /** @var OrderNumberSequence */
    private $orderNumberGenerator;


    public function __construct()
    {
        $this->orderService = app(OrderServiceInterface::class);
        $this->productService = app(ProductServiceInterface::class);
        $this->productGroupService = app(ProductGroupServiceInterface::class);
        $this->productCompositeService = app(ProductCompositeServiceInterface::class);
        $this->paymentService = app(PaymentServiceInterface::class);
        $this->addressService = app(AddressService::class);
        $this->orderNumberGenerator = app(OrderNumberSequence::class);
    }

    /**
     * Initializes a payment request for the user that owns the order.
     *
     * @param Order $order
     * @return RedirectResponse
     */
    public function startPaymentForOrder(Order $order): RedirectResponse
    {
        $pspAdapter = $this->paymentService->getAdapter();
        $transaction = $pspAdapter->createTransaction($order);
        return $pspAdapter->redirectForPayment($transaction);
    }

    /**
     * @param ShoppingCartItemInterface[] $shoppingCartItems
     * @param SiteUser $customer
     * @param Address $addressForShipping
     * @param Address $addressForInvoice
     * @return Order|null
     * @throws \Throwable
     */
    public function createOrderFromShoppingCartItems(array $shoppingCartItems, SiteUser $customer, Address $addressForShipping, Address $addressForInvoice): ?Order {
        foreach ($shoppingCartItems as $shoppingCartItem) {
            if (!is_a($shoppingCartItem, ShoppingCartItemInterface::class)) {
                throw new \RuntimeException('The given "ShoppingCartItem" wasn\'t an instance of: ' . ShoppingCartItemInterface::class);
            }
        }

        $order = null;
        \DB::transaction(function () use ($shoppingCartItems, $customer, $addressForShipping, $addressForInvoice, &$order) {
            //Convert the addresses into shipping and invoice addresses
            $attributes = $addressForShipping->getAttributes();
            if (isset($attributes['id'])) {
                unset($attributes['id']);
            } //If you don't do this, saving will skip an id somehow. Even if you exclude id in the fillable or included it in the guarded properties of the model. laravel bug?

            $attributes = $addressForInvoice->getAttributes();
            if (isset($attributes['id'])) {
                unset($attributes['id']);
            } //If you don't do this, saving will skip an id somehow. Even if you exclude id in the fillable or included it in the guarded properties of the model. laravel bug?

            //Create the order, link customer and addresses to it and save it. We need to save it because the ordered productables need a order id
            /** @var Order $order */
            $order = $this->orderService->newModel();
            $order->order_number = (string) $this->orderNumberGenerator->next();
            $order->customer()->associate($customer);
            $order = $this->fillOrderWithInvoiceAddressFromAddress($order, $addressForInvoice);
            $order = $this->fillOrderWithShippingAddressFromAddress($order, $addressForShipping);
            $order->save();

            //Loop over all shopping cart items and create ordered products for them. And link them to the order
            foreach ($shoppingCartItems as $shoppingCartItem) {
                $productable = $shoppingCartItem->getProductable();

                $shoppingCartItem->getTotal(true);
                $shoppingCartItem->getAmount();
                $productableClassName = get_class($productable);

                switch ($productableClassName) {
                    case Product::class:
                        /** @var Product $productable */
                        $this->productService->createOrderedProductFromProduct($productable, $order);
                        break;
                    case ProductGroup::class:
                        /** @var ProductGroup $productable */
                        $this->productGroupService->createOrderedProductGroupFromProductGroup($productable, $order);
                        break;
                    case ProductComposite::class;
                        /** @var ProductComposite $productable */
                        $this->productCompositeService->createOrderedProductCompositeProductComposite($productable, $order);
                        break;
                    default:
                        return null;
                }
            };

            $this->orderService->calculateTotalOrderPrice($order);
            $order->status = OrderStatus::NEW;

            $order->save();
        });

        return $order;
    }

    /**
     * @param Order $order
     * @param Address $address
     * @return Order
     */
    private function fillOrderWithShippingAddressFromAddress(Order $order, Address $address): Order
    {
        foreach($address->getFillable() as $index => $attributeName) $order['shipping_'.$attributeName] = $address->$attributeName;
        return $order;
    }

    /**
     * @param Order $order
     * @param Address $address
     * @return Order
     */
    private function fillOrderWithInvoiceAddressFromAddress(Order $order, Address $address)
    {
        foreach($address->getFillable() as $index => $attributeName) $order['invoice_'.$attributeName] = $address->$attributeName;
        return $order;
    }

    /**
     * Returns the last used shipping address for user or null if that not exists.
     *
     * @param SiteUser $user
     * @return Address
     */
    public function getLastUsedShippingAddressForUser(SiteUser $user): ? Address
    {
        $addressQuery = $user->addresses();

        /** @var Order $latestOrder */
        $latestOrder = $user->orders()->latest()->first();
        if(!$latestOrder) return null;

        $attributes = $latestOrder->getShippingAddressAttributes();
        foreach ($attributes as $attribute => $value) $addressQuery->where(str_replace('shipping_', '', $attribute), '=', $value);
        return $addressQuery->first();
    }

    /**
     * Returns the last used invoice address for the user or null if that not exists
     *
     * @param SiteUser $user
     * @return Address
     * @see Address
     */
    public function getLastUsedInvoiceAddressForUser(SiteUser $user): ? Address
    {
        $addressQuery = $user->addresses();

        /** @var Order $latestOrder */
        $latestOrder = $user->orders()->latest()->first();
        if(!$latestOrder) return null;

        $attributes = $latestOrder->getInvoiceAddressAttributes();
        foreach ($attributes as $attribute => $value) $addressQuery->where(str_replace('invoice_', '', $attribute), '=', $value);
        return $addressQuery->first();
    }
}