<?php
namespace App\Application\Cart;
use App\Admin\Document\Client;
use App\Admin\Document\Counterparty;
use App\Admin\Document\Product;
use App\Admin\Document\PromoCode;
use App\Admin\Document\PropertyValue;
use App\Admin\Document\UserAccount;
use AvenueAdminBundle\Authentication\Storage\Session;
use Doctrine\ODM\MongoDB\DocumentManager;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class Cart extends AbstractCart
{
/**
* @var SessionInterface
*/
private $session;
/**
* @var DocumentManager
*/
private $documentManager;
/**
* @var Session
*/
private $storage;
/**
* @param SessionInterface $session
* @param DocumentManager $documentManager
*/
public function __construct(SessionInterface $session, DocumentManager $documentManager, Session $storage)
{
$this->session = $session;
$this->documentManager = $documentManager;
$this->storage = $storage;
}
/**
* @return UserAccount
*/
private function getIdentity()
{
return $this->storage->read();
}
public function getCounterpartyId() {
return $this->getCounterparty() ? $this->getCounterparty()->getId() : null;
}
/**
* @var Counterparty
*/
private $counterparty;
/**
* @return Counterparty
*/
public function getCounterparty() {
if (!isset($this->counterparty)) {
$userAccount = $this->getIdentity();
if (!$userAccount) {
return null;
}
$id = $this->session->get('cart-counterparty', null);
if ($id) {
$this->counterparty = $this->documentManager->getRepository(Counterparty::class)->findOneBy([
'_id' => $id,
'client' => $userAccount->getClient()->getId()
]);
}
if (!$this->counterparty) {
$this->counterparty = false;
}
}
return $this->counterparty;
}
public function getCounterpartyName() {
$counterparty = $this->getCounterparty();
if ($counterparty) {
return $counterparty->getName();
}
return null;
}
public function getValidPrice(Product $product) {
$counterparty = $this->getCounterparty();
if ($counterparty) {
return $counterparty->getSellerProductPrice($product);
}
return $product->getPrice();
}
public function isValid() {
$counterparty = $this->getCounterparty();
if ($counterparty) {
foreach ($this->getItems() as $item) {
if (!$counterparty->getSellerProductPrice($item->product)) {
return false;
}
}
}
return true;
}
public function hasRetailCart(?UserAccount $userAccount ) {
$counterpartyId = $this->getCounterpartyId();
if ($counterpartyId) {
foreach ($userAccount->getCartItemsByCounterparty(null) as $productId => $a) {
if ($productId && is_array($a)) {
$product = $this->findProductById($productId);
if ($product) {
return true;
}
}
}
}
return false;
}
public function loadRetail(UserAccount $userAccount) {
$items = $userAccount->getCartItemsByCounterparty(null);
$this->setSessionItems($items);
}
public function setCounterparty(Counterparty $counterparty = null, array $sessionItems) {
$this->counterparty = $counterparty;
$this->session->set('cart-counterparty', $counterparty ? $counterparty->getId() : null);
$this->setSessionItems($sessionItems);
if ($counterparty && $counterparty->getUseDealerPromoCode()) {
$this->setPromoCode(PromoCode::getDealerPromoCode());
} elseif ($this->getPromoCode() && ($this->getPromoCode()->isDealer() || !$this->getShowPromoCode())) {
$this->clearPromoCode();
}
}
public function getSessionItems(): array {
return $this->session->get('cart-items', []);
}
private function setSessionItems($items) {
$this->session->set('cart-items', $items);
}
private function getCalcSessionItems(): array {
return $this->session->get('calc-items', []);
}
private function setCalcSessionItems($items) {
$this->session->set('calc-items', $items);
}
private function getDecorCalcSessionItems(): array {
return $this->session->get('decor-calc-items', []);
}
private function setDecorCalcSessionItems($items) {
$this->session->set('decor-calc-items', $items);
}
public function getGlueCount() {
return $this->session->get('glue-count', 0);
}
public function getDecorGlueCount() {
return $this->session->get('glue-count-decor', 0);
}
private function setGlueCount($value, $decor) {
return $this->session->set('glue-count' . ($decor ? '-decor' : ''), $value);
}
public function getCompareList(): array {
return $this->session->get('cart-compare-list', []);
}
private function setCompareList($list) {
$this->session->set('cart-compare-list', $list);
}
private function getCartItem($productId, $items) {
if (isset($items[$productId])) {
$cartItem = $items[$productId];
} else {
$cartItem = ['quantity' => 0];
}
return $cartItem;
}
public function add($productId, $quantity, $replace = false)
{
$items = $this->getSessionItems();
$cartItem = $this->getCartItem($productId, $items);
if ($replace) {
$cartItem['quantity'] = $quantity;
} else {
$cartItem['quantity'] += $quantity;
}
$items[$productId] = $cartItem;
$this->setSessionItems($items);
return $cartItem['quantity'];
}
public function setNotInStock($productId, $maxQuantity)
{
$items = $this->getSessionItems();
$cartItem = $this->getCartItem($productId, $items);
$cartItem['notInStock'] = true;
$cartItem['maxQuantity'] = $maxQuantity;
$items[$productId] = $cartItem;
$this->setSessionItems($items);
}
public function clearNotInStock($productId)
{
$items = $this->getSessionItems();
$cartItem = $this->getCartItem($productId, $items);
unset($cartItem['notInStock']);
unset($cartItem['maxQuantity']);
$items[$productId] = $cartItem;
$this->setSessionItems($items);
}
public function put($productId, $quantity)
{
return $this->add($productId, $quantity, true);
}
/**
* @param string $productId
*/
public function remove($productId)
{
$items = $this->getSessionItems();
if (isset($items[$productId])) {
unset($items[$productId]);
}
$this->setSessionItems($items);
}
public function has($productId) {
return $this->getQuantity($productId) > 0;
}
public function getQuantity($productId) {
$items = $this->getSessionItems();
if (isset($items[$productId])) {
return $items[$productId]['quantity'];
}
return 0;
}
/**
* @return CartItem[]
*/
public function getItems($sessionItems = null): array
{
if (!isset($sessionItems)) {
$sessionItems = $this->getSessionItems();
}
$result = [];
foreach ($sessionItems as $productId => $item) {
$product = $this->findProductById($productId);
if (!$product) {
continue;
}
$result[] = new CartItem($this, $product, $item);
}
return $result;
}
public function clear() {
$this->setSessionItems([]);
}
/**
* @param string $productId
* @return null|Product
*/
private function findProductById($productId)
{
return $this->documentManager->getRepository(Product::class)->findOneBy(['active' => true, '_id' => $productId]);
}
public function getDiscountAmount() {
$result = 0;
foreach ($this->getItems() as $item) {
$result += $item->getDiscountAmount();
}
return $result;
}
public function getAmountWithDiscount() {
return $this->getAmount() - $this->getDiscountAmount();
}
public function getVat() {
if ($this->getCounterparty()) {
return $this->getCounterparty()->getVat();
}
return Counterparty::getVatByType('cosca');
}
public static function calcVat($amount, $vat) {
return round($amount * $vat / (100 + $vat), 2);
}
public function getVatAmount() {
return self::calcVat($this->getAmountWithDiscount(), $this->getVat());
}
private $promoCode = false;
public function clearPromoCode(): void
{
$this->promoCode = false;
$this->session->set('cart-promo-map', null);
}
public function setPromoCode(PromoCode $promoCode)
{
if (!$this->getCounterparty() || $this->getCounterparty()->getShowPromoCode()
|| $this->getCounterparty()->getUseDealerPromoCode() && $promoCode->isDealer()
) {
$this->promoCode = $promoCode;
$a = $this->session->get('cart-promo-map', []);
$a[$this->getCounterpartyId()] = $this->promoCode->getCode();
$this->session->set('cart-promo-map', $a);
return true;
}
return false;
}
/**
* @param Counterparty $counterparty
* @return string|null
*/
private function getCartPromoCode($counterparty) {
$a = $this->session->get('cart-promo-map', []);
return $a[$counterparty ? $counterparty->getId() : ''] ?? null;
}
/**
* @return PromoCode
*/
public function getPromoCode()
{
if ($this->promoCode === false) {
$this->promoCode = $this->getCounterpartyPromoCode($this->getCounterparty());
}
return $this->promoCode;
}
/**
* @return PromoCode
*/
public function getCounterpartyPromoCode($counterparty)
{
$code = $this->getCartPromoCode($counterparty);
if ($code) {
if ($code == PromoCode::DEALER_CODE) {
return PromoCode::getDealerPromoCode();
}
return $this->documentManager->getRepository(PromoCode::class)->findOneBy(['code' => $code]);
}
return null;
}
public function getShowPromoCode() {
return !$this->getCounterparty() || $this->getCounterparty()->getShowPromoCode();
}
public function addInCompareList($id) {
$list = $this->getCompareList();
$list[] = $id;
$this->setCompareList($list);
}
public function clearCompareList($id) {
$this->setCompareList([]);
}
public function inCompareList($id) {
$list = $this->getCompareList();
return in_array($id, $list);
}
public function addToCalc($productId, $quantity = 1, $replace = false)
{
$items = $this->getCalcSessionItems();
$cartItem = $this->getCartItem($productId, $items);
if ($replace) {
$cartItem['quantity'] = $quantity;
} else {
$cartItem['quantity'] += $quantity;
}
$items[$productId] = $cartItem;
$this->setCalcSessionItems($items);
$this->updateGlueCount(false);
return $cartItem['quantity'];
}
public function clearCalc() {
$this->setCalcSessionItems([]);
$this->updateGlueCount(false);
}
public function addToDecorCalc($productId)
{
$items = $this->getDecorCalcSessionItems();
$cartItem = $this->getCartItem($productId, $items);
$cartItem['quantity'] = 1;
$items[$productId] = $cartItem;
$this->setDecorCalcSessionItems($items);
$this->updateGlueCount(true);
return $cartItem['quantity'];
}
public function clearDecorCalc() {
$this->setDecorCalcSessionItems([]);
$this->updateGlueCount(true);
}
public function removeFromCalc($productId)
{
$items = $this->getCalcSessionItems();
unset($items[$productId]);
$this->setCalcSessionItems($items);
$this->updateGlueCount(false);
}
public function removeFromDecorCalc($productId)
{
$items = $this->getDecorCalcSessionItems();
unset($items[$productId]);
$this->setDecorCalcSessionItems($items);
$this->updateGlueCount(true);
}
/**
* @return CartItem[]
*/
public function getCalcItems(): array
{
return $this->getItems($this->getCalcSessionItems());
}
/**
* @return CartItem[]
*/
public function getDecorCalcItems(): array
{
return $this->getItems($this->getDecorCalcSessionItems());
}
public function hasCalcItem($productId) {
$items = $this->getCalcSessionItems();
return isset($items[$productId]);
}
public function hasDecorCalcItem($productId) {
$items = $this->getDecorCalcSessionItems();
return isset($items[$productId]);
}
public function getCalcPerimeter() {
return $this->session->get('calc-perimeter', 0);
}
public function setCalcPerimeter($value) {
$this->session->set('calc-perimeter', $value);
$this->updateGlueCount(true);
}
public function getCalcOpeningWidth() {
return $this->session->get('calc-opening-width', 0);
}
public function setCalcOpeningWidth($value) {
$this->session->set('calc-opening-width', $value);
$this->updateGlueCount(true);
}
private function updateGlueCount($decor) {
$glueCount = 0;
if ($decor) {
$items = $this->getDecorCalcSessionItems();
}
foreach ($decor ? $this->getDecorCalcItems() : $this->getCalcItems() as $item) {
$len = $item->product->getLengthForGlue() ?: 1;
if ($decor) {
$s = $this->getCalcPerimeter();
if ($item->product->isPlinthCalculator()) {
$s -= $this->getCalcOpeningWidth();
}
$quantity = ceil($s / $len);
$sessionItem = $this->getCartItem($item->product->getId(), $items);
$sessionItem['quantity'] = $quantity;
$items[$item->product->getId()] = $sessionItem;
} else {
$quantity = $item->quantity;
}
$mountingSurface = $item->product->getMountingSurface() ?: 2;
$glueCount += ceil($mountingSurface * $quantity * $len / 27);
}
$this->setGlueCount($glueCount, $decor);
if ($decor) {
$this->setDecorCalcSessionItems($items);
}
}
}