<commit_before><?php

/**
 * Wallee Shopware
 *
 * This Shopware extension enables to process payments with Wallee (https://wallee.com/).
 *
 * @package Wallee_Payment
 * @author customweb GmbH (http://www.customweb.com/)
 * @license http://www.apache.org/licenses/LICENSE-2.0  Apache Software License (ASL 2.0)
 * @link https://github.com/wallee-payment/shopware
 */

namespace WalleePayment\Components;

use Shopware\Models\Order\Order;
use Shopware\Models\Order\Detail;
use Shopware\Components\Model\ModelManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use WalleePayment\Components\Provider\Currency as CurrencyProvider;

class LineItem extends AbstractService
{
    const ORDER_DETAIL_MODE_DEFAULT_ARTICLE = 0;

    const ORDER_DETAIL_MODE_PREMIUM_ARTICLE = 1;

    const ORDER_DETAIL_MODE_VOUCHER = 2;

    const ORDER_DETAIL_MODE_CUSTOMERGROUP_DISCOUNT = 3;

    const ORDER_DETAIL_MODE_PAYMENT_SURCHARGE_DISCOUNT = 4;

    const ORDER_DETAIL_MODE_BUNDLE_DISCOUNT = 10;

    const ORDER_DETAIL_MODE_TRUSTED_SHOP_ARTICLE = 12;

    /**
     *
     * @var ModelManager
     */
    private $modelManager;

    /**
     *
     * @var CurrencyProvider
     */
    private $currencyProvider;

    /**
     * Constructor.
     *
     * @param ContainerInterface $container
     * @param ModelManager $modelManager
     * @param CurrencyProvider $currencyProvider
     */
    public function __construct(ContainerInterface $container, ModelManager $modelManager, CurrencyProvider $currencyProvider)
    {
        parent::__construct($container);
        $this->modelManager = $modelManager;
        $this->currencyProvider = $currencyProvider;
    }

    public function collectLineItems(Order $order)
    {
        $lineItems = [];

        $details = $order->getDetails();
        foreach ($details as $detail) {
            $type = $this->getType($detail);
            /* @var Detail $detail */
            $lineItem = new \Wallee\Sdk\Model\LineItemCreate();
            $lineItem->setAmountIncludingTax($this->roundAmount($this->getAmountIncludingTax($order, $detail), $order->getCurrency()));
            $lineItem->setName($detail->getArticleName());
            $lineItem->setQuantity($detail->getQuantity());
            $lineItem->setShippingRequired($type == \Wallee\Sdk\Model\LineItemType::PRODUCT && ! $detail->getEsdArticle());
            $lineItem->setSku($detail->getArticleNumber());
            $lineItem->setTaxes([
                $detail->getTax()
                    ->getId() != 0 ? $this->getTax($detail->getTaxRate(), $detail->getTax()
                    ->getName()) : $this->getBestMatchingTax($detail->getTaxRate())
            ]);
            $lineItem->setType($type);
            $lineItem->setUniqueId($detail->getId());
            $lineItems[] = $this->cleanLineItem($lineItem);
        }

        if ($order->getInvoiceShipping() > 0) {
            if ($order->getDispatch() instanceof \Shopware\Models\Dispatch\Dispatch) {
                $shippingMethodName = $order->getDispatch()->getName();
            } else {
                $shippingMethodName = $this->container->get('snippets')
                    ->getNamespace('frontend/wallee_payment/main')
                    ->get('line_item/shipping', 'Shipping');
            }

            $lineItem = new \Wallee\Sdk\Model\LineItemCreate();
            $lineItem->setAmountIncludingTax($this->roundAmount($order->getInvoiceShipping(), $order->getCurrency()));
            $lineItem->setName($shippingMethodName);
            $lineItem->setQuantity(1);
            $lineItem->setShippingRequired(false);
            $lineItem->setSku('shipping');
            $lineItem->setTaxes([
                $this->getShippingTax($order)
            ]);
            $lineItem->setType(\Wallee\Sdk\Model\LineItemType::SHIPPING);
            $lineItem->setUniqueId('shipping');
            $lineItems[] = $this->cleanLineItem($lineItem);
        }
        
        if (abs($this->getTotalAmountIncludingTax($lineItems) - $order->getInvoiceAmount()) > 0.00000001) {
            throw new \Exception('The line item total amount does not match the order\'s invoice amount.');
        }

        return $lineItems;
    }

