241 lines
7.0 KiB
PHP
241 lines
7.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KupShop\PreordersBundle\Entity;
|
|
|
|
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
|
|
use Doctrine\DBAL\Exception as DBALException;
|
|
use Doctrine\DBAL\ParameterType;
|
|
use KupShop\PreordersBundle\Exception\NotFoundException;
|
|
use KupShop\PreordersBundle\Exception\UnsupportedOperationException;
|
|
use KupShop\PreordersBundle\Service\PreorderUtil;
|
|
use Query\Operator as Op;
|
|
|
|
class Preorder implements \ArrayAccess
|
|
{
|
|
private array $preorder;
|
|
private ?array $dates = [];
|
|
|
|
public function __construct(
|
|
public readonly int $id,
|
|
) {
|
|
$this->fetchData();
|
|
}
|
|
|
|
public function getItemsByUser(\User|int $user, ?array $dateIds = null): ?array
|
|
{
|
|
if ($user instanceof \User) {
|
|
$user = $user->id;
|
|
}
|
|
|
|
$items = sqlQueryBuilder()
|
|
->select('pi.*')
|
|
->from('preorders_items', 'pi')
|
|
->leftJoin('pi', 'preorders_dates', 'pd', 'pi.id_preorder_date = pd.id')
|
|
->andWhere(Op::equals([
|
|
'pi.id_user' => $user,
|
|
'pd.id_preorder' => $this->id,
|
|
]));
|
|
|
|
if ($dateIds !== null) {
|
|
$items->andWhere(Op::inIntArray($dateIds, 'pd.id'));
|
|
}
|
|
|
|
$items = $items->execute()->fetchAllAssociative();
|
|
|
|
$resultItems = [];
|
|
|
|
foreach ($items as $item) {
|
|
$productId = (int) $item['id_product'];
|
|
$variationId = $item['id_variation'] ? (int) $item['id_variation'] : null;
|
|
$dateId = (int) $item['id_preorder_date'];
|
|
|
|
$itemKey = $variationId === null ? $productId : "{$productId}_{$variationId}";
|
|
|
|
if (!isset($resultItems[$itemKey])) {
|
|
$resultItems[$itemKey] = $item;
|
|
|
|
$resultItems[$itemKey]['pieces'] = 0;
|
|
$resultItems[$itemKey]['pieces_sent'] = 0;
|
|
|
|
$resultItems[$itemKey]['pieces_per_date'] = [];
|
|
$resultItems[$itemKey]['pieces_sent_per_date'] = [];
|
|
}
|
|
|
|
$resultItems[$itemKey]['pieces_per_date'][$dateId] = (int) $item['pieces'];
|
|
$resultItems[$itemKey]['pieces_sent_per_date'][$dateId] = (int) $item['pieces_sent'];
|
|
|
|
$resultItems[$itemKey]['pieces'] += (int) $item['pieces'];
|
|
$resultItems[$itemKey]['pieces_sent'] += (int) $item['pieces_sent'];
|
|
}
|
|
|
|
return $resultItems;
|
|
}
|
|
|
|
public function getItemsByUserInClosedDates(\User|int $user): ?array
|
|
{
|
|
try {
|
|
$dates = $this->getDates();
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
|
|
$today = (new \DateTimeImmutable())->format('Y-m-d');
|
|
$closedDates = array_filter($dates, fn (array $date) => $date['date_end'] < $today);
|
|
|
|
return $this->getItemsByUser($user, array_column($closedDates, 'id'));
|
|
}
|
|
|
|
public function getSettings(): array
|
|
{
|
|
if (is_string($this->preorder['settings'])) {
|
|
$this->preorder['settings'] = empty($this->preorder['settings']) ?
|
|
[] : json_decode($this->preorder['settings'], true);
|
|
}
|
|
|
|
return $this->preorder['settings'];
|
|
}
|
|
|
|
private function fetchData(): void
|
|
{
|
|
$preorder = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('preorders', 'po')
|
|
->andWhere('po.id = :id')
|
|
->addParameters(['id' => $this->id], [ParameterType::INTEGER]);
|
|
|
|
try {
|
|
$preorder = $preorder->execute()->fetchAllAssociative();
|
|
} catch (\Throwable) {
|
|
$preorder = [];
|
|
}
|
|
|
|
if (count($preorder) !== 1) {
|
|
throw new NotFoundException("Preorder with id={$this->id} was not found!");
|
|
}
|
|
|
|
$this->preorder = $preorder[0];
|
|
}
|
|
|
|
public function offsetExists($offset): bool
|
|
{
|
|
return isset($this->preorder[$offset]);
|
|
}
|
|
|
|
public function offsetGet(mixed $offset): mixed
|
|
{
|
|
return $this->preorder[$offset] ?? null;
|
|
}
|
|
|
|
public function offsetSet(mixed $offset, mixed $value): void
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
public function offsetUnset(mixed $offset): void
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
public function toArray(): array
|
|
{
|
|
$this->getSettings();
|
|
|
|
return $this->preorder;
|
|
}
|
|
|
|
public function getPriceLevelID(?\Decimal $total = null): ?int
|
|
{
|
|
if ($total === null) {
|
|
$total = \DecimalConstants::zero();
|
|
}
|
|
|
|
$dynamicPriceLevel = $this->getActiveDynamicPrice($total);
|
|
|
|
if ($dynamicPriceLevel !== null && PreorderUtil::fieldIsComposedOfDigits($dynamicPriceLevel, 'id_price_level')) {
|
|
return (int) $dynamicPriceLevel['id_price_level'];
|
|
}
|
|
|
|
if (PreorderUtil::fieldIsComposedOfDigits($this->preorder, 'id_price_level')) {
|
|
return (int) $this->preorder['id_price_level'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getPricelistID(?\Decimal $total = null): ?int
|
|
{
|
|
if ($total === null) {
|
|
$total = \DecimalConstants::zero();
|
|
}
|
|
|
|
$dynamicPricelist = $this->getActiveDynamicPrice($total);
|
|
|
|
if ($dynamicPricelist !== null && PreorderUtil::fieldIsComposedOfDigits($dynamicPricelist, 'id_pricelist')) {
|
|
return (int) $dynamicPricelist['id_pricelist'];
|
|
}
|
|
|
|
if (PreorderUtil::fieldIsComposedOfDigits($this->preorder, 'id_pricelist')) {
|
|
return (int) $this->preorder['id_pricelist'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function getActiveDynamicPrice(\Decimal $price): ?array
|
|
{
|
|
foreach (($this->getSettings()['dynamic_prices'] ?? []) as $dynPrice) {
|
|
if (empty($dynPrice['price_from'])) {
|
|
$overLowerBound = true;
|
|
} else {
|
|
$overLowerBound = toDecimal($dynPrice['price_from'])->lowerThanOrEqual($price);
|
|
}
|
|
|
|
if (empty($dynPrice['price_to'])) {
|
|
$underUpperBound = true;
|
|
} else {
|
|
$underUpperBound = $price->lowerThanOrEqual(toDecimal($dynPrice['price_to']));
|
|
}
|
|
|
|
if ($overLowerBound && $underUpperBound) {
|
|
return $dynPrice;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function hasDynamicPrice(): bool
|
|
{
|
|
return count($this->getSettings()['dynamic_prices'] ?? []) > 0;
|
|
}
|
|
|
|
/**
|
|
* @throws DBALDriverException
|
|
* @throws DBALException
|
|
*/
|
|
public function getDates(): array
|
|
{
|
|
if ($this->dates === null) {
|
|
$qb = sqlQueryBuilder()->select('*')
|
|
->from('preorders_dates', 'pd')
|
|
->andWhere(Op::equals(['pd.id_preorder' => $this->id]));
|
|
|
|
$this->dates = $qb->execute()->fetchAllAssociative();
|
|
}
|
|
|
|
return $this->dates;
|
|
}
|
|
|
|
public function getAllowedUsersGroups(): array
|
|
{
|
|
return $this->preorder['settings']['users_groups'] ?? [];
|
|
}
|
|
|
|
public function isAllowed(\User $user): bool
|
|
{
|
|
return count(array_intersect($this->getAllowedUsersGroups(), array_keys($user->getGroups()))) > 0;
|
|
}
|
|
}
|