JEMBOT MAWOT Bypass Shell

Current Path : /home/cinepatreb/billetterie/modules/mollie/src/Service/
Upload File :
Current File : /home/cinepatreb/billetterie/modules/mollie/src/Service/CartLinesService.php

<?php
/**
 * Mollie       https://www.mollie.nl
 *
 * @author      Mollie B.V. <info@mollie.nl>
 * @copyright   Mollie B.V.
 * @license     https://github.com/mollie/PrestaShop/blob/master/LICENSE.md
 *
 * @see        https://github.com/mollie/PrestaShop
 * @codingStandardsIgnoreStart
 */

namespace Mollie\Service;

use Cart;
use Mollie\Adapter\Context;
use Mollie\Adapter\ToolsAdapter;
use Mollie\Config\Config;
use Mollie\DTO\Line;
use Mollie\DTO\Object\Amount;
use Mollie\DTO\PaymentFeeData;
use Mollie\Utility\CalculationUtility;
use Mollie\Utility\CartPriceUtility;
use Mollie\Utility\NumberUtility;
use Mollie\Utility\TextFormatUtility;

if (!defined('_PS_VERSION_')) {
    exit;
}

class CartLinesService
{
    /**
     * @var VoucherService
     */
    private $voucherService;

    /**
     * @var LanguageService
     */
    private $languageService;

    /**
     * @var ToolsAdapter
     */
    private $tools;
    private $context;

    public function __construct(LanguageService $languageService, VoucherService $voucherService, ToolsAdapter $tools, Context $context)
    {
        $this->voucherService = $voucherService;
        $this->languageService = $languageService;
        $this->tools = $tools;
        $this->context = $context;
    }

    /**
     * @param float $amount
     * @param PaymentFeeData $paymentFeeData
     * @param string $currencyIsoCode
     * @param array $cartSummary
     * @param float $shippingCost
     * @param array $cartItems
     * @param bool $psGiftWrapping
     * @param string $selectedVoucherCategory
     *
     * @return array
     *
     * @throws \PrestaShop\Decimal\Exception\DivisionByZeroException
     */
    public function getCartLines(
        $amount,
        $paymentFeeData,
        $currencyIsoCode,
        $cartSummary,
        $shippingCost,
        $cartItems,
        $psGiftWrapping,
        $selectedVoucherCategory
    ) {
        // TODO refactor whole service, split order line append into separate services and test them individually at least!!!

        $apiRoundingPrecision = Config::API_ROUNDING_PRECISION;
        $vatRatePrecision = Config::VAT_RATE_ROUNDING_PRECISION;

        $totalPrice = round($amount, $apiRoundingPrecision);
        $roundedShippingCost = round($shippingCost, $apiRoundingPrecision);
        foreach ($cartSummary['discounts'] as $discount) {
            if ($discount['free_shipping']) {
                $roundedShippingCost = 0;
            }
        }

        $wrappingPrice = $psGiftWrapping ? round($cartSummary['total_wrapping'], $apiRoundingPrecision) : 0;
        $totalDiscounts = isset($cartSummary['total_discounts']) ? $cartSummary['total_discounts'] : 0;
        $remaining = round(
            CalculationUtility::getCartRemainingPrice((float) $totalPrice, (float) $roundedShippingCost, (float) $wrappingPrice),
            $apiRoundingPrecision
        );

        $orderLines = [];
        /* Item */
        list($orderLines, $remaining) = $this->createProductLines($cartItems, $apiRoundingPrecision, $cartSummary['gift_products'], $orderLines, $selectedVoucherCategory, $remaining);

        // Add discount if applicable
        list($orderLines, $remaining) = $this->addDiscountsToProductLines($totalDiscounts, $apiRoundingPrecision, $orderLines, $remaining);

        // Compensate for order total rounding inaccuracies
        $orderLines = $this->compositeRoundingInaccuracies($remaining, $apiRoundingPrecision, $orderLines);

        // Fill the order lines with the rest of the data (tax, total amount, etc.)
        $orderLines = $this->fillProductLinesWithRemainingData($orderLines, $apiRoundingPrecision, $vatRatePrecision);

        // Add shipping
        $orderLines = $this->addShippingLine($roundedShippingCost, $cartSummary, $apiRoundingPrecision, $orderLines);

        // Add wrapping
        $orderLines = $this->addWrappingLine($wrappingPrice, $cartSummary, $vatRatePrecision, $apiRoundingPrecision, $orderLines);

        // Add fee
        $orderLines = $this->addPaymentFeeLine($paymentFeeData, $apiRoundingPrecision, $orderLines);

        // Ungroup all the cart lines, just one level
        $newItems = $this->ungroupLines($orderLines);

        // Convert floats to strings for the Mollie API and add additional info
        return $this->convertToLineArray($newItems, $currencyIsoCode, $apiRoundingPrecision);
    }

