Files
kupshop/bundles/KupShop/ShoppingListBundle/Util/ShoppingListUtil.php
2025-08-02 16:30:27 +02:00

396 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\ShoppingListBundle\Util;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\GraphQLBundle\EventListener\JsShopRefreshListener;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\UserContext;
use KupShop\OrderingBundle\Cart;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use KupShop\ShoppingListBundle\Email\ShareShoppingListEmail;
use KupShop\ShoppingListBundle\Entity\ShoppingListEntity;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Service\Attribute\Required;
class ShoppingListUtil
{
#[Required]
public ShoppingListEntity $shoppingListEntity;
#[Required]
public PurchaseUtil $purchaseUtil;
#[Required]
public Cart $cart;
#[Required]
public UserContext $userContext;
#[Required]
public SessionInterface $session;
#[Required]
public ShareShoppingListEmail $shareShoppingListEmail;
public function getShoppingList(?int $id): ShoppingListEntity
{
$sl = $this->shoppingListEntity;
$list = sqlQueryBuilder()->select('*')
->from('shopping_list')
->where(
Operator::equals(
['id' => $id]
)
)
->execute()->fetch();
if (!$list) {
return $sl;
}
$sl->setId($list['id']);
$sl->setIdUser($list['id_user']);
$sl->setName($list['name']);
$sl->setNote($list['note']);
$sl->setDate($list['date']);
$sl->setHash($list['hash']);
$sl->setLabel($list['label']);
return $sl;
}
public function processShoppingListItems($id_shopping_list, $items, $duplicate = false)
{
if (is_iterable($items)) {
foreach ($items as $id => $item) {
if ($id == 0) {
continue;
}
if ($id > 0 && isset($item['delete'])) {
$this->removeProductFromList($item['id']);
} elseif ($id > 0 && !$duplicate) {
sqlQueryBuilder()->update('shopping_list_products')
->set('pieces', $item['pieces'])
->where(Operator::equals(['id' => $item['id']]))->execute();
} elseif (!empty($item['id_product'])) {
$this->addProductToShoppingList(
(int) $id_shopping_list,
(int) $item['id_product'],
(int) $item['id_variation'] ?: null,
floatval($item['pieces']));
}
}
}
}
public function renameShoppingList($id_shopping_list, $new_name): void
{
sqlQueryBuilder()->update('shopping_list')->directValues(['name' => $new_name])->andWhere(Operator::equals(['id' => $id_shopping_list]))->execute();
}
public function validHash(int $slId, string $hash): bool
{
return (bool) sqlQueryBuilder()->select('count(id)')
->from('shopping_list')
->where(Operator::equals([
'id' => $slId,
'hash' => $hash,
]))
->execute()->fetchOne();
}
public function createShoppingList(string $name, ?string $label = null): int
{
$created = date('Y-m-d');
sqlQueryBuilder()->insert('shopping_list')
->directValues([
'id_user' => $this->userContext->getActiveId(),
'date' => $created,
'name' => $name,
'label' => $label,
])->execute();
$insertedId = intval(sqlInsertId());
$this->updateHash($insertedId, $created);
return $insertedId;
}
public function updateHash(int $id, string $created): void
{
sqlQueryBuilder()
->update('shopping_list')->set('hash', ':hash')
->setParameter('hash', $this->createHash($id, $created))
->where(\Query\Operator::equals(['id' => $id]))
->execute();
}
public function createHash(int $id, string $created)
{
return urlencode(
sha1(
getShopUniqueName()
.join('', [
$id,
$created,
])
)
);
}
public function fetchItems(int $idSL, $fromAdmin = false): \ProductList
{
$productList = new \ProductList(findModule(\Modules::PRODUCTS_VARIATIONS));
if (!$fromAdmin) {
$productList->applyDefaultFilterParams();
}
$productList->andSpec(function (QueryBuilder $qb) use ($idSL) {
$qb->join('p', 'shopping_list_products', 'slp', 'slp.id_product = p.id')
->andWhere('id_shopping_list=:id_shopping_list')
->addParameters(['id_shopping_list' => $idSL]);
if (findModule(\Modules::PRODUCTS_VARIATIONS)) {
$qb->andWhere('slp.id_variation IS NULL OR slp.id_variation = pv.id');
$qb->addSelect('slp.id_variation');
$qb->addSelect(\Query\Product::getInStoreField(false, $qb).' AS in_store_product');
$qb->groupBy('p.id, slp.id_variation');
}
$qb->addSelect('slp.id as id_slp, slp.pieces as slp_pieces');
if ($in_store_show_max = findModule(\Modules::PRODUCTS, \Modules::SUB_SHOW_MAX)) {
$qb->addSelect("COALESCE(p.in_store_show_max, {$in_store_show_max}) AS in_store_show_max");
}
});
$productList->addResultModifiers(function (ProductCollection $products, $dataAll) use ($fromAdmin) {
if (!$fromAdmin && ($products->count() > 0)) {
$this->countItemsInCart($products);
}
foreach ($dataAll as $key => $data) {
$products[$key]['id_slp'] = $data['id_slp'];
$products[$key]['pieces'] = $data['slp_pieces'];
if (isset($data['in_store_show_max'])) {
$products[$key]['in_store_show_max'] = $data['in_store_show_max'];
}
if (($data['has_variations'] ?? false) && empty($data['id_variation'])) {
// kdyz produkt ma varianty, ale v nakupnim seznamu je bez vybrane varianty:
// inStore a deliveryTimeText jsou od varianty (matched_id_variation), protoze productList ma variationsAsResult=true,
// potrebujeme upravit inStore a deliveryTimeText, aby byly od produktu
$products[$key]['inStore'] = $data['in_store_product'];
unset($products[$key]['in_store_suppliers']);
$products[$key]->prepareDeliveryText();
}
}
});
$cfg = Config::get();
$mainSize = 'product_cart';
if (empty($cfg['Photo']['types']['product_cart'])) {
$mainSize = 'product_catalog';
}
$productList->fetchImages($mainSize, fallbackToProductPhoto: true);
return $productList;
}
private function countItemsInCart(&$products)
{
$products->forAll(function ($key, &$product) {
$product['in_cart'] = 0;
return true;
});
if (is_null($this->cart->only_virtual_products)) {
// not yet initialized, but purchaseState could be set somehow...
$this->cart->invalidatePurchaseState();
}
foreach ($this->purchaseUtil->getPurchaseState()->getProducts() as $cartItems) {
$key = $cartItems->getIdProduct();
if (isset($products[$key])) {
$products[$key]['in_cart'] += $cartItems->getPieces();
}
if ($idVariation = $cartItems->getIdVariation()) {
$key .= '/'.$idVariation;
if (isset($products[$key])) {
$products[$key]['in_cart'] += $cartItems->getPieces();
}
}
}
}
public function removeProductFromList(int $id)
{
return sqlQueryBuilder()->delete('shopping_list_products')
->where(Operator::equals(['id' => $id]))
->execute();
}
public function getProductlistIdForProduct(int $idSlProduct)
{
return sqlQueryBuilder()->select('id_shopping_list')
->from('shopping_list_products')
->where(Operator::equals(['id' => $idSlProduct]))->execute()->fetchOne();
}
public function getShoppingListLabel(int $id)
{
return sqlQueryBuilder()->select('label')
->from('shopping_list')
->where(Operator::equals(['id' => $id]))->execute()->fetchOne();
}
public function deleteShoppingList(int $id)
{
return sqlQueryBuilder()->delete('shopping_list')
->where(Operator::equals(['id' => $id]))
->execute();
}
public function isUserOwner(int $idList): bool
{
if ($userId = $this->userContext->getActiveId()) {
if (sqlQueryBuilder()->select('count(id)')
->from('shopping_list')->where(
Operator::equals(['id_user' => $userId, 'id' => $idList])
)->execute()->fetchOne()) {
return true;
}
}
return false;
}
public function addProductToShoppingList(int $listId, int $productId, ?int $variationId = null, float $pieces = 1): bool
{
if ($existId = sqlQueryBuilder()->select('id')
->from('shopping_list_products')
->where(
Operator::equalsNullable(
['id_shopping_list' => $listId, 'id_product' => $productId, 'id_variation' => $variationId]
)
)
->execute()->fetchOne()) {
return (bool) sqlQueryBuilder()->update('shopping_list_products')
->set('pieces', 'pieces+'.$pieces)
->where(Operator::equals(['id' => $existId]))->execute();
}
return (bool) sqlQueryBuilder()->insert('shopping_list_products')
->directValues([
'id_shopping_list' => $listId,
'id_product' => $productId,
'id_variation' => $variationId,
'pieces' => $pieces,
]
)->execute();
}
public function addItemsToCart(array $products)
{
foreach ($products as $id => $pieces) {
$product = $this->getShoppingListItem(intval($id));
if ($product) {
$item = ['id_product' => $product['id_product'], 'id_variation' => $product['id_variation'], 'pieces' => $pieces];
$this->addItemToCart($item);
}
}
}
public function updateShoppingList(array $products)
{
foreach ($products as $id => $pieces) {
sqlQueryBuilder()->update('shopping_list_products')
->set('pieces', $pieces)
->where(Operator::equals(['id' => $id]))->execute();
}
}
private function getShoppingListItem(int $id)
{
return sqlQueryBuilder()->select('id_product, id_variation')
->from('shopping_list_products')
->where(Operator::equals(['id' => $id]))
->execute()->fetch();
}
public function addToShoppingList(int $listId, array $products): void
{
foreach ($products as $product) {
$this->addProductToShoppingList(
$listId,
intval($product['productId']),
!empty($product['variationId']) ? intval($product['variationId']) : null,
floatval($product['pieces'] ?? 1)
);
}
}
public function addItemsFromCart($idList): void
{
foreach ($this->purchaseUtil->getPurchaseState()->getProducts() as $product) {
if ($product->getIdProduct()) {
$this->addProductToShoppingList((int) $idList, $product->getIdProduct(), $product->getIdVariation(), (float) $product->getPieces());
}
}
}
public function getHash($id)
{
return urlencode(
sha1(
getShopUniqueName()
.join('', [
$id,
date('Y-m-d'),
])
)
);
}
public function addItemToCart($item): void
{
$id = $this->cart->addItem($item);
if ($id <= 0) {
addUserMessage(translate('error', 'order')['invalid_variation'], 'error');
return;
}
if (findModule(\Modules::JS_SHOP)) {
$this->session->set(JsShopRefreshListener::SESSION_NAME, true);
}
}
public function getFavoritesShoppingList(): ?array
{
$id_user = $this->userContext->getActiveId();
if (!$id_user) {
return null;
}
$list = sqlQueryBuilder()->select('*')->from('shopping_list')
->andWhere(Operator::equals(['id_user' => $id_user, 'label' => 'favorites']))
->execute()->fetchAssociative();
return $list ?: null;
}
public function createFavoritesShoppingList(): int
{
return $this->createShoppingList(translate('title', 'category')['favorites'] ?? 'Favorites', 'favorites');
}
public function shareShoppingList(int $listId, string $emailTo, string $from): void
{
$this->shareShoppingListEmail->setListId($listId);
$this->shareShoppingListEmail->setFrom($from);
$email = $this->shareShoppingListEmail->getEmail();
$email['to'] = $emailTo;
$this->shareShoppingListEmail->sendEmail($email);
}
}