    /**
     * Returns the total amount including tax of the given line items.
     *
     * @param \Wallee\Sdk\Model\LineItem[] $lineItems
     * @return float
     */
    public function getTotalAmountIncludingTax(array $lineItems)
    {
        $sum = 0;
        foreach ($lineItems as $lineItem) {
            $sum += $lineItem->getAmountIncludingTax();
        }

        return $sum;
    }

    private function getAmountIncludingTax(Order $order, Detail $detail)
    {
        $amountIncludingTax = $detail->getPrice() * $detail->getQuantity();
        if ($order->getNet() && ! $order->getTaxFree()) {
            $amountIncludingTax = $amountIncludingTax / 100 * (100 + $detail->getTaxRate());
        }
        return $amountIncludingTax;
    }

    private function getType(Detail $detail)
    {
        switch ($detail->getMode()) {
            case self::ORDER_DETAIL_MODE_VOUCHER:
            case self::ORDER_DETAIL_MODE_CUSTOMERGROUP_DISCOUNT:
            case self::ORDER_DETAIL_MODE_BUNDLE_DISCOUNT:
                return \Wallee\Sdk\Model\LineItemType::DISCOUNT;
            case self::ORDER_DETAIL_MODE_PAYMENT_SURCHARGE_DISCOUNT:
                if ($detail->getPrice() > 0) {
                    return \Wallee\Sdk\Model\LineItemType::FEE;
                } else {
                    return \Wallee\Sdk\Model\LineItemType::DISCOUNT;
                }
            case self::ORDER_DETAIL_MODE_DEFAULT_ARTICLE:
            case self::ORDER_DETAIL_MODE_PREMIUM_ARTICLE:
            case self::ORDER_DETAIL_MODE_TRUSTED_SHOP_ARTICLE:
            default:
                return \Wallee\Sdk\Model\LineItemType::PRODUCT;
        }
    }