    /**
     * Spread the cart line amount evenly.
     *
     * Optionally split into multiple lines in case of rounding inaccuracies
     *
     * @param array[] $cartLineGroup Cart Line Group WITHOUT VAT details (except target VAT rate)
     * @param float $newTotal
     *
     * @return array[]
     *
     * @since 3.2.2
     * @since 3.3.3 Omits VAT details
     */
    public static function spreadCartLineGroup($cartLineGroup, $newTotal)
    {
        $apiRoundingPrecision = Config::API_ROUNDING_PRECISION;
        $newTotal = round($newTotal, $apiRoundingPrecision);
        $quantity = array_sum(array_column($cartLineGroup, 'quantity'));
        $newCartLineGroup = [];
        $spread = CartPriceUtility::spreadAmountEvenly($newTotal, $quantity);
        foreach ($spread as $unitPrice => $qty) {
            $newCartLineGroup[] = [
                'name' => $cartLineGroup[0]['name'],
                'quantity' => $qty,
                'unitPrice' => (float) $unitPrice,
                'totalAmount' => (float) $unitPrice * $qty,
                'sku' => isset($cartLineGroup[0]['sku']) ? $cartLineGroup[0]['sku'] : '',
                'targetVat' => $cartLineGroup[0]['targetVat'],
                'category' => $cartLineGroup[0]['category'],
            ];
        }

        return $newCartLineGroup;
    }

    /**
     * @param int $apiRoundingPrecision
     * @param array $giftProducts
     * @param string $selectedVoucherCategory
     * @param float $remaining
     *
     * @return array
     */
    private function createProductLines(array $cartItems, $apiRoundingPrecision, $giftProducts, array $orderLines, $selectedVoucherCategory, $remaining)
    {
        foreach ($cartItems as $cartItem) {
            // Get the rounded total w/ tax
            $roundedTotalWithTax = round($cartItem['total_wt'], $apiRoundingPrecision);

            // Skip if no qty
            $quantity = (int) $cartItem['cart_quantity'];
            if ($quantity <= 0 || $cartItem['price_wt'] <= 0) {
                continue;
            }

            // Generate the product hash
            $idProduct = TextFormatUtility::formatNumber($cartItem['id_product'], 0);
            $idProductAttribute = TextFormatUtility::formatNumber($cartItem['id_product_attribute'], 0);
            $idCustomization = TextFormatUtility::formatNumber($cartItem['id_customization'], 0);

            $productHash = "{$idProduct}¤{$idProductAttribute}¤{$idCustomization}";

            foreach ($giftProducts as $gift_product) {
                if ($gift_product['id_product'] === $cartItem['id_product']) {
                    $quantity = NumberUtility::minus($quantity, $gift_product['cart_quantity']);

                    $productHashGift = "{$idProduct}¤{$idProductAttribute}¤{$idCustomization}gift";
                    $orderLines[$productHashGift][] = [
                        'name' => $cartItem['name'],
                        'sku' => $productHashGift,
                        'targetVat' => (float) $cartItem['rate'],
                        'quantity' => $gift_product['cart_quantity'],
                        'unitPrice' => 0,
                        'totalAmount' => 0,
                        'category' => '',
                        'product_url' => $this->context->getProductLink($cartItem['id_product']),
                        'image_url' => $this->context->getImageLink($cartItem['link_rewrite'], $cartItem['id_image']),
                    ];
                    continue;
                }
            }

            if ((int) $quantity <= 0) {
                continue;
            }

            // Try to spread this product evenly and account for rounding differences on the order line
            $orderLines[$productHash][] = [
                'name' => $cartItem['name'],
                'sku' => $productHash,
                'targetVat' => (float) $cartItem['rate'],
                'quantity' => $quantity,
                'unitPrice' => round($cartItem['price_wt'], $apiRoundingPrecision),
                'totalAmount' => (float) $roundedTotalWithTax,
                'category' => $this->voucherService->getVoucherCategory($cartItem, $selectedVoucherCategory),
                'product_url' => $this->context->getProductLink($cartItem['id_product']),
                'image_url' => $this->context->getImageLink($cartItem['link_rewrite'], $cartItem['id_image']),
            ];
            $remaining -= $roundedTotalWithTax;
        }

        return [$orderLines, $remaining];
    }

