<?php
/**
* (c) itmedia.by <info@itmedia.by>
*/
namespace Submarine\OrdersBundle\Entity;
use Submarine\OrdersBundle\Entity\OrderB24Data;
use Postroyka\AppBundle\Entity\Promocode;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Submarine\CartBundle\Cart\CartInterface;
use Submarine\CartBundle\Cart\OptionInterface;
use Submarine\CartBundle\Entity\Option;
use Submarine\CartBundle\Exception\CartEmptyException;
use Submarine\CartBundle\Exception\CartExpiredException;
use Submarine\CoreBundle\Entity\SubmarineEntityInterface;
use Submarine\OrdersBundle\Order\OrderDeliveryInterface;
use Submarine\OrdersBundle\Order\OrderInterface;
use Submarine\OrdersBundle\Order\OrderItemInterface;
use Submarine\OrdersBundle\Order\OrderPaymentInterface;
use Submarine\PagesBundle\Entity\Page;
use Submarine\UsersBundle\Entity\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity(repositoryClass="Submarine\OrdersBundle\Repository\OrderRepository")
*
* @ORM\Table(name="submarine_orders", indexes={
* @ORM\Index(name="created_at", columns={"created_at"})
* })
*
* @ORM\HasLifecycleCallbacks()
*/
class Order implements SubmarineEntityInterface, OrderInterface, OrderDeliveryInterface, OrderPaymentInterface
{
const NAME_PHONE_OPTION = "phone";
const NAME_EMAIL_OPTION = "email";
/**
* @var int
*
* @ORM\Id()
* @ORM\Column(name="id", type="integer", nullable=false, unique=true)
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var UuidInterface|null
*
* @ORM\Column(name="uuid", type="uuid", nullable=true)
*/
private $uuid;
/**
* @var Status
*
* @ORM\ManyToOne(targetEntity="Submarine\OrdersBundle\Entity\Status")
* @ORM\JoinColumn(name="status_is", referencedColumnName="id")
*/
private $status;
// ------------------ Order Info -------------------
/**
* @var OrderItem[]|ArrayCollection
*
* @ORM\OneToMany(targetEntity="Submarine\OrdersBundle\Entity\OrderItem", mappedBy="order", cascade={"ALL"})
*/
private $items;
/**
* @var UserInterface|null
*
* @ORM\ManyToOne(targetEntity="Submarine\UsersBundle\Entity\User", inversedBy="orders")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* Общая стоимость, с учетом скидок
* @var float
*
* @ORM\Column(name="total", type="decimal", precision=10, scale=2, nullable=true)
*/
private $total = 0;
/**
* Общая скидка
* @var float
*
* @ORM\Column(name="total_discount", type="decimal", precision=10, scale=2, nullable=true)
*/
private $totalDiscount = 0;
/**
* Дополнительные параметры, такие как адрес доставки, имя пользователя и т.д.
*
* @var ArrayCollection|OptionInterface[]
*
* @ORM\Column(name="options", type="array", nullable=false)
*/
private $options;
// ---------------- Order Shipping & payment -------------
/**
* Заказ оплачен?
*
* @var bool
*
* @ORM\Column(name="is_paid", type="boolean", nullable=true)
*/
private $paid = false;
/**
* Способ оплаты
*
* @ORM\Column(name="payment_method", type="string", nullable=true)
*/
private $paymentMethod;
/**
* Комиссия за оплату
*
* @var float
*
* @ORM\Column(name="payment_method_price", type="decimal", precision=10, scale=2, nullable=true)
*/
private $paymentMethodPrice = 0;
/**
* Способ доставки
*
* @ORM\Column(name="delivery_method", type="string", nullable=true)
*/
private $deliveryMethod;
/**
* Дополнительная стоимость за доставку
*
* @var float
*
* @ORM\Column(name="delivery_method_price", type="decimal", precision=10, scale=2, nullable=true)
*/
private $deliveryMethodPrice = 0;
// ---------------------- Descriptions -------------------
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* Заметки, недоступны клиенту
*
* @var string
*
* @ORM\Column(name="notes", type="text", nullable=true)
*/
private $notes;
/**
* @var \DateTime
*
* @ORM\Column(name="created_at", type="datetime", nullable=false)
*/
private $createdAt;
/**
* @var \DateTime
*
* @ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
private $updatedAt;
/**
* @ORM\OneToOne(targetEntity="Submarine\OrdersBundle\Entity\CardPayment", mappedBy="relatedOrder", cascade={"persist", "remove"})
*/
private $cardPayment;
/**
* IP пользователя
*
* @var string
*
* @ORM\Column(name="userIp", type="string", nullable=false)
*/
private $userIp;
/**
* @var Promocode|null
*
* @ORM\ManyToOne(targetEntity="Postroyka\AppBundle\Entity\Promocode", inversedBy="orders")
* @ORM\JoinColumn(name="promocode_id", referencedColumnName="id")
*/
private $promocode;
/**
* @var OrderB24Data
*
* @ORM\OneToOne(targetEntity="Submarine\OrdersBundle\Entity\OrderB24Data", mappedBy="order", cascade={"persist", "remove"})
*/
private $b24Data;
public function __construct()
{
$this->items = new ArrayCollection();
$this->options = new ArrayCollection();
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->userIp = self::getIpUser();
$this->uuid = Uuid::uuid4();
$this->b24Data = new OrderB24Data($this);
}
/**
* @return string
*/
public static function entityName()
{
return __CLASS__;
}
/**
* @ORM\PreUpdate()
*/
public function preUpdate()
{
$this->updatedAt = new \DateTime();
}
/**
* @param CartInterface $cart
*
* @throws CartEmptyException
* @throws CartExpiredException
*/
public function handleCart(CartInterface $cart)
{
if ($cart->isEmpty()) {
throw new CartEmptyException();
}
if ($cart->isExpired()) {
throw new CartExpiredException();
}
foreach ($cart->getInStockItems() as $cartItem) {
$orderItem = new OrderItem();
$orderItem->handleCartItem($cartItem);
$this->addItem($orderItem);
}
$this->total = $cart->getTotal();
$this->totalDiscount = $cart->getTotalDiscount();
$this->description = $cart->getDescription();
$promocode = $cart->getPromocode();
if($promocode){
$this->promocode = $promocode;
$promocode->addOrder($this);
}
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
public function getUuid()
{
return $this->uuid;
}
/**
* @return Status|null
*/
public function getStatus()
{
return $this->status;
}
/**
* @param Status $status
*/
public function setStatus(Status $status = null)
{
$this->status = $status;
}
/**
* @return ArrayCollection|OrderItem[]
*/
public function getItems()
{
return $this->items;
}
/**
* @param OrderItemInterface $item
*/
public function addItem(OrderItemInterface $item)
{
$item->setOrder($this);
$this->items->add($item);
}
/**
* @return null|UserInterface
*/
public function getUser()
{
return $this->user;
}
/**
* @param null|UserInterface|User $user
*/
public function setUser(UserInterface $user = null)
{
$this->user = $user;
}
/**
* Общая стоимость заказа
* @return float
*/
public function getTotal()
{
return $this->total;
}
/**
* @param float $total
*/
public function setTotal(float|int $total): void
{
$this->total = $total;
}
/**
* Итого к оплате
* @return float
*/
public function getPayPrice()
{
return $this->getTotal() + $this->getDeliveryMethodPrice() + $this->getPaymentMethodPrice();
}
/**
* @return float
*/
public function getTotalDiscount()
{
return $this->totalDiscount;
}
/**
* @param float $totalDiscount
*/
public function setTotalDiscount(float|int $totalDiscount): void
{
$this->totalDiscount = $totalDiscount;
}
/**
* @param OptionInterface $option
*/
public function addOption(OptionInterface $option)
{
$this->options->set($option->getName(), $option);
}
/**
* @return ArrayCollection|OptionInterface[]
*/
public function getOptions()
{
return $this->options;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return string
*/
public function getNotes()
{
return $this->notes;
}
/**
* @param string $notes
*/
public function setNotes($notes)
{
$this->notes = $notes;
}
/**
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param \DateTime $createdAt
*/
public function setCreatedAt(\DateTime $createdAt): void
{
$this->createdAt = $createdAt;
}
/**
* @param \DateTime $updatedAt
*/
public function setUpdatedAt(\DateTime $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
/**
* @return string
*/
public function getUserIp()
{
return $this->userIp;
}
/**
* @param string $userIp
*/
public function setUserIp($userIp): void
{
$this->userIp = $userIp;
}
// ---------------- Order Shipping & payment -------------
/**
* @return boolean
*/
public function isPaid()
{
return $this->paid;
}
/**
* @param boolean $paid
*/
public function setPaid($paid)
{
$this->paid = (bool)$paid;
}
/**
* @return string
*/
public function getPaymentMethod()
{
return $this->paymentMethod;
}
/**
* @param string $paymentMethod
*/
public function setPaymentMethod($paymentMethod)
{
$this->paymentMethod = $paymentMethod;
}
/**
* @return float
*/
public function getPaymentMethodPrice()
{
return $this->paymentMethodPrice;
}
/**
* @param float $paymentMethodPrice
*/
public function setPaymentMethodPrice($paymentMethodPrice)
{
$this->paymentMethodPrice = $paymentMethodPrice;
}
// ----------------- Delivery ---------------
/**
* {@inheritdoc}
*/
public function getDeliveryMethod()
{
return $this->deliveryMethod;
}
/**
* {@inheritdoc}
*/
public function setDeliveryMethod($methodName)
{
$this->deliveryMethod = $methodName;
}
/**
* {@inheritdoc}
*/
public function getDeliveryMethodPrice()
{
return $this->deliveryMethodPrice;
}
/**
* {@inheritdoc}
*/
public function setDeliveryMethodPrice($price)
{
$this->deliveryMethodPrice = $price;
}
public function getCardPayment(): ?CardPayment
{
return $this->cardPayment;
}
public function setCardPayment(CardPayment $cardPayment)
{
$this->cardPayment = $cardPayment;
// set the owning side of the relation if necessary
if ($this !== $cardPayment->getRelatedOrder()) {
$cardPayment->setRelatedOrder($this);
}
return $this;
}
public function getOptionValue($name)
{
/** @var Option $option */
$option = $this->options->get($name);
return $option ? $option->getValue() : null;
}
public function getEcommerceOptionString()
{
$allOptions = [];
foreach ($this->options as $option){
if(!$option->getValue()){
continue;
}
$allOptions[] = $option->getName() . ": " . html_entity_decode($option->getValue());
}
return implode(" | ", $allOptions);
}
/**
* @return Promocode|null
*/
public function getPromocode(): ?Promocode
{
return $this->promocode;
}
/**
* @param Promocode|null $promocode
*/
public function setPromocode(?Promocode $promocode): void
{
$this->promocode = $promocode;
}
/**
* @return OrderB24Data
*/
public function getB24Data(): OrderB24Data
{
return $this->b24Data;
}
/**
* @param OrderB24Data $b24Data
*/
public function setB24Data(OrderB24Data $b24Data): void
{
$this->b24Data = $b24Data;
}
public function getCountAllItems()
{
$count = 0;
foreach ($this->items as $item){
$count += $item->getQuantity();
}
return $count;
}
static function getIpUser(): string
{
return $_SERVER['HTTP_CLIENT_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? "";
}
static function getNumEnding($number, $endingArray = ["товар", "товара", "товаров"])
{
$number = $number % 100;
if($number >= 11 && $number <= 19){
return $endingArray[2];
}
switch ($number % 10) {
case 1:
return $endingArray[0];
case 2: case 3: case 4:
return $endingArray[1];
default: return $endingArray[2];
}
}
public function isExistLongProduct()
{
foreach ($this->items as $item){
if($item->getLength() >= 4){
return true;
}
}
return false;
}
public function getInStockItems()
{
return $this->items;
}
public function searchOrderItemByProductId(int $productId, float $length, bool $isDefected) : OrderItem|false
{
$filteredItems = $this->items->filter(function (OrderItem $orderItem) use ($productId, $length, $isDefected){
return $productId === $orderItem->getEntityId() && $orderItem->getLength() === $length && $orderItem->isDefected() === $isDefected;
});
return $filteredItems->first();
}
}