<?php
namespace App\Service\Cart;
use App\Env;
use App\DTO\AppDTO;
use App\DTO\CartDTO;
use App\Entity\Prod;
use App\Model\ProdColor;
use App\Service\Auth\Auth;
use App\ValueObject\Money;
use App\Entity\CartUnsaved;
use App\Entity\Cart as EntityCart;
use App\Repository\CartRepository;
use App\Repository\ProdRepository;
use App\Service\Discount\NumDiscount;
use App\Service\Discount\SumDiscount;
use App\Service\Discount\UserDiscount;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\CartUnsavedRepository;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class Cart
{
protected EntityManagerInterface $em;
protected AppDTO $app;
protected Auth $Auth;
protected SessionInterface $Session;
protected ProdColor $prodColor;
protected RequestStack $rs;
protected $cart;
protected $prods_limited = [];
protected $order_id;
protected NumDiscount $NumDiscount;
protected SumDiscount $SumDiscount;
protected UserDiscount $UserDiscount;
//Repository
protected ProdRepository $Prods;
protected CartUnsavedRepository $CartUnsaved;
protected CartRepository $Carts;
public function __construct(EntityManagerInterface $em, AppDTO $app, Auth $Auth, NumDiscount $NumDiscount, SumDiscount $SumDiscount, UserDiscount $UserDiscount, ProdColor $prodColor, RequestStack $rs, Security $security)
{
$this->em = $em;
$this->app = $app;
$this->Auth = $Auth;
$this->Auth->setUser($security->getUser());
$this->prodColor = $prodColor;
$this->rs = $rs;
$this->Session = $rs->getSession();
$this->Prods = $this->em->getRepository(Prod::class);
$this->CartUnsaved = $this->em->getRepository(CartUnsaved::class);
$this->Carts = $this->em->getRepository(EntityCart::class);
$this->NumDiscount = $NumDiscount;
$this->SumDiscount = $SumDiscount;
$this->UserDiscount = $UserDiscount;
$this->cart = $this->Session->get('cart');
if (empty($this->cart)) {
$this->cart = [];
}
if (empty($this->cart)) {
$this->load_session();
}
$this->recount();
$this->flush();
}
public function getCart(): array
{
$deleted = 0;
foreach ($this->cart as $k => $v) {
$prod = $this->Prods->find($v['id']);
if ($prod == null) {
$deleted = 1;
unset ($this->cart[$k]);
}
}
if ($deleted) {
$this->save_session();
$this->flush();
}
return $this->cart;
}
public function isFreeDelivery(float $free_delivery_min): bool
{
$freedelivery = false;
if ($this->getAmount() >= $free_delivery_min && !$this->Auth->isOpt()) {
$freedelivery = true;
}
return $freedelivery;
}
public function getFromOrder(int $order_id): array
{
$Prods = $this->em->getRepository(Prod::class);
$cart = $this->loadFromOrder2($order_id);
// $cart = $this->getCart();
foreach ($cart as $k => $v) {
$cart[$k]['prod'] = $Prods->find($v['id']);
}
return $cart;
}
public function loadFromOrder(int $order_id)
{
$this->order_id = $order_id;
/** @var \App\Entity\Cart[] $prods */
$prods = $this->em->createQuery("SELECT c FROM App\Entity\Cart c WHERE c.order_id = ".$order_id)->getResult();
foreach($prods as $prod) {
$this->cart[$this->getCartId($prod->getProd()->getId(), 0)] = [
'cid' => $prod->getId(),
'id' => $prod->getProd()->getId(),
'var' => $prod->getVar(),
'num' => $prod->getNum(),
'baseprice' => (new Money($prod->getPrice()))->getAmount(),
'price' => 0,
'skidka' => $prod->getSkidka(),
'numdiscount' => $prod->getNumdiscount(),
'userdiscount' => $prod->getUserdiscount(),
];
}
$this->flush();
}
public function loadFromOrder2(int $order_id)
{
$cart = [];
$this->order_id = $order_id;
/** @var \App\Entity\Cart[] $prods */
$prods = $this->em->createQuery("SELECT c FROM App\Entity\Cart c WHERE c.order_id = ".$order_id)->getResult();
foreach($prods as $prod) {
if ($prod->getProd() == null) {
continue;
}
$cart[$this->getCartId($prod->getProd()->getId(), 0)] = [
'cid' => $prod->getId(),
'id' => $prod->getProd()->getId(),
'var' => $prod->getVar(),
'num' => $prod->getNum(),
'baseprice' => (new Money($prod->getPrice()))->getAmount(),
'price' => (new Money($prod->getPrice()))->getAmount(),
'skidka' => $prod->getSkidka(),
'numdiscount' => $prod->getNumdiscount(),
'userdiscount' => $prod->getUserdiscount(),
];
}
$cart = $this->recount($cart);
return $cart;
}
public function getCartId(int $prod_id, int $var = 0, array $chars = [], int $user_id = 0) {
$id = $prod_id."_".$var;
if (!empty($chars)) {
ksort($chars);
$id .= "_".json_encode($chars);
}
if ($user_id) {
$id .= "_".$user_id;
}
return md5($id);
}
public function addItem($id = 0, $var = 0, $num = 1, $price = 0, $skidka = 0, $numdiscount = [], $weight = 0){
$cart_id = $this->getCartId($id, $var);
if(isset($this->cart[$cart_id])){
$this->cart[$cart_id]['num'] += $num;
if($this->cart[$cart_id]['skidka'] == 0){
$this->cart[$cart_id]['numdiscount'] = $this->NumDiscount->getDiscount($num, $numdiscount);
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}else{
$this->cart[$cart_id]['numdiscount'] = 0;
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}
}else{
// array_unshift($this->cart, array($cart_id => array('id' => intval($id), 'var' => intval($var), 'num' => intval($num), 'baseprice' => floatval($price), 'price' => floatval($price), 'skidka' => floatval($skidka), 'weight' => floatval($weight))));
$this->cart[$cart_id] = array('id' => intval($id), 'var' => intval($var), 'num' => intval($num), 'baseprice' => floatval($price), 'price' => floatval($price), 'skidka' => floatval($skidka), 'weight' => floatval($weight));
if($this->cart[$cart_id]['skidka'] == 0){
$this->cart[$cart_id]['numdiscount'] = $this->NumDiscount->getDiscount($num, $numdiscount);
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}else{
$this->cart[$cart_id]['numdiscount'] = 0;
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}
}
$this->recount();
$this->save_session();
$this->flush();
}
public function updateItem($cart_id = '', $num = 0, $numdiscount = []){
if($num == 0){
$prod = $this->cart[$cart_id]['id'];
$prodvar = $this->cart[$cart_id]['var'];
unset($this->cart[$cart_id]);
}else{
$this->cart[$cart_id]['num'] = intval($num);
if($this->order_id == 0) {
if($this->cart[$cart_id]['skidka'] == 0){
$this->cart[$cart_id]['numdiscount'] = $this->NumDiscount->getDiscount($num, $numdiscount);
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}else{
$this->cart[$cart_id]['numdiscount'] = 0;
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}
} else {
if($this->cart[$cart_id]['skidka'] == 0){
$this->cart[$cart_id]['numdiscount'] = $this->NumDiscount->getDiscount($num, $numdiscount);
$this->cart[$cart_id]['userdiscount'] = $this->UserDiscount->getValue();
}else{
$this->cart[$cart_id]['numdiscount'] = 0;
$this->cart[$cart_id]['userdiscount'] = 0;
}
}
$this->recount();
$prod = intval($this->cart[$cart_id]['id']);
$prodvar = intval($this->cart[$cart_id]['var']);
}
$this->save_session();
$this->flush();
}
public function deleteItem(string $cart_id)
{
$prod = $this->cart[$cart_id]['id'];
$prodvar = $this->cart[$cart_id]['var'];
unset($this->cart[$cart_id]);
$this->recount();
$this->save_session();
$this->flush();
}
public function deleteAll()
{
$this->cart = [];
$this->delete_session();
$this->flush();
}
public function cart_id($prod = 0, $var = 0, $chars = array(), $user_id = 0)
{
$this->getCartId($prod, $var, $chars, $user_id);
}
public function getAmount(): float
{
$amount = 0;
foreach($this->cart as $k => $v)
$amount += round($v['price'], Env::price_precission()) * $v['num'];
return $amount;
}
public function getBaseAmount(): float
{
$amount = 0;
foreach($this->cart as $k => $v)
$amount += round($v['baseprice'], Env::price_precission()) * $v['num'];
return $amount;
}
public function getAmountWithoutDiscount()
{
$amount = 0;
foreach ($this->cart as $k => $v) {
$amount += round($v['baseprice'], Env::price_precission()) * $v['num'];
}
return $amount;
}
public function getAmountDelivery()
{
return (float)@$_SESSION['_sf2_attributes']['checkout']['delivery_cost'];
}
public function getAmountWithDelivery()
{
if (($this->getAmount() < $this->app->sett->get('free_delivery_amount')) || ($this->Auth->isOpt())) {
return $this->getAmount() + $this->getAmountDelivery();
} else {
return $this->getAmount();
}
}
public function userLogin($user_id)
{
$this->load_session($user_id);
$discount = $this->UserDiscount->getValue();
if ($discount >= 0) {
foreach ($this->cart as $k => $v) {
$prod = $this->Prods->find((int)$v['id']);
$numdiscount = $prod->getNumdiscount();
if($v['var'] == 2){
$numdiscount = $prod->getNumdiscount2();
}
if($v['var'] == 3){
$numdiscount = $prod->getNumdiscount3();
}
$this->cart[$k]['userdiscount'] = $discount;
if($this->Auth->isOpt()) {
$this->cart[$k]['numdiscount'] = $this->NumDiscount->getDiscount((int) $this->cart[$k]['num'], $numdiscount);
}
}
}
$this->recount();
$this->save_session();
$this->em->createQuery("DELETE App\Entity\CartUnsaved c WHERE c.user_id = '".$this->Auth->guestId()."'")->getResult();
$this->flush();
}
public function setUserDiscount($discount){
if($discount){
foreach($this->cart as $k => $v){
$this->cart[$k]['userdiscount'] = $discount;
}
}
$this->recount();
$this->save_session();
$this->flush();
}
protected function recount($cart = [])
{
if (!empty($cart)) {
foreach ($cart as $k => $v) {
if (!isset($v['userdiscount'])) $cart[$k]['userdiscount'] = 0;
if (!isset($v['numdiscount'])) $cart[$k]['numdiscount'] = 0;
if (!isset($v['skidka'])) $cart[$k]['skidka'] = 0;
$cart[$k]['baseprice'] = (new Money($v['baseprice']))->getAmount();
if ($v['skidka']) {
$cart[$k]['price'] = (new Money(($v['baseprice']) * (100 - $v['skidka']) / 100))->getAmount();
} else {
$cart[$k]['price'] = (new Money((($v['baseprice']) * (100 - $v['userdiscount']) * (100 - $v['numdiscount']) / 100 / 100)))->getAmount();
}
}
return $cart;
}
foreach ($this->cart as $k => $v) {
if (!isset($v['userdiscount'])) $this->cart[$k]['userdiscount'] = 0;
if (!isset($v['numdiscount'])) $this->cart[$k]['numdiscount'] = 0;
if (!isset($v['skidka'])) $this->cart[$k]['skidka'] = 0;
if ($this->order_id == 0) {
$prod = $this->Prods->find((int) $v['id']);
if ($prod) {
$skidka = $prod->getSkidka();
if ($v['var'] == 2) {
$skidka = $prod->getSkidka2();
}
if ($v['var'] == 3) {
$skidka = $prod->getSkidka3();
}
$this->cart[$k]['skidka'] = $skidka;
}
}
$this->cart[$k]['baseprice'] = (new Money($v['baseprice']))->getAmount();
if ($v['skidka']) {
$this->cart[$k]['price'] = (new Money(($v['baseprice']) * (100 - $v['skidka']) / 100))->getAmount();
} else {
$this->cart[$k]['price'] = (new Money((($v['baseprice']) * (100 - $v['userdiscount']) * (100 - $v['numdiscount']) / 100 / 100)))->getAmount();
}
}
}
public function getProdNum()
{
return (empty($this->cart)) ? 0 : count($this->cart);
}
public function getPackNum()
{
$num = 0;
foreach($this->cart as $k => $v)
$num += $v['num'];
return $num;
}
public function getWeight()
{
$weight = 0;
foreach($this->cart as $k => $v)
{
$n = $v['num'] ?? 0;
$w = $v['weight'] ?? 0;
$weight += $n * $w;
}
return round($weight / 1000, 2);
}
protected function load_session()
{
$uid = $this->Auth->getUserId() ? $this->Auth->getUserId(): $this->Auth->guestId();
$unsaved_cart = $this->CartUnsaved->findOneBy(["user_id" => $uid]);
if ($unsaved_cart) {
$cart = json_decode($unsaved_cart->getCart(), true);
foreach ($cart as $k => $v) {
$prod = $this->Prods->find((int) $v['id']);
$v['baseprice'] = $prod->getPrice();
if ($v['var'] == 2) {
$v['baseprice'] = $prod->getPrice2();
} elseif ($v['var'] == 3) {
$v['baseprice'] = $prod->getPrice3();
}
if (!isset($this->cart[$k])) {
$this->cart[$k] = $v;
}
}
}
$this->flush();
}
private function flush()
{
$this->Session->set('cart', $this->cart);
}
public function save_session()
{
$uid = $this->Auth->getUserId() ? $this->Auth->getUserId(): $this->Auth->guestId();
$cart = json_encode($this->cart, JSON_UNESCAPED_UNICODE);
$unsaved_cart = $this->CartUnsaved->findOneBy(["user_id" => $uid]);
if ($unsaved_cart) {
$unsaved_cart->setCart($cart);
} else {
$unsaved_cart = new CartUnsaved();
$unsaved_cart->setUserId($uid);
$unsaved_cart->setCart($cart);
$this->em->persist($unsaved_cart);
}
$this->em->flush();
}
public function delete_session()
{
$uid = $this->Auth->getUserId() ? $this->Auth->getUserId(): $this->Auth->guestId();
$unsaved_cart = $this->CartUnsaved->findOneBy(["user_id" => $uid]);
if ($unsaved_cart) {
$this->em->remove($unsaved_cart);
$this->em->flush();
}
}
public function saveCart(int $order_id) {
// if ($this->Auth->isAuth() || !$this->Auth->isOpt()) {
// $userdiscount = $this->UserDiscount->calculateUserDiscount(new Model_Discount, new Model_Order(), new Model_User(), Auth::userid());
// } else {
// $userdiscount = 0;
// }
foreach ($this->cart as $k => $v) {
$prod = $this->Prods->find((int) $v['id']);
$price = $prod->getPrice();
$num = $prod->getNum();
if ($v['skidka']) {
$v['numdiscount'] = 0;
}
$Cart = new EntityCart();
$Cart->setOrderId($order_id);
$Cart->setProd($prod);
$Cart->setVar((int) $v['var']);
$Cart->setNum((int) $v['num']);
$Cart->setPrice(round($price, Env::price_precission()));
$Cart->setSkidka((int) $v['skidka']);
$Cart->setNumdiscount((int) $v['numdiscount']);
$Cart->setUserdiscount((int) $v['userdiscount']);
//$Cart->setSumdiscount((int) $v['sumdiscount']);
$this->em->persist($Cart);
}
$this->em->flush();
$this->flush();
}
//Удалить товары с нулевыми остатками из цветов
public function deleteNullFromColors()
{
foreach ($this->cart as $k => $v) {
$prod = $this->Prods->find((int) $v['id']);
$prod_num = $prod->getNum();
if ($v['var'] == 2) $prod_num = $prod->getNum2();
if ($v['var'] == 3) $prod_num = $prod->getNum3();
if ($prod->getId() == $v['id'] && $prod_num > 0 && $prod_num < $v['num']) {
$this->prods_limited[] = $v['id'];
$this->cart[$k]['num'] = $prod_num;
}
if ($prod->getId() == $v['id'] && $prod_num <= 0) {
$this->prodColor->deleteColor($prod->getId());
}
}
$this->flush();
}
public function save_cart_admin($order_id) {
$this->em->createQuery("DELETE App\Entity\Cart c WHERE c.order = ".$order_id)->getResult();
foreach ($this->cart as $v) {
$prod = $this->Prods->find((int) $v['id']);
if ($v['skidka']) {
$v['numdiscount'] = 0;
}
$Cart = new EntityCart();
$Cart->setOrderId($order_id);
$Cart->setProd($prod);
$Cart->setVar((int) $v['var']);
$Cart->setNum((int) $v['num']);
$Cart->setPrice(round($v['baseprice'], Env::price_precission()));
$Cart->setSkidka((int) $v['skidka']);
$Cart->setNumdiscount((int) $v['numdiscount']);
$Cart->setUserdiscount((int) $v['userdiscount']);
$Cart->setSumdiscount((int) $v['sumdiscount']);
$this->em->persist($Cart);
}
$this->em->flush();
$this->flush();
}
public function prods_limited() {
foreach ($this->cart as $k => $v) {
$prod = $this->Prods->find((int) $v['id']);
$prod_num = $prod->getNum();
if ($v['var'] == 2) $prod_num = $prod->getNum2();
if ($v['var'] == 3) $prod_num = $prod->getNum3();
if ($prod->getId() == $v['id'] && $prod_num > 0 && $prod_num < $v['num']) {
$this->prods_limited[] = $v['id'];
$this->cart[$k]['num'] = $prod_num;
}
if ($prod->getId() == $v['id'] && $prod_num <= 0) {
unset($this->cart[$k]);
}
}
$this->flush();
$this->save_session();
if (!empty($this->prods_limited)) return true;
else return false;
}
public function getProdsLimited (): array
{
return $this->prods_limited;
}
}