<commit_before><?php

namespace Ekyna\Bundle\CommerceBundle\Service\Stat;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityRepository;
use Ekyna\Component\Commerce\Order\Model\OrderStates;
use Ekyna\Component\Commerce\Stat\Calculator\StatCalculatorInterface;
use Ekyna\Component\Commerce\Stat\Entity;
use Ekyna\Component\Commerce\Stat\Repository;
use Ekyna\Component\Commerce\Stock\Entity\AbstractStockUnit;
use Ekyna\Component\Commerce\Stock\Model\StockUnitStates;
use Symfony\Bridge\Doctrine\RegistryInterface;

/**
 * Class StatCalculator
 * @package Ekyna\Bundle\CommerceBundle\Service\Stat
 * @author  <NAME> <<EMAIL>>
 */
class StatCalculator implements StatCalculatorInterface
{
    /**
     * @var RegistryInterface
     */
    protected $registry;

    /**
     * @var string
     */
    protected $orderClass;

    /**
     * @var \Ekyna\Component\Commerce\Stat\Repository\StockStatRepositoryInterface
     */
    protected $stockStatRepository;

    /**
     * @var \Ekyna\Component\Commerce\Stat\Repository\OrderStatRepositoryInterface
     */
    protected $orderStatRepository;

    /**
     * @var EntityRepository
     */
    protected $stockUnitRepository;

    /**
     * @var EntityRepository
     */
    protected $orderRepository;


    /**
     * Constructor.
     *
     * @param RegistryInterface $registry
     * @param string            $orderClass
     */
    public function __construct(RegistryInterface $registry, $orderClass)
    {
        $this->registry = $registry;
        $this->orderClass = $orderClass;
    }