    private function getTax($rate, $title)
    {<commit_msg>Fix line item price calculation.<commit_after><?php

/**
 * Wallee Shopware
 *
 * This Shopware extension enables to process payments with Wallee (https://wallee.com/).
 *
 * @package Wallee_Payment
 * @author customweb GmbH (http://www.customweb.com/)
 * @license http://www.apache.org/licenses/LICENSE-2.0  Apache Software License (ASL 2.0)
 * @link https://github.com/wallee-payment/shopware
 */

namespace WalleePayment\Components;

use Shopware\Models\Order\Order;
use Shopware\Models\Order\Detail;
use Shopware\Components\Model\ModelManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use WalleePayment\Components\Provider\Currency as CurrencyProvider;

class LineItem extends AbstractService
{
    const ORDER_DETAIL_MODE_DEFAULT_ARTICLE = 0;

    const ORDER_DETAIL_MODE_PREMIUM_ARTICLE = 1;

    const ORDER_DETAIL_MODE_VOUCHER = 2;

    const ORDER_DETAIL_MODE_CUSTOMERGROUP_DISCOUNT = 3;

    const ORDER_DETAIL_MODE_PAYMENT_SURCHARGE_DISCOUNT = 4;

    const ORDER_DETAIL_MODE_BUNDLE_DISCOUNT = 10;

    const ORDER_DETAIL_MODE_TRUSTED_SHOP_ARTICLE = 12;

    /**
     *
     * @var ModelManager
     */
    private $modelManager;

    /**
     *
     * @var CurrencyProvider
     */
    private $currencyProvider;

    /**
     * Constructor.
     *
     * @param ContainerInterface $container
     * @param ModelManager $modelManager
     * @param CurrencyProvider $currencyProvider
     */
    public function __construct(ContainerInterface $container, ModelManager $modelManager, CurrencyProvider $currencyProvider)
    {
        parent::__construct($container);
        $this->modelManager = $modelManager;
        $this->currencyProvider = $currencyProvider;
    }

    public function collectLineItems(Order $order)
    {
        $lineItems = [];

        $details = $order->getDetails();
        foreach ($details as $detail) {
            $type = $this->getType($detail);
            /* @var Detail $detail */
            $lineItem = new \Wallee\Sdk\Model\LineItemCreate();
            $lineItem->setAmountIncludingTax($this->roundAmount($this->getAmountIncludingTax($order, $detail), $order->getCurrency()));
            $lineItem->setName($detail->getArticleName());
            $lineItem->setQuantity($detail->getQuantity());
            $lineItem->setShippingRequired($type == \Wallee\Sdk\Model\LineItemType::PRODUCT && ! $detail->getEsdArticle());
            $lineItem->setSku($detail->getArticleNumber());
            $lineItem->setTaxes([
                $detail->getTax()
                    ->getId() != 0 ? $this->getTax($detail->getTaxRate(), $detail->getTax()
                    ->getName()) : $this->getBestMatchingTax($detail->getTaxRate())
            ]);
            $lineItem->setType($type);
            $lineItem->setUniqueId($detail->getId());
            $lineItems[] = $this->cleanLineItem($lineItem);
        }

        if ($order->getInvoiceShipping() > 0) {
            if ($order->getDispatch() instanceof \Shopware\Models\Dispatch\Dispatch) {
                $shippingMethodName = $order->getDispatch()->getName();
            } else {
                $shippingMethodName = $this->container->get('snippets')
                    ->getNamespace('frontend/wallee_payment/main')
                    ->get('line_item/shipping', 'Shipping');
            }

            $lineItem = new \Wallee\Sdk\Model\LineItemCreate();
            $lineItem->setAmountIncludingTax($this->roundAmount($order->getInvoiceShipping(), $order->getCurrency()));
            $lineItem->setName($shippingMethodName);
            $lineItem->setQuantity(1);
            $lineItem->setShippingRequired(false);
            $lineItem->setSku('shipping');
            $lineItem->setTaxes([
                $this->getShippingTax($order)
            ]);
            $lineItem->setType(\Wallee\Sdk\Model\LineItemType::SHIPPING);
            $lineItem->setUniqueId('shipping');
            $lineItems[] = $this->cleanLineItem($lineItem);
        }
        
        if (abs($this->getTotalAmountIncludingTax($lineItems) - $order->getInvoiceAmount()) > 0.00000001) {
            throw new \Exception('The line item total amount does not match the order\'s invoice amount.');
        }

        return $lineItems;
    }

    /**
     * Returns the total amount including tax of the given line items.
     *
     * @param \Wallee\Sdk\Model\LineItem[] $lineItems
     * @return float
     */
    public function getTotalAmountIncludingTax(array $lineItems)
    {
        $sum = 0;
        foreach ($lineItems as $lineItem) {
            $sum += $lineItem->getAmountIncludingTax();
        }

        return $sum;
    }

    private function getAmountIncludingTax(Order $order, Detail $detail)
    {
        $amountIncludingTax = $this->roundAmount($detail->getPrice(), $order->getCurrency()) * $detail->getQuantity();
        if ($order->getNet() && ! $order->getTaxFree()) {
            $amountIncludingTax = $amountIncludingTax / 100 * (100 + $detail->getTaxRate());
        }
        return $amountIncludingTax;
    }

    private function getType(Detail $detail)
    {
        switch ($detail->getMode()) {
            case self::ORDER_DETAIL_MODE_VOUCHER:
            case self::ORDER_DETAIL_MODE_CUSTOMERGROUP_DISCOUNT:
            case self::ORDER_DETAIL_MODE_BUNDLE_DISCOUNT:
                return \Wallee\Sdk\Model\LineItemType::DISCOUNT;
            case self::ORDER_DETAIL_MODE_PAYMENT_SURCHARGE_DISCOUNT:
                if ($detail->getPrice() > 0) {
                    return \Wallee\Sdk\Model\LineItemType::FEE;
                } else {
                    return \Wallee\Sdk\Model\LineItemType::DISCOUNT;
                }
            case self::ORDER_DETAIL_MODE_DEFAULT_ARTICLE:
            case self::ORDER_DETAIL_MODE_PREMIUM_ARTICLE:
            case self::ORDER_DETAIL_MODE_TRUSTED_SHOP_ARTICLE:
            default:
                return \Wallee\Sdk\Model\LineItemType::PRODUCT;
        }
    }

    private function getTax($rate, $title)
    {
{'fraction_non_alphanumeric': 0.12644641958745598, 'fraction_numerical': 0.005534127117222874, 'mean_word_length': 2.5276545400769, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 131, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3516447', 'n_tokens_mistral': 3638, 'n_tokens_neox': 3450, 'n_words': 553}