vendor/roothirsch/shop-bundle/Entity/OrderPosition.php line 22

Open in your IDE?
  1. <?php
  2. namespace Roothirsch\ShopBundle\Entity;
  3. use App\Entity\Company;
  4. use Roothirsch\CoreBundle\Entity\Traits\TimetrackedTrait;
  5. use Roothirsch\ShopBundle\Repository\OrderPositionRepository;
  6. use Doctrine\Common\Collections\ArrayCollection;
  7. use Doctrine\Common\Collections\Collection;
  8. use Doctrine\ORM\Mapping as ORM;
  9. use ApiPlatform\Core\Annotation\ApiResource;
  10. use Roothirsch\PimBundle\Entity\Product;
  11. use Symfony\Component\Serializer\Annotation\Groups;
  12. /**
  13. * @ORM\Entity(repositoryClass=OrderPositionRepository::class)
  14. * @ORM\Table(name="shop_order_position")
  15. * @ApiResource(
  16. * shortName="Shop/OrderPosition"
  17. * )
  18. */
  19. class OrderPosition
  20. {
  21. use TimetrackedTrait;
  22. /**
  23. * @ORM\Id
  24. * @ORM\GeneratedValue
  25. * @ORM\Column(type="integer")
  26. * @Groups({"list"})
  27. */
  28. private $id;
  29. /**
  30. * @ORM\Column(type="string", length=255)
  31. * @Groups({"list"})
  32. */
  33. private $state = 'draft';
  34. /**
  35. * @ORM\ManyToOne(targetEntity=Product::class)
  36. * @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
  37. * @Groups({"list"})
  38. */
  39. private $type;
  40. /**
  41. * @ORM\Column(type="string", length=255, nullable=true)
  42. * @Groups({"list"})
  43. */
  44. private $title;
  45. /**
  46. * @ORM\Column(type="string", length=255, nullable=true)
  47. * @Groups({"list"})
  48. */
  49. private $label;
  50. /**
  51. * @ORM\Column(type="float", nullable=true)
  52. * @Groups({"list"})
  53. */
  54. private $unitPrice;
  55. /**
  56. * @ORM\Column(type="integer")
  57. * @Groups({"list"})
  58. */
  59. private $amount = 1;
  60. /**
  61. * @ORM\OneToMany(targetEntity=OrderPositionAttribute::class, mappedBy="position", orphanRemoval=true, cascade={"persist", "remove"})
  62. * @ORM\OrderBy({"name" = "ASC"})
  63. */
  64. private $attributes;
  65. /**
  66. * @ORM\ManyToOne(targetEntity=Order::class, inversedBy="positions")
  67. * @ORM\JoinColumn(nullable=false)
  68. */
  69. private $order;
  70. /**
  71. * @ORM\Column(type="json")
  72. * @Groups({"list"})
  73. */
  74. private $articles = [];
  75. /**
  76. * @ORM\Column(type="json")
  77. * @Groups({"list"})
  78. */
  79. private $priceAdjustments = [];
  80. /**
  81. * @ORM\Column(type="json")
  82. * @Groups({"list"})
  83. */
  84. private $surcharges = [];
  85. /**
  86. * @ORM\Column(type="json")
  87. */
  88. private $additionalDiscounts = [];
  89. private $articleAttributes = null;
  90. public function __construct()
  91. {
  92. $this->attributes = new ArrayCollection();
  93. }
  94. public function __clone() {
  95. $this->id = null;
  96. $this->setCreatedAt(new \DateTime());
  97. $this->setUpdatedAt(new \DateTime());
  98. $oldAttributes = $this->attributes;
  99. $this->attributes = new ArrayCollection();
  100. foreach($oldAttributes as $oldAttribute) {
  101. $newAttribute = clone $oldAttribute;
  102. $this->attributes->add($newAttribute);
  103. $newAttribute->setPosition($this);
  104. }
  105. if ($this->articles === null) {
  106. $this->articles = [];
  107. }
  108. }
  109. public function getId(): ?int
  110. {
  111. return $this->id;
  112. }
  113. public function getTitle(): ?string
  114. {
  115. return $this->title;
  116. }
  117. public function setTitle(string $title): self
  118. {
  119. $this->title = $title;
  120. return $this;
  121. }
  122. public function getUnitPrice(): ?float
  123. {
  124. return floatval($this->unitPrice);
  125. }
  126. public function setUnitPrice(float $unitPrice): self
  127. {
  128. $this->unitPrice = $unitPrice;
  129. return $this;
  130. }
  131. public function getAmount(): ?int
  132. {
  133. return $this->amount;
  134. }
  135. public function setAmount(int $amount): self
  136. {
  137. $this->amount = $amount;
  138. return $this;
  139. }
  140. /**
  141. * @return Collection|OrderPositionAttribute[]
  142. */
  143. public function getAttributes(): Collection
  144. {
  145. return $this->attributes;
  146. }
  147. /**
  148. * @param ArrayCollection $attributes
  149. */
  150. public function setAttributes($attributes): void
  151. {
  152. foreach ($this->attributes as $attribute) {
  153. if (!isset($attributes[$attribute->getName()])) {
  154. $this->attributes->removeElement($attribute);
  155. }
  156. }
  157. /** @var OrderPositionAttribute $attribute */
  158. foreach ($attributes as $attributeName => $attribute) {
  159. $existingAttribute = $this->getAttribute($attributeName);
  160. if ($existingAttribute instanceof OrderPositionAttribute) {
  161. $existingAttribute->setValue($attribute->getValue());
  162. $existingAttribute->setTitle($attribute->getTitle());
  163. $existingAttribute->setName($attribute->getName());
  164. $existingAttribute->setAmount($attribute->getAmount());
  165. $existingAttribute->setAmountFormat($attribute->getAmountFormat());
  166. $existingAttribute->setArticle($attribute->getArticle());
  167. } else {
  168. $attribute->setPosition($this);
  169. $this->attributes->add($attribute);
  170. }
  171. }
  172. }
  173. public function getAttribute($name)
  174. {
  175. foreach ($this->attributes as $attribute) {
  176. if ($attribute->getName() == $name) {
  177. return $attribute;
  178. }
  179. }
  180. }
  181. public function __get($name) {
  182. if ($this->hasAttribute($name)) {
  183. return $this->getAttribute($name)->getValue();
  184. }
  185. }
  186. public function hasAttribute($name)
  187. {
  188. return $this->getAttribute($name) !== null;
  189. }
  190. public function __has($name) {
  191. return $this->hasAttribute($name);
  192. }
  193. public function getOrder(): ?Order
  194. {
  195. return $this->order;
  196. }
  197. public function setOrder(?Order $order): self
  198. {
  199. $this->order = $order;
  200. return $this;
  201. }
  202. /**
  203. * Get the value of type
  204. */
  205. public function getType()
  206. {
  207. return $this->type;
  208. }
  209. /**
  210. * Set the value of type
  211. *
  212. * @return self
  213. */
  214. public function setType($type)
  215. {
  216. $this->type = $type;
  217. return $this;
  218. }
  219. /**
  220. * @return string
  221. */
  222. public function getState(): string
  223. {
  224. return $this->state;
  225. }
  226. /**
  227. * @param string $state
  228. */
  229. public function setState(string $state): void
  230. {
  231. $this->state = $state;
  232. }
  233. /**
  234. * @return array
  235. */
  236. public function getArticles(): array
  237. {
  238. return (array) $this->articles;
  239. }
  240. /**
  241. * @return array
  242. */
  243. public function getArticleNames(): array
  244. {
  245. $names = [];
  246. if (is_iterable($this->articles)) {
  247. foreach ($this->articles as $article) {
  248. $names[] = $article['name'];
  249. }
  250. }
  251. return $names;
  252. }
  253. /**
  254. * @param array $articles
  255. */
  256. public function setArticles(array $articles): void
  257. {
  258. $this->articles = $articles;
  259. }
  260. public function getTotal()
  261. {
  262. $total = 0;
  263. foreach($this->getArticles() as $article) {
  264. $total+= $article['total'];
  265. }
  266. return intval($this->amount * $total);
  267. }
  268. public function getTotalAfterPriceAdjustments() {
  269. $total = $this->getTotal();
  270. foreach($this->getPriceAdjustments() as $priceAdjustment) {
  271. $total += $priceAdjustment['total'] * $this->getAmount();
  272. }
  273. return $total;
  274. }
  275. public function getTotalAfterDiscounts() {
  276. $total = $this->getTotalAfterPriceAdjustments();
  277. foreach($this->getDiscounts() as $discount) {
  278. $total += $discount['total'];
  279. }
  280. return $total;
  281. }
  282. public function getTotalWithTax() {
  283. if ($this->getOrder()->isApplyMwst() == false) {
  284. return $this->getTotalAfterDiscounts();
  285. }
  286. return intval($this->getTotalAfterDiscounts() / 100 * (108.1));
  287. }
  288. public function getTax() {
  289. return $this->getOrder()->getTax();
  290. }
  291. public function getArticlesSortedBySection()
  292. {
  293. $groups = [];
  294. $articles = $this->getArticles();
  295. usort($articles, function($l, $r){
  296. $key = 'sorting';
  297. $leftPriority = (array_key_exists($key, $l) ? $l[$key] : 0);
  298. $rightPriority = (array_key_exists($key, $r) ? $r[$key] : 0);
  299. return ($leftPriority < $rightPriority) ? 1 : -1;
  300. });
  301. foreach ($articles as $index => $article)
  302. {
  303. $hasGroupName = array_key_exists('group', $article);
  304. $groupName = $hasGroupName ? $article['group'] : '__none__';
  305. if(!array_key_exists($groupName, $groups)){
  306. $groups[$groupName] = [
  307. "label" => $hasGroupName ? $article['group'] : '',
  308. "subtotal" => 0,
  309. "total" => 0,
  310. "articles" => []
  311. ];
  312. }
  313. $groups[$groupName]['subtotal'] += $article['total'];
  314. $groups[$groupName]['total'] = $groups[$groupName]['subtotal'];
  315. $groups[$groupName]['priceAdjustments'] = [];
  316. foreach($this->getPriceAdjustments() as $priceAdjustment) {
  317. if ($groupName == $priceAdjustment['group']) {
  318. $groups[$groupName]['priceAdjustments'][] = $priceAdjustment;
  319. }
  320. }
  321. array_push($groups[$groupName]['articles'], $article);
  322. }
  323. return array_values($groups);
  324. }
  325. public function getArticleAttributes(){
  326. if($this->articleAttributes) {
  327. return $this->articleAttributes;
  328. }
  329. $attributes = [];
  330. foreach ($this->getArticles() as $article) {
  331. if(!array_key_exists("attributes", $article)){
  332. continue;
  333. }
  334. $articleAttributes = $article['attributes'];
  335. foreach ($articleAttributes as $attribute => $value){
  336. if(!$value){
  337. continue;
  338. }
  339. if(!array_key_exists($article['type'], $attributes)) {
  340. $attributes[$article['type']] = [];
  341. }
  342. $attributes[$article['type']][$attribute] = $value;
  343. }
  344. }
  345. $this->articleAttributes = $attributes;
  346. return $this->articleAttributes;
  347. }
  348. /**
  349. * @return array
  350. */
  351. public function getPriceAdjustments(): array
  352. {
  353. if (is_array($this->priceAdjustments)) {
  354. $articleGroups = $this->getArticlesGrouped();
  355. foreach($this->priceAdjustments as $index => $priceAdjustment) {
  356. $total = 0;
  357. if ($this->priceAdjustments[$index]['group'] == 'Panneau de porte') {
  358. $this->priceAdjustments[$index]['group'] = 'Türblatt';
  359. }
  360. if (isset($articleGroups[$priceAdjustment['group']])) {
  361. foreach ($articleGroups[$priceAdjustment['group']] as $article) {
  362. $total += $article['total'];
  363. }
  364. }
  365. switch($priceAdjustment['type']) {
  366. case 'percentage':
  367. $this->priceAdjustments[$index]['total'] = intval($total / 100 * $priceAdjustment['value']);
  368. default:
  369. break;
  370. }
  371. }
  372. }
  373. return is_array($this->priceAdjustments) ? $this->priceAdjustments : [];
  374. }
  375. /**
  376. * @return array
  377. */
  378. public function getDiscounts(): array
  379. {
  380. $discounts = [];
  381. $totalAfterDiscounts = $this->getTotalAfterPriceAdjustments();
  382. if($this->getOrder()->isApplyDiscount() && $this->getOrder()->getOwner()->getCompany() instanceof Company) {
  383. $companyDiscount = $this->getOrder()->getOwner()->getCompany()->getDiscount();
  384. $discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $companyDiscount);
  385. $totalAfterDiscounts+= $discountTotal;
  386. if ($companyDiscount > 0) {
  387. $discounts[] = [
  388. 'translationId' => 'discounts.companyDiscount',
  389. 'description' => 'BRUNEX-Rabattkonditionen',
  390. 'amount' => $companyDiscount . '%',
  391. 'total' => $discountTotal,
  392. 'highlight' => false
  393. ];
  394. }
  395. }
  396. if($this->getOrder()->customerDiscount > 0) {
  397. $customerDiscount = floatval($this->getOrder()->customerDiscount) * 100;
  398. $discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $customerDiscount);
  399. $totalAfterDiscounts+= $discountTotal;
  400. $discounts[] = [
  401. 'translationId' => 'discounts.customerDiscount',
  402. 'description' => 'Kundenrabatt',
  403. 'amount' => $customerDiscount . '%',
  404. 'total' => $discountTotal,
  405. 'highlight' => false
  406. ];
  407. }
  408. if (is_array($this->additionalDiscounts)) {
  409. foreach($this->additionalDiscounts as $additionalDiscount) {
  410. $discountTotal = intval($this->getTotalAfterPriceAdjustments() / 100 * $additionalDiscount['value']);
  411. $totalAfterDiscounts+= $discountTotal;
  412. $discounts[] = [
  413. 'translationId' => $additionalDiscount['label'],
  414. 'description' => $additionalDiscount['label'],
  415. 'amount' => $additionalDiscount['value'] . '%',
  416. 'total' => $discountTotal,
  417. 'highlight' => isset($additionalDiscount['highlight']) ? $additionalDiscount['highlight'] : false
  418. ];
  419. }
  420. }
  421. $surcharges = array_filter($this->getSurcharges(), function ($surcharge) { return !in_array($surcharge['label'], ['Frühlingsrabatt', 'Rabais de printemps', 'Herbstrabatt', 'Jubiläumsaktion', 'action de jubilé']); });
  422. foreach($surcharges as $surcharge) {
  423. $discounts[] = [
  424. 'translationId' => $surcharge['label'],
  425. 'description' => $surcharge['label'],
  426. 'amount' => $surcharge['value'] . '%',
  427. 'total' => intval($totalAfterDiscounts / 100 * $surcharge['value']),
  428. 'highlight' => isset($surcharge['highlight']) ? $surcharge['highlight'] : false
  429. ];
  430. }
  431. return $discounts;
  432. }
  433. /**
  434. * @param array $priceAdjustments
  435. */
  436. public function setPriceAdjustments(array $priceAdjustments): void
  437. {
  438. $this->priceAdjustments = $priceAdjustments;
  439. }
  440. public function getArticlesGrouped() {
  441. $articleGroups = [];
  442. foreach($this->getArticles() as $article) {
  443. if (!isset($article['group']) || empty($article['group'])) {
  444. $article['group'] = 'Türblatt';
  445. }
  446. if (!isset($articleGroups[$article['group']])) {
  447. $articleGroups[$article['group']] = [];
  448. }
  449. $articleGroups[$article['group']][] = $article;
  450. }
  451. return $articleGroups;
  452. }
  453. /**
  454. * @return array
  455. */
  456. public function getSurcharges(): array
  457. {
  458. return is_array($this->surcharges) ? $this->surcharges : [];
  459. }
  460. /**
  461. * @param array $surcharges
  462. */
  463. public function setSurcharges(array $surcharges): void
  464. {
  465. $this->surcharges = $surcharges;
  466. }
  467. public function isApplyMwst() {
  468. return $this->getOrder()->isApplyMwst();
  469. }
  470. public function getOwner() {
  471. return $this->getOrder()->getOwner();
  472. }
  473. /**
  474. * @return mixed
  475. */
  476. public function getLabel()
  477. {
  478. return $this->label;
  479. }
  480. /**
  481. * @param mixed $label
  482. */
  483. public function setLabel($label): void
  484. {
  485. $this->label = $label;
  486. }
  487. public function addAttribute(OrderPositionAttribute $attribute): self
  488. {
  489. if (!$this->getAttributes()->contains($attribute)) {
  490. $this->getAttributes()->add($attribute);
  491. $attribute->setPosition($this);
  492. }
  493. return $this;
  494. }
  495. public function removeAttribute(OrderPositionAttribute $attribute): self
  496. {
  497. if ($this->getAttributes()->removeElement($attribute)) {
  498. // set the owning side to null (unless already changed)
  499. if ($attribute->getPosition() === $this) {
  500. $attribute->setPosition(null);
  501. }
  502. }
  503. return $this;
  504. }
  505. /**
  506. * @return array
  507. */
  508. public function getAdditionalDiscounts(): array
  509. {
  510. return $this->additionalDiscounts;
  511. }
  512. /**
  513. * @param array $additionalDiscounts
  514. */
  515. public function setAdditionalDiscounts(array $additionalDiscounts): void
  516. {
  517. $this->additionalDiscounts = $additionalDiscounts;
  518. }
  519. /**
  520. * @return bool
  521. */
  522. public function isPositionInvalid(): bool
  523. {
  524. /** @var OrderPositionAttribute | EstimatePositionAttribute $attribute */
  525. $attribute = $this->getAttribute('orderValidation');
  526. if(!$attribute) {
  527. return false;
  528. }
  529. $val = $attribute->getValue() ?? $attribute->getData();
  530. return false == $val;
  531. }
  532. }