vendor/roothirsch/shop-bundle/Entity/EstimatePosition.php line 21

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