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/SBogers10/blije-gasten.komma.pro/app/Komma/Shop/Orders/OrderService.php
<?php


namespace App\Komma\Shop\Orders;


use App\Komma\Addresses\Models\Address;
use App\Komma\Base\Service;
use App\Komma\Shop\Cart\ShoppingCartItemInterface;
use App\Komma\Shop\Cart\ShoppingCartServiceInterface;
use App\Komma\Shop\Orders\Models\Order;
use App\Komma\Shop\Payment\PaymentServiceInterface;
use App\Komma\Shop\Products\Product\Product;
use App\Komma\Shop\Products\Product\ProductModelService;
use App\Komma\Shop\Products\ProductComposite\ProductComposite;
use App\Komma\Shop\Products\ProductComposite\ProductCompositeModelService;
use App\Komma\Shop\Products\ProductGroup\ProductGroup;
use App\Komma\Shop\Products\ProductGroup\ProductGroupModelService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\RedirectResponse;

final class OrderService extends Service
{

    private PaymentServiceInterface $paymentService;
    private OrderNumberSequence $orderNumberGenerator;
    private InvoiceNumberSequence $invoiceNumberGenerator;
    private ProductGroupModelService $productGroupService;
    private ProductModelService $productService;
    private ProductCompositeModelService $productCompositeService;

    public function __construct()
    {
        parent::__construct();

        $this->paymentService = app(PaymentServiceInterface::class);
        $this->orderNumberGenerator = app(OrderNumberSequence::class);
        $this->invoiceNumberGenerator = app(InvoiceNumberSequence::class);
        $this->productService = new ProductModelService();
        $this->productGroupService = new ProductGroupModelService();
        $this->productCompositeService = new ProductCompositeModelService();
    }

    /**
     * Get order
     *
     * @param $orderId
     * @return Order
     */
    public function getOrderById($orderId): Order
    {
        return Order::where('id', $orderId)->first();
    }

    /**
     * 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);
    }
    /**
     * Initializes a payment request for an additional payment on intake of an order.
     *
     * @param Order $order
     * @return RedirectResponse
     */
    public function startIntakePaymentForOrder(Order $order): RedirectResponse
    {
        $pspAdapter = $this->paymentService->getAdapter();
        $transaction = $pspAdapter->createIntakeTransaction($order);
        return $pspAdapter->redirectForIntakePayment($transaction);
    }

