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. if (isset($article['name'])) {
  249. $names[] = $article['name'];
  250. }
  251. }
  252. }
  253. return $names;
  254. }
  255. /**
  256. * @param array $articles
  257. */
  258. public function setArticles(array $articles): void
  259. {
  260. $this->articles = $articles;
  261. }
  262. public function getTotal()
  263. {
  264. $total = 0;
  265. foreach($this->getArticles() as $article) {
  266. $total+= $article['total'];
  267. }
  268. return intval($this->amount * $total);
  269. }
  270. public function getTotalAfterPriceAdjustments() {
  271. $total = $this->getTotal();
  272. foreach($this->getPriceAdjustments() as $priceAdjustment) {
  273. $total += $priceAdjustment['total'] * $this->getAmount();
  274. }
  275. return $total;
  276. }
  277. public function getTotalAfterDiscounts() {
  278. $total = $this->getTotalAfterPriceAdjustments();
  279. foreach($this->getDiscounts() as $discount) {
  280. $total += $discount['total'];
  281. }
  282. return $total;
  283. }
  284. public function getTotalWithTax() {
  285. if ($this->getOrder()->isApplyMwst() == false) {
  286. return $this->getTotalAfterDiscounts();
  287. }
  288. return intval($this->getTotalAfterDiscounts() / 100 * (108.1));
  289. }
  290. public function getTax() {
  291. return $this->getOrder()->getTax();
  292. }
  293. public function getArticlesSortedBySection()
  294. {
  295. $groups = [];
  296. $articles = $this->getArticles();
  297. usort($articles, function($l, $r){
  298. $key = 'sorting';
  299. $leftPriority = (array_key_exists($key, $l) ? $l[$key] : 0);
  300. $rightPriority = (array_key_exists($key, $r) ? $r[$key] : 0);
  301. return ($leftPriority < $rightPriority) ? 1 : -1;
  302. });
  303. foreach ($articles as $index => $article)
  304. {
  305. $hasGroupName = array_key_exists('group', $article);
  306. $groupName = $hasGroupName ? $article['group'] : '__none__';
  307. if(!array_key_exists($groupName, $groups)){
  308. $groups[$groupName] = [
  309. "label" => $hasGroupName ? $article['group'] : '',
  310. "subtotal" => 0,
  311. "total" => 0,
  312. "articles" => []
  313. ];
  314. }
  315. $groups[$groupName]['subtotal'] += $article['total'];
  316. $groups[$groupName]['total'] = $groups[$groupName]['subtotal'];
  317. $groups[$groupName]['priceAdjustments'] = [];
  318. foreach($this->getPriceAdjustments() as $priceAdjustment) {
  319. if ($groupName == $priceAdjustment['group']) {
  320. $groups[$groupName]['priceAdjustments'][] = $priceAdjustment;
  321. }
  322. }
  323. array_push($groups[$groupName]['articles'], $article);
  324. }
  325. return array_values($groups);
  326. }
  327. public function getArticleAttributes(){
  328. if($this->articleAttributes) {
  329. return $this->articleAttributes;
  330. }
  331. $attributes = [];
  332. foreach ($this->getArticles() as $article) {
  333. if(!array_key_exists("attributes", $article)){
  334. continue;
  335. }
  336. $articleAttributes = $article['attributes'];
  337. foreach ($articleAttributes as $attribute => $value){
  338. if(!$value){
  339. continue;
  340. }
  341. if(!array_key_exists($article['type'], $attributes)) {
  342. $attributes[$article['type']] = [];
  343. }
  344. $attributes[$article['type']][$attribute] = $value;
  345. }
  346. }
  347. $this->articleAttributes = $attributes;
  348. return $this->articleAttributes;
  349. }
  350. /**
  351. * @return array
  352. */
  353. public function getPriceAdjustments(): array
  354. {
  355. if (is_array($this->priceAdjustments)) {
  356. $articleGroups = $this->getArticlesGrouped();
  357. foreach($this->priceAdjustments as $index => $priceAdjustment) {
  358. $total = 0;
  359. if ($this->priceAdjustments[$index]['group'] == 'Panneau de porte') {
  360. $this->priceAdjustments[$index]['group'] = 'Türblatt';
  361. }
  362. if (isset($articleGroups[$priceAdjustment['group']])) {
  363. foreach ($articleGroups[$priceAdjustment['group']] as $article) {
  364. $total += $article['total'];
  365. }
  366. }
  367. switch($priceAdjustment['type']) {
  368. case 'percentage':
  369. $this->priceAdjustments[$index]['total'] = intval($total / 100 * $priceAdjustment['value']);
  370. default:
  371. break;
  372. }
  373. }
  374. }
  375. return is_array($this->priceAdjustments) ? $this->priceAdjustments : [];
  376. }
  377. /**
  378. * @return array
  379. */
  380. public function getDiscounts(): array
  381. {
  382. $discounts = [];
  383. $totalAfterDiscounts = $this->getTotalAfterPriceAdjustments();
  384. if($this->getOrder()->isApplyDiscount() &&
  385. $this->getOrder()->getOwner() !== null &&
  386. $this->getOrder()->getOwner()->getCompany() instanceof Company) {
  387. $companyDiscount = $this->getOrder()->getOwner()->getCompany()->getDiscount();
  388. $discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $companyDiscount);
  389. $totalAfterDiscounts+= $discountTotal;
  390. if ($companyDiscount > 0) {
  391. $discounts[] = [
  392. 'translationId' => 'discounts.companyDiscount',
  393. 'description' => 'BRUNEX-Rabattkonditionen',
  394. 'amount' => $companyDiscount . '%',
  395. 'total' => $discountTotal,
  396. 'highlight' => false
  397. ];
  398. }
  399. }
  400. if($this->getOrder()->customerDiscount > 0) {
  401. $customerDiscount = floatval($this->getOrder()->customerDiscount) * 100;
  402. $discountTotal = - intval($this->getTotalAfterPriceAdjustments() / 100 * $customerDiscount);
  403. $totalAfterDiscounts+= $discountTotal;
  404. $discounts[] = [
  405. 'translationId' => 'discounts.customerDiscount',
  406. 'description' => 'Kundenrabatt',
  407. 'amount' => $customerDiscount . '%',
  408. 'total' => $discountTotal,
  409. 'highlight' => false
  410. ];
  411. }
  412. if (is_array($this->additionalDiscounts)) {
  413. foreach($this->additionalDiscounts as $additionalDiscount) {
  414. $discountTotal = intval($this->getTotalAfterPriceAdjustments() / 100 * $additionalDiscount['value']);
  415. $totalAfterDiscounts+= $discountTotal;
  416. $discounts[] = [
  417. 'translationId' => $additionalDiscount['label'],
  418. 'description' => $additionalDiscount['label'],
  419. 'amount' => $additionalDiscount['value'] . '%',
  420. 'total' => $discountTotal,
  421. 'highlight' => isset($additionalDiscount['highlight']) ? $additionalDiscount['highlight'] : false
  422. ];
  423. }
  424. }
  425. foreach($this->getSurcharges() as $surcharge) {
  426. $discounts[] = [
  427. 'translationId' => $surcharge['label'],
  428. 'description' => $surcharge['label'],
  429. 'amount' => $surcharge['value'] . '%',
  430. 'total' => intval($totalAfterDiscounts / 100 * $surcharge['value']),
  431. 'highlight' => isset($surcharge['highlight']) ? $surcharge['highlight'] : false
  432. ];
  433. }
  434. return $discounts;
  435. }
  436. /**
  437. * @param array $priceAdjustments
  438. */
  439. public function setPriceAdjustments(array $priceAdjustments): void
  440. {
  441. $this->priceAdjustments = $priceAdjustments;
  442. }
  443. public function getArticlesGrouped() {
  444. $articleGroups = [];
  445. foreach($this->getArticles() as $article) {
  446. if (!isset($article['group']) || empty($article['group'])) {
  447. $article['group'] = 'Türblatt';
  448. }
  449. if (!isset($articleGroups[$article['group']])) {
  450. $articleGroups[$article['group']] = [];
  451. }
  452. $articleGroups[$article['group']][] = $article;
  453. }
  454. return $articleGroups;
  455. }
  456. /**
  457. * @return array
  458. */
  459. public function getSurcharges(): array
  460. {
  461. $surcharges = is_array($this->surcharges) ? $this->surcharges : [];
  462. return \Roothirsch\ShopBundle\Service\DiscountFilterService::filterSurcharges($surcharges);
  463. }
  464. /**
  465. * @param array $surcharges
  466. */
  467. public function setSurcharges(array $surcharges): void
  468. {
  469. $this->surcharges = $surcharges;
  470. }
  471. public function isApplyMwst() {
  472. return $this->getOrder()->isApplyMwst();
  473. }
  474. public function getOwner() {
  475. return $this->getOrder()->getOwner();
  476. }
  477. /**
  478. * @return mixed
  479. */
  480. public function getLabel()
  481. {
  482. return $this->label;
  483. }
  484. /**
  485. * @param mixed $label
  486. */
  487. public function setLabel($label): void
  488. {
  489. $this->label = $label;
  490. }
  491. public function addAttribute(OrderPositionAttribute $attribute): self
  492. {
  493. if (!$this->getAttributes()->contains($attribute)) {
  494. $this->getAttributes()->add($attribute);
  495. $attribute->setPosition($this);
  496. }
  497. return $this;
  498. }
  499. public function removeAttribute(OrderPositionAttribute $attribute): self
  500. {
  501. if ($this->getAttributes()->removeElement($attribute)) {
  502. // set the owning side to null (unless already changed)
  503. if ($attribute->getPosition() === $this) {
  504. $attribute->setPosition(null);
  505. }
  506. }
  507. return $this;
  508. }
  509. /**
  510. * @return array
  511. */
  512. public function getAdditionalDiscounts(): array
  513. {
  514. return $this->additionalDiscounts;
  515. }
  516. /**
  517. * @param array $additionalDiscounts
  518. */
  519. public function setAdditionalDiscounts(array $additionalDiscounts): void
  520. {
  521. $this->additionalDiscounts = $additionalDiscounts;
  522. }
  523. /**
  524. * @return bool
  525. */
  526. public function isPositionInvalid(): bool
  527. {
  528. /** @var OrderPositionAttribute | EstimatePositionAttribute $attribute */
  529. $attribute = $this->getAttribute('orderValidation');
  530. if(!$attribute) {
  531. return false;
  532. }
  533. $val = $attribute->getValue() ?? $attribute->getData();
  534. return false == $val;
  535. }
  536. }