    /**
     * @param float $totalDiscounts
     * @param int $apiRoundingPrecision
     * @param array $orderLines
     * @param float $remaining
     *
     * @return array
     */
    private function addDiscountsToProductLines($totalDiscounts, $apiRoundingPrecision, $orderLines, $remaining)
    {
        if ($totalDiscounts >= 0.01) {
            $orderLines['discount'] = [
                [
                    'name' => 'Discount',
                    'type' => 'discount',
                    'quantity' => 1,
                    'unitPrice' => -round($totalDiscounts, $apiRoundingPrecision),
                    'totalAmount' => -round($totalDiscounts, $apiRoundingPrecision),
                    'targetVat' => 0,
                    'category' => '',
                ],
            ];
            $remaining = NumberUtility::plus($remaining, $totalDiscounts);
        }

        return [$orderLines, $remaining];
    }

    /**
     * @param float $remaining
     * @param int $apiRoundingPrecision
     * @param array $orderLines
     *
     * @return array
     */
    private function compositeRoundingInaccuracies($remaining, $apiRoundingPrecision, $orderLines)
    {
        $remaining = round($remaining, $apiRoundingPrecision);
        if ($remaining < 0) {
            foreach (array_reverse($orderLines) as $hash => $items) {
                // Grab the line group's total amount
                $totalAmount = array_sum(array_column($items, 'totalAmount'));

                // Remove when total is lower than remaining
                if ($totalAmount <= $remaining) {
                    // The line total is less than remaining, we should remove this line group and continue
                    $remaining = $remaining - $totalAmount;
                    unset($items);
                    continue;
                }

                // Otherwise spread the cart line again with the updated total
                //TODO: check why remaining comes -100 when testing and new total becomes different
                $orderLines[$hash] = static::spreadCartLineGroup($items, $totalAmount + $remaining);
                break;
            }
        } elseif ($remaining > 0) {
            foreach (array_reverse($orderLines) as $hash => $items) {
                // Grab the line group's total amount
                $totalAmount = array_sum(array_column($items, 'totalAmount'));
                // Otherwise spread the cart line again with the updated total
                $orderLines[$hash] = static::spreadCartLineGroup($items, $totalAmount + $remaining);
                break;
            }
        }

        return $orderLines;
    }

    /**
     * @param int $apiRoundingPrecision
     * @param int $vatRatePrecision
     *
     * @return array
     *
     * @throws \PrestaShop\Decimal\Exception\DivisionByZeroException
     */
    private function fillProductLinesWithRemainingData(array $orderLines, $apiRoundingPrecision, $vatRatePrecision)
    {
        foreach ($orderLines as $productHash => $aItem) {
            $orderLines[$productHash] = array_map(function ($line) use ($apiRoundingPrecision, $vatRatePrecision) {
                $quantity = (int) $line['quantity'];
                $targetVat = $line['targetVat'];
                $unitPrice = $line['unitPrice'];
                $unitPriceNoTax = round(CalculationUtility::getUnitPriceNoTax(
                    $line['unitPrice'],
                    $targetVat
                ),
                    $apiRoundingPrecision
                );

                // Calculate VAT
                $totalAmount = $line['totalAmount'];
                $actualVatRate = 0;
                if ($unitPriceNoTax > 0) {
                    $actualVatRate = round(
                        $vatAmount = CalculationUtility::getActualVatRate($unitPrice, $unitPriceNoTax, $quantity),
                        $vatRatePrecision
                    );
                }
                $vatRateWithPercentages = NumberUtility::plus($actualVatRate, 100);
                $vatAmount = NumberUtility::times(
                    $totalAmount,
                    NumberUtility::divide($actualVatRate, $vatRateWithPercentages)
                );

                $newItem = [
                    'name' => $line['name'],
                    'category' => $line['category'],
                    'quantity' => (int) $quantity,
                    'unitPrice' => round($unitPrice, $apiRoundingPrecision),
                    'totalAmount' => round($totalAmount, $apiRoundingPrecision),
                    'vatRate' => round($actualVatRate, $apiRoundingPrecision),
                    'vatAmount' => round($vatAmount, $apiRoundingPrecision),
                    'product_url' => $line['product_url'] ?? null,
                    'image_url' => $line['image_url'] ?? null,
                ];
                if (isset($line['sku'])) {
                    $newItem['sku'] = $line['sku'];
                }

                return $newItem;
            }, $aItem);
        }

        return $orderLines;
    }

    /**
     * @param float $roundedShippingCost
     * @param array $cartSummary
     * @param int $apiRoundingPrecision
     *
     * @return array
     */
    private function addShippingLine($roundedShippingCost, $cartSummary, $apiRoundingPrecision, array $orderLines)
    {
        if (round($roundedShippingCost, 2) > 0) {
            $shippingVatRate = round(($cartSummary['total_shipping'] - $cartSummary['total_shipping_tax_exc']) / $cartSummary['total_shipping_tax_exc'] * 100, $apiRoundingPrecision);

            $orderLines['shipping'] = [
                [
                    'name' => $this->languageService->lang('Shipping'),
                    'quantity' => 1,
                    'unitPrice' => round($roundedShippingCost, $apiRoundingPrecision),
                    'totalAmount' => round($roundedShippingCost, $apiRoundingPrecision),
                    'vatAmount' => round($roundedShippingCost * $shippingVatRate / ($shippingVatRate + 100), $apiRoundingPrecision),
                    'vatRate' => $shippingVatRate,
                ],
            ];
        }

        return $orderLines;
    }

