<?php
namespace Roothirsch\ShopBundle\Entity;
use App\Entity\Company;
use Roothirsch\CoreBundle\Entity\Traits\TimetrackedTrait;
use Roothirsch\ShopBundle\Repository\OrderPositionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
use Roothirsch\PimBundle\Entity\Product;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity(repositoryClass=OrderPositionRepository::class)
* @ORM\Table(name="shop_order_position")
* @ApiResource(
* shortName="Shop/OrderPosition"
* )
*/
class OrderPosition
{
use TimetrackedTrait;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({"list"})
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Groups({"list"})
*/
private $state = 'draft';
/**
* @ORM\ManyToOne(targetEntity=Product::class)
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
* @Groups({"list"})
*/
private $type;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"list"})
*/
private $title;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Groups({"list"})
*/
private $label;
/**
* @ORM\Column(type="float", nullable=true)
* @Groups({"list"})
*/
private $unitPrice;
/**
* @ORM\Column(type="integer")
* @Groups({"list"})
*/
private $amount = 1;
/**
* @ORM\OneToMany(targetEntity=OrderPositionAttribute::class, mappedBy="position", orphanRemoval=true, cascade={"persist", "remove"})
* @ORM\OrderBy({"name" = "ASC"})
*/
private $attributes;
/**
* @ORM\ManyToOne(targetEntity=Order::class, inversedBy="positions")
* @ORM\JoinColumn(nullable=false)
*/
private $order;
/**
* @ORM\Column(type="json")
* @Groups({"list"})
*/
private $articles = [];
/**
* @ORM\Column(type="json")
* @Groups({"list"})
*/
private $priceAdjustments = [];
/**
* @ORM\Column(type="json")
* @Groups({"list"})
*/
private $surcharges = [];
/**
* @ORM\Column(type="json")
*/
private $additionalDiscounts = [];
private $articleAttributes = null;
public function __construct()
{
$this->attributes = new ArrayCollection();
}
public function __clone() {
$this->id = null;
$this->setCreatedAt(new \DateTime());
$this->setUpdatedAt(new \DateTime());
$oldAttributes = $this->attributes;
$this->attributes = new ArrayCollection();
foreach($oldAttributes as $oldAttribute) {
$newAttribute = clone $oldAttribute;
$this->attributes->add($newAttribute);
$newAttribute->setPosition($this);
}
if ($this->articles === null) {
$this->articles = [];
}
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getUnitPrice(): ?float
{
return floatval($this->unitPrice);
}
public function setUnitPrice(float $unitPrice): self
{
$this->unitPrice = $unitPrice;
return $this;
}
public function getAmount(): ?int
{
return $this->amount;
}
public function setAmount(int $amount): self
{
$this->amount = $amount;
return $this;
}
/**
* @return Collection|OrderPositionAttribute[]
*/
public function getAttributes(): Collection
{
return $this->attributes;
}
/**
* @param ArrayCollection $attributes
*/
public function setAttributes($attributes): void
{
foreach ($this->attributes as $attribute) {
if (!isset($attributes[$attribute->getName()])) {
$this->attributes->removeElement($attribute);
}
}
/** @var OrderPositionAttribute $attribute */
foreach ($attributes as $attributeName => $attribute) {
$existingAttribute = $this->getAttribute($attributeName);
if ($existingAttribute instanceof OrderPositionAttribute) {
$existingAttribute->setValue($attribute->getValue());
$existingAttribute->setTitle($attribute->getTitle());
$existingAttribute->setName($attribute->getName());
$existingAttribute->setAmount($attribute->getAmount());
$existingAttribute->setAmountFormat($attribute->getAmountFormat());
$existingAttribute->setArticle($attribute->getArticle());
} else {
$attribute->setPosition($this);
$this->attributes->add($attribute);
}
}
}
public function getAttribute($name)
{
foreach ($this->attributes as $attribute) {
if ($attribute->getName() == $name) {
return $attribute;
}
}
}
public function __get($name) {
if ($this->hasAttribute($name)) {
return $this->getAttribute($name)->getValue();
}
}
public function hasAttribute($name)
{
return $this->getAttribute($name) !== null;
}
public function __has($name) {
return $this->hasAttribute($name);
}
public function getOrder(): ?Order
{
return $this->order;
}
public function setOrder(?Order $order): self
{
$this->order = $order;
return $this;
}
/**
* Get the value of type
*/
public function getType()
{
return $this->type;
}
/**
* Set the value of type
*
* @return self
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return string
*/
public function getState(): string
{
return $this->state;
}
/**
* @param string $state
*/
public function setState(string $state): void
{
$this->state = $state;
}
/**
* @return array
*/
public function getArticles(): array
{
return (array) $this->articles;
}
/**
* @return array
*/
public function getArticleNames(): array
{
$names = [];
if (is_iterable($this->articles)) {
foreach ($this->articles as $article) {
$names[] = $article['name'];
}
}
return $names;
}
/**
* @param array $articles
*/
public function setArticles(array $articles): void
{
$this->articles = $articles;
}
public function getTotal()
{
$total = 0;
foreach($this->getArticles() as $article) {
$total+= $article['total'];
}
return intval($this->amount * $total);
}
public function getTotalAfterPriceAdjustments() {
$total = $this->getTotal();
foreach($this->getPriceAdjustments() as $priceAdjustment) {
$total += $priceAdjustment['total'] * $this->getAmount();
}
return $total;
}
public function getTotalAfterDiscounts() {
$total = $this->getTotalAfterPriceAdjustments();
foreach($this->getDiscounts() as $discount) {
$total += $discount['total'];
}
return $total;
}
public function getTotalWithTax() {
if ($this->getOrder()->isApplyMwst() == false) {
return $this->getTotalAfterDiscounts();
}
return intval($this->getTotalAfterDiscounts() / 100 * (108.1));
}
public function getTax() {
return $this->getOrder()->getTax();
}
public function getArticlesSortedBySection()
{
$groups = [];
$articles = $this->getArticles();
usort($articles, function($l, $r){
$key = 'sorting';
$leftPriority = (array_key_exists($key, $l) ? $l[$key] : 0);
$rightPriority = (array_key_exists($key, $r) ? $r[$key] : 0);
return ($leftPriority < $rightPriority) ? 1 : -1;
});
foreach ($articles as $index => $article)
{
$hasGroupName = array_key_exists('group', $article);
$groupName = $hasGroupName ? $article['group'] : '__none__';
if(!array_key_exists($groupName, $groups)){
$groups[$groupName] = [
"label" => $hasGroupName ? $article['group'] : '',
"subtotal" => 0,
"total" => 0,
"articles" => []
];
}
$groups[$groupName]['subtotal'] += $article['total'];
$groups[$groupName]['total'] = $groups[$groupName]['subtotal'];
$groups[$groupName]['priceAdjustments'] = [];
foreach($this->getPriceAdjustments() as $priceAdjustment) {
if ($groupName == $priceAdjustment['group']) {
$groups[$groupName]['priceAdjustments'][] = $priceAdjustment;
}
}
array_push($groups[$groupName]['articles'], $article);
}
return array_values($groups);
}
public function getArticleAttributes(){
if($this->articleAttributes) {
return $this->articleAttributes;
}
$attributes = [];
foreach ($this->getArticles() as $article) {
if(!array_key_exists("attributes", $article)){
continue;
}
$articleAttributes = $article['attributes'];
foreach ($articleAttributes as $attribute => $value){
if(!$value){
continue;
}
if(!array_key_exists($article['type'], $attributes)) {
$attributes[$article['type']] = [];
}
$attributes[$article['type']][$attribute] = $value;
}
}
$this->articleAttributes = $attributes;
return $this->articleAttributes;
}
/**
* @return array
*/
public function getPriceAdjustments(): array
{
if (is_array($this->priceAdjustments)) {
$articleGroups = $this->getArticlesGrouped();
foreach($this->priceAdjustments as $index => $priceAdjustment) {
$total = 0;
if ($this->priceAdjustments[$index]['group'] == 'Panneau de porte') {
$this->priceAdjustments[$index]['group'] = 'Türblatt';
}
if (isset($articleGroups[$priceAdjustment['group']])) {
foreach ($articleGroups[$priceAdjustment['group']] as $article) {
$total += $article['total'];
}
}
switch($priceAdjustment['type']) {
case 'percentage':
$this->priceAdjustments[$index]['total'] = intval($total / 100 * $priceAdjustment['value']);
default:
break;
}
}
}
return is_array($this->priceAdjustments) ? $this->priceAdjustments : [];
}
/**
* @return array
*/
public function getDiscounts(): array
{
$discounts = [];
$totalAfterDiscounts = $this->getTotalAfterPriceAdjustments();
if($this->getOrder()->isApplyDiscount() && $this->getOrder()->getOwner()->getCompany() instanceof Company) {
$companyDiscount = $this->getOrder()->getOwner()->getCompany()->getDiscount();
$discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $companyDiscount);
$totalAfterDiscounts+= $discountTotal;
if ($companyDiscount > 0) {
$discounts[] = [
'translationId' => 'discounts.companyDiscount',
'description' => 'BRUNEX-Rabattkonditionen',
'amount' => $companyDiscount . '%',
'total' => $discountTotal,
'highlight' => false
];
}
}
if($this->getOrder()->customerDiscount > 0) {
$customerDiscount = floatval($this->getOrder()->customerDiscount) * 100;
$discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $customerDiscount);
$totalAfterDiscounts+= $discountTotal;
$discounts[] = [
'translationId' => 'discounts.customerDiscount',
'description' => 'Kundenrabatt',
'amount' => $customerDiscount . '%',
'total' => $discountTotal,
'highlight' => false
];
}
if (is_array($this->additionalDiscounts)) {
foreach($this->additionalDiscounts as $additionalDiscount) {
$discountTotal = intval($this->getTotalAfterPriceAdjustments() / 100 * $additionalDiscount['value']);
$totalAfterDiscounts+= $discountTotal;
$discounts[] = [
'translationId' => $additionalDiscount['label'],
'description' => $additionalDiscount['label'],
'amount' => $additionalDiscount['value'] . '%',
'total' => $discountTotal,
'highlight' => isset($additionalDiscount['highlight']) ? $additionalDiscount['highlight'] : false
];
}
}
$surcharges = array_filter($this->getSurcharges(), function ($surcharge) { return !in_array($surcharge['label'], ['Frühlingsrabatt', 'Rabais de printemps', 'Herbstrabatt', 'Jubiläumsaktion', 'action de jubilé']); });
foreach($surcharges as $surcharge) {
$discounts[] = [
'translationId' => $surcharge['label'],
'description' => $surcharge['label'],
'amount' => $surcharge['value'] . '%',
'total' => intval($totalAfterDiscounts / 100 * $surcharge['value']),
'highlight' => isset($surcharge['highlight']) ? $surcharge['highlight'] : false
];
}
return $discounts;
}
/**
* @param array $priceAdjustments
*/
public function setPriceAdjustments(array $priceAdjustments): void
{
$this->priceAdjustments = $priceAdjustments;
}
public function getArticlesGrouped() {
$articleGroups = [];
foreach($this->getArticles() as $article) {
if (!isset($article['group']) || empty($article['group'])) {
$article['group'] = 'Türblatt';
}
if (!isset($articleGroups[$article['group']])) {
$articleGroups[$article['group']] = [];
}
$articleGroups[$article['group']][] = $article;
}
return $articleGroups;
}
/**
* @return array
*/
public function getSurcharges(): array
{
return is_array($this->surcharges) ? $this->surcharges : [];
}
/**
* @param array $surcharges
*/
public function setSurcharges(array $surcharges): void
{
$this->surcharges = $surcharges;
}
public function isApplyMwst() {
return $this->getOrder()->isApplyMwst();
}
public function getOwner() {
return $this->getOrder()->getOwner();
}
/**
* @return mixed
*/
public function getLabel()
{
return $this->label;
}
/**
* @param mixed $label
*/
public function setLabel($label): void
{
$this->label = $label;
}
public function addAttribute(OrderPositionAttribute $attribute): self
{
if (!$this->getAttributes()->contains($attribute)) {
$this->getAttributes()->add($attribute);
$attribute->setPosition($this);
}
return $this;
}
public function removeAttribute(OrderPositionAttribute $attribute): self
{
if ($this->getAttributes()->removeElement($attribute)) {
// set the owning side to null (unless already changed)
if ($attribute->getPosition() === $this) {
$attribute->setPosition(null);
}
}
return $this;
}
/**
* @return array
*/
public function getAdditionalDiscounts(): array
{
return $this->additionalDiscounts;
}
/**
* @param array $additionalDiscounts
*/
public function setAdditionalDiscounts(array $additionalDiscounts): void
{
$this->additionalDiscounts = $additionalDiscounts;
}
/**
* @return bool
*/
public function isPositionInvalid(): bool
{
/** @var OrderPositionAttribute | EstimatePositionAttribute $attribute */
$attribute = $this->getAttribute('orderValidation');
if(!$attribute) {
return false;
}
$val = $attribute->getValue() ?? $attribute->getData();
return false == $val;
}
}