    /**
     * @param ShoppingCartServiceInterface $shoppingCartService
     * @param $userData
     * @param $addressForShipping
     * @param Address $addressForInvoice
     * @return Order|null
     */
    public function createOrder(ShoppingCartServiceInterface $shoppingCartService, $userData, Address $addressForInvoice, $addressForShipping): ?Order {

        $order = null;

        \DB::transaction(function () use ($shoppingCartService, $userData, $addressForShipping, $addressForInvoice, &$order) {
            //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 = new Order();
            $order->status = OrderStatus::NEW;
            $order->date = $shoppingCartService->getDate();
            $order->order_number = (string) $this->orderNumberGenerator->next();
            $order->invoice_number = (string) $this->invoiceNumberGenerator->next();
//            $order->customer()->associate($customer);

            $order = $this->fillOrderWithUserData($order, $userData);
            $order = $this->fillOrderWithInvoiceAddressFromAddress($order, $addressForInvoice);

            if($shoppingCartService->useShipping()) {
                $order->use_shipping = true;
                $order = $this->fillOrderWithShippingAddressFromAddress($order, $addressForShipping);
            }
            else {
                $order->use_shipping = false;
            }

            // Get pricing from shopping cart
            $order->subtotal = $shoppingCartService->getProductTotal();
            $order->shipping_cost = $shoppingCartService->getShippingCost();
            $order->total_without_vat = $shoppingCartService->getTotalWithoutVat();
            $order->total = $shoppingCartService->getTotal();
            $order->deposit = $shoppingCartService->getDeposit();

//            /** @var VatServiceInterface $vatService */
//            $vatService = app()->make(VatServiceInterface::class);
//            $order->total_including_vat = $vatService->calculateIncVatRatePrice($shoppingCartService->getTotal());

            $order->save();

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

                $quantity = $shoppingCartItem->getQuantity();
                $productableClassName = get_class($productable);

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

        return $order;
    }

    private function fillOrderWithUserData(Order $order, $userData): Order
    {
        $skippableKeys = [ 'clientType', 'other_shipping_address', 'vies_valid', 'vies_result'];

        foreach ($userData as $propertyKey => $propertyValue){
            if(in_array($propertyKey, $skippableKeys)) continue;
            $order->{$propertyKey} = $propertyValue;
        }

        return $order;
    }

    /**
     * @param Order $order
     * @param Address $address
     * @return Order
     */
    private function fillOrderWithShippingAddressFromAddress(Order $order, Address $address): Order
    {
        $skippableKeys = ['country'];

        foreach($address->getFillable() as $attributeName) {
            if(in_array($attributeName, $skippableKeys)) continue;
            $order->{'shipping_' . $attributeName} = $address->{$attributeName};
        }

        return $order;
    }

    /**
     * @param Order $order
     * @param Address $address
     * @return Order
     */
    private function fillOrderWithInvoiceAddressFromAddress(Order $order, Address $address)
    {
        $skippableKeys = ['country'];

        foreach($address->getFillable() as $attributeName) {
            if(in_array($attributeName, $skippableKeys)) continue;
            $order->{'invoice_' . $attributeName} = $address->{$attributeName};
        }
        return $order;
    }

    /**
     * Get the order for a given status
     *
     * @param  int  $type
     * @return mixed
     */
    public function getOrdersForType(int $type)
    {

        $orders = Order::where('status', $type)
            ->with('orderedProducts');

        switch ($type) {
            case OrderStatus::AWAITING_FULFILLMENT:
                $orders = $orders->orderBy('date', 'asc');
                break;

            default:
                $orders = $orders->orderBy('date', 'desc');
                break;
        }

        return $orders->get();
    }

    /**
     * Count the orders for a given status
     * @param  int  $type
     * @return int
     */
    public function countOrdersForType(int $type): int
    {
        return Order::where('status', $type)->count();
    }

    /**
     * Find order by order number (or like)
     *
     * @param  string  $orderNumber
     * @return Collection
     */
    public function findByOrderNumber(string $orderNumber): Collection
    {
        return Order::where('order_number', 'LIKE', '%'. $orderNumber)->get();
    }

    /**
     * Load the paid transaction and create a refund for it
     *
     * @param  Order  $order
     */
    public function createRefund(Order $order): void
    {
        $order->load('paidTransactions');
        if($order->paidTransactions->isEmpty()) throw new \LogicException(self::class.': Order has no paid transactions. This should normally not be possible.');

        $pspAdapter = $this->paymentService->getAdapter();
        $paidTransaction = $order->paidTransactions->first();

        $pspAdapter->createDepositRefund($paidTransaction, $order);
    }

    public function handleIntakeProducts(array $intakeProducts, Order $order)
    {

        $shortageTotal = 0;

        foreach ($intakeProducts as $productId => $productValues) {

            $orderedProduct = $order->orderedProducts->where('id', $productId)->first();
            if(!isset($orderedProduct)) abort('Request product "'. $productId .'" is not found within the order.');

            // Deposit handled is not in the array it is false.
            if(!in_array('deposit_handled', array_keys($productValues))) {
                $productValues['deposit_handled'] = false;
            }

            foreach ($productValues as $valueKey => $productValue) {

                switch ($valueKey) {

                    case('deposit_total_shortage'):
                        if(empty($productValue)) $productValue = 0;
                        elseif(is_numeric($productValue)){
                            $orderedProduct->{$valueKey} = $productValue * 100;
                            $shortageTotal += $productValue * 100;
                        }
                        else throw new \UnexpectedValueException('Handling for deposit_total_shortage could not be handled because it is not a numeric.');
                        break;

                    case('deposit_handled'):
                        if($productValue == 'on') $productValue = true;
                        $orderedProduct->deposit_handled = $productValue;
                        break;

                    case('deposit_remarks'):
                        $orderedProduct->{$valueKey} = $productValue;
                        break;

                    case('deposit_broken_units'):
                        $orderedProduct->deposit_broken_units = $productValue;
                        $orderedProduct->shortage_price = $orderedProduct->product->shortage_price;
                        $orderedProduct->deposit_total_shortage = $productValue * $orderedProduct->product->shortage_price;
                        $shortageTotal += $orderedProduct->deposit_total_shortage;
                        break;

                    default:
                        throw new \UnexpectedValueException('Handling not defined for value key:"' . $valueKey . '"');

                }
            }
            $orderedProduct->save();
        }

        $order->shortage_total = $shortageTotal;

        $order->open_fee_note = request('open_fee_note');
        $openFee = (float) request('open_fee');
        if(is_numeric($openFee)){
            $order->open_fee = $openFee * 100;
        }
        else throw new \UnexpectedValueException('Handling for open fee could not be handled because it is not a numeric.');

        $order->status = OrderStatus::VERIFICATION;
        $order->save();
    }

}