    /**
     * @param float $wrappingPrice
     * @param int $vatRatePrecision
     * @param int $apiRoundingPrecision
     *
     * @return array
     */
    private function addWrappingLine($wrappingPrice, array $cartSummary, $vatRatePrecision, $apiRoundingPrecision, array $orderLines)
    {
        if (round($wrappingPrice, 2) > 0) {
            $wrappingVatRate = round(
                CalculationUtility::getActualVatRate(
                    $cartSummary['total_wrapping'],
                    $cartSummary['total_wrapping_tax_exc']
                ),
                $vatRatePrecision
            );

            $orderLines['wrapping'] = [
                [
                    'name' => $this->languageService->lang('Gift wrapping'),
                    'quantity' => 1,
                    'unitPrice' => round($wrappingPrice, $apiRoundingPrecision),
                    'totalAmount' => round($wrappingPrice, $apiRoundingPrecision),
                    'vatAmount' => round($wrappingPrice * $wrappingVatRate / ($wrappingVatRate + 100), $apiRoundingPrecision),
                    'vatRate' => $wrappingVatRate,
                ],
            ];
        }

        return $orderLines;
    }

    /**
     * @param PaymentFeeData $paymentFeeData
     * @param int $apiRoundingPrecision
     *
     * @return array
     */
    private function addPaymentFeeLine($paymentFeeData, $apiRoundingPrecision, array $orderLines)
    {
        if (!$paymentFeeData->isActive()) {
            return $orderLines;
        }

        $orderLines['surcharge'] = [
            [
                'name' => $this->languageService->lang('Payment fee'),
                'sku' => Config::PAYMENT_FEE_SKU,
                'quantity' => 1,
                'unitPrice' => round($paymentFeeData->getPaymentFeeTaxIncl(), $apiRoundingPrecision),
                'totalAmount' => round($paymentFeeData->getPaymentFeeTaxIncl(), $apiRoundingPrecision),
                'vatAmount' => NumberUtility::minus($paymentFeeData->getPaymentFeeTaxIncl(), $paymentFeeData->getPaymentFeeTaxExcl()),
                'vatRate' => $paymentFeeData->getTaxRate(),
            ],
        ];

        return $orderLines;
    }

    /**
     * @return array
     */
    private function ungroupLines(array $orderLines)
    {
        $newItems = [];
        foreach ($orderLines as &$items) {
            foreach ($items as &$item) {
                $newItems[] = $item;
            }
        }

        return $newItems;
    }

    /**
     * @param string $currencyIsoCode
     * @param int $apiRoundingPrecision
     *
     * @return array
     */
    private function convertToLineArray(array $newItems, $currencyIsoCode, $apiRoundingPrecision)
    {
        foreach ($newItems as $index => $item) {
            $line = new Line();
            $line->setName($item['name'] ?: $item['sku']);
            $line->setQuantity((int) $item['quantity']);
            $line->setSku(isset($item['sku']) ? $item['sku'] : '');

            $currency = strtoupper(strtolower($currencyIsoCode));

            if (isset($item['discount'])) {
                $line->setDiscountAmount(new Amount(
                        $currency,
                        TextFormatUtility::formatNumber($item['discount'], $apiRoundingPrecision, '.', '')
                    )
                );
            }

            $line->setUnitPrice(new Amount(
                $currency,
                TextFormatUtility::formatNumber($item['unitPrice'], $apiRoundingPrecision, '.', '')
            ));

            $line->setTotalPrice(new Amount(
                $currency,
                TextFormatUtility::formatNumber($item['totalAmount'], $apiRoundingPrecision, '.', '')
            ));

            $line->setVatAmount(new Amount(
                $currency,
                TextFormatUtility::formatNumber($item['vatAmount'], $apiRoundingPrecision, '.', '')
            ));

            if (isset($item['category'])) {
                $line->setCategory($item['category']);
            }

            $line->setVatRate(TextFormatUtility::formatNumber($item['vatRate'], $apiRoundingPrecision, '.', ''));
            $line->setProductUrl($item['product_url'] ?? null);
            $line->setImageUrl($item['image_url'] ?? null);

            $newItems[$index] = $line;
        }

        return $newItems;
    }
}

xxxxx1.0, XXX xxxx