    /**
     * @inheritdoc
     */
    public function calculateStockStats()
    {
        $qb = $this->getStockUnitRepository()->createQueryBuilder('u');
        $ex = $qb->expr();

        return $qb
            ->select([
                'SUM((u.receivedQuantity + u.adjustedQuantity - u.shippedQuantity) * u.netPrice) as in_value',
                'SUM((u.soldQuantity - u.shippedQuantity) * u.netPrice) as sold_value'
            ])
            ->andWhere($ex->in('u.state', ':state'))
            ->getQuery()
            ->useQueryCache(true)
            ->setParameter(':state', [StockUnitStates::STATE_PENDING, StockUnitStates::STATE_READY])
            ->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR);
    }

    /**
     * @inheritdoc
     */
    public function calculateDayOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from->setTime(0,0,0);

        $to = clone $date;
        $to->setTime(23,59,59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    public function calculateMonthOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from
            ->modify('first day of this month')
            ->setTime(0,0,0);

        $to = clone $date;
        $to
            ->modify('last day of this month')
            ->setTime(23,59,59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    public function calculateYearOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from
            ->modify('first day of january ' . $date->format('Y'))
            ->setTime(0,0,0);

        $to = clone $date;
        $to
            ->modify('last day of december ' . $date->format('Y'))
            ->setTime(23,59,59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    protected function calculateOrderStats(\DateTime $from, \DateTime $to)
    {
        $qb = $this->getOrderRepository()->createQueryBuilder('o');
        $ex = $qb->expr();

        return $qb
            ->select([
                'SUM(o.netTotal - o.shipmentAmount) as revenue',
                'SUM(o.shipmentAmount) as shipping',
                'SUM(o.marginTotal) as margin',
                'COUNT(o.id) as orders',
                'SUM(o.itemsCount) as items',
                'AVG(o.netTotal) as average',
            ])
            ->andWhere($ex->between('o.createdAt', ':from', ':to'))
            ->andWhere($ex->in('o.state', ':state'))
            ->getQuery()
            ->useQueryCache(true)
            ->setParameter('from', $from, Type::DATETIME)
            ->setParameter('to', $to, Type::DATETIME)
            ->setParameter('state', [
                OrderStates::STATE_COMPLETED,
                OrderStates::STATE_ACCEPTED,
                OrderStates::STATE_PENDING,
            ])
            ->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR);
    }

    /**
     * Returns the stock unit repository.
     *
     * @return EntityRepository
     */
    protected function getStockUnitRepository()
    {
        if (null !== $this->stockUnitRepository) {
            return $this->stockUnitRepository;
        }

        /** @noinspection PhpIncompatibleReturnTypeInspection */
        return $this->stockUnitRepository = $this->registry->getRepository(AbstractStockUnit::class);
    }

    /**
     * Returns the order repository.<commit_msg>[Commerce] Fixed stat calculator when net or shipping sum is null is null.<commit_after><?php

namespace Ekyna\Bundle\CommerceBundle\Service\Stat;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityRepository;
use Ekyna\Component\Commerce\Order\Model\OrderStates;
use Ekyna\Component\Commerce\Stat\Calculator\StatCalculatorInterface;
use Ekyna\Component\Commerce\Stat\Entity;
use Ekyna\Component\Commerce\Stat\Repository;
use Ekyna\Component\Commerce\Stock\Entity\AbstractStockUnit;
use Ekyna\Component\Commerce\Stock\Model\StockUnitStates;
use Symfony\Bridge\Doctrine\RegistryInterface;

/**
 * Class StatCalculator
 * @package Ekyna\Bundle\CommerceBundle\Service\Stat
 * @author  <NAME> <<EMAIL>>
 */
class StatCalculator implements StatCalculatorInterface
{
    /**
     * @var RegistryInterface
     */
    protected $registry;

    /**
     * @var string
     */
    protected $orderClass;

    /**
     * @var \Ekyna\Component\Commerce\Stat\Repository\StockStatRepositoryInterface
     */
    protected $stockStatRepository;

    /**
     * @var \Ekyna\Component\Commerce\Stat\Repository\OrderStatRepositoryInterface
     */
    protected $orderStatRepository;

    /**
     * @var EntityRepository
     */
    protected $stockUnitRepository;

    /**
     * @var EntityRepository
     */
    protected $orderRepository;


    /**
     * Constructor.
     *
     * @param RegistryInterface $registry
     * @param string            $orderClass
     */
    public function __construct(RegistryInterface $registry, $orderClass)
    {
        $this->registry = $registry;
        $this->orderClass = $orderClass;
    }

    /**
     * @inheritdoc
     */
    public function calculateStockStats()
    {
        $qb = $this->getStockUnitRepository()->createQueryBuilder('u');
        $ex = $qb->expr();

        return $qb
            ->select([
                'SUM((u.receivedQuantity + u.adjustedQuantity - u.shippedQuantity) * u.netPrice) as in_value',
                'SUM((u.soldQuantity - u.shippedQuantity) * u.netPrice) as sold_value',
            ])
            ->andWhere($ex->in('u.state', ':state'))
            ->getQuery()
            ->useQueryCache(true)
            ->setParameter(':state', [StockUnitStates::STATE_PENDING, StockUnitStates::STATE_READY])
            ->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR);
    }

    /**
     * @inheritdoc
     */
    public function calculateDayOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from->setTime(0, 0, 0);

        $to = clone $date;
        $to->setTime(23, 59, 59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    public function calculateMonthOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from
            ->modify('first day of this month')
            ->setTime(0, 0, 0);

        $to = clone $date;
        $to
            ->modify('last day of this month')
            ->setTime(23, 59, 59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    public function calculateYearOrderStats(\DateTime $date)
    {
        $from = clone $date;
        $from
            ->modify('first day of january ' . $date->format('Y'))
            ->setTime(0, 0, 0);

        $to = clone $date;
        $to
            ->modify('last day of december ' . $date->format('Y'))
            ->setTime(23, 59, 59);

        return $this->calculateOrderStats($from, $to);
    }

    /**
     * @inheritdoc
     */
    protected function calculateOrderStats(\DateTime $from, \DateTime $to)
    {
        $qb = $this->getOrderRepository()->createQueryBuilder('o');
        $ex = $qb->expr();

        $result = $qb
            ->select([
                'SUM(o.netTotal) as net',
                'SUM(o.shipmentAmount) as shipping',
                'SUM(o.marginTotal) as margin',
                'COUNT(o.id) as orders',
                'SUM(o.itemsCount) as items',
                'AVG(o.netTotal) as average',
            ])
            ->andWhere($ex->between('o.createdAt', ':from', ':to'))
            ->andWhere($ex->in('o.state', ':state'))
            ->getQuery()
            ->useQueryCache(true)
            ->setParameter('from', $from, Type::DATETIME)
            ->setParameter('to', $to, Type::DATETIME)
            ->setParameter('state', [
                OrderStates::STATE_COMPLETED,
                OrderStates::STATE_ACCEPTED,
                OrderStates::STATE_PENDING,
            ])
            ->getOneOrNullResult(AbstractQuery::HYDRATE_SCALAR);

        if ($result) {
            return [
                'revenue'  => (string)round($result['net'] - $result['shipping'], 3),
                'shipping' => (string)round($result['shipping'], 3),
                'margin'   => (string)round($result['margin'], 3),
                'orders'   => (string)$result['orders'],
                'items'    => (string)$result['items'],
                'average'  => (string)round($result['average'], 3),
            ];
        }

        return null;
    }

    /**
     * Returns the stock unit repository.
     *
     * @return EntityRepository
     */
    protected function getStockUnitRepository()
    {
        if (null !== $this->stockUnitRepository) {
            return $this->stockUnitRepository;
        }

        /** @noinspection PhpIncompatibleReturnTypeInspection */
        return $this->stockUnitRepository = $this->registry->getRepository(AbstractStockUnit::class);
    }

    /**
     * Returns the order repository.
{'fraction_non_alphanumeric': 0.13990804166275686, 'fraction_numerical': 0.005442432204185043, 'mean_word_length': 2.1328630217519104, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '4799452', 'n_tokens_mistral': 3224, 'n_tokens_neox': 3045, 'n_words': 546}