src/Service/DeliveryService.php line 319

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Entity\Delivery;
  4. use App\Entity\Variables\PriceComplementary;
  5. use App\Entity\Variables\PricePerKilometer;
  6. use App\Entity\Variables\Tax;
  7. use App\Entity\VehicleType;
  8. use App\Enum\MercureToEnum;
  9. use App\Enum\MercureTypeEnum;
  10. use App\Enum\PriceComplementaryEnum;
  11. use App\Enum\TaxEnum;
  12. use App\Repository\Variables\PriceComplementaryRepository;
  13. use App\Repository\Variables\PricePerKilometerRepository;
  14. use App\Repository\Variables\TaxRepository;
  15. use Doctrine\Persistence\ManagerRegistry;
  16. use Psr\Log\LoggerInterface;
  17. use Symfony\Component\HttpFoundation\RequestStack;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\Mercure\HubInterface;
  20. use Symfony\Component\Mercure\Update;
  21. class DeliveryService
  22. {
  23. public function __construct(
  24. private RequestStack $requestStack,
  25. private ManagerRegistry $doctrine,
  26. private HubInterface $hub,
  27. private LoggerInterface $logger
  28. ) {
  29. }
  30. /**
  31. * Get SousTotal HT.
  32. *
  33. * distance en mètre
  34. */
  35. public function getSousTotalHT(int $distance, float $fraisMeteo): float
  36. {
  37. /**
  38. * @var PricePerKilometerRepository $pricePerKilometerRepository
  39. */
  40. $pricePerKilometerRepository = $this->doctrine->getRepository(PricePerKilometer::class);
  41. /**
  42. * @var PricePerKilometer[] $prices
  43. */
  44. $prices = $pricePerKilometerRepository->getCurrents();
  45. $tarifMetrique = [];
  46. foreach ($prices as $price) {
  47. $tarifMetrique[$price->getUpperLanding()] = $price->getRateMetricTTC();
  48. }
  49. /**
  50. * @var PriceComplementaryRepository $priceComplementaryRepository
  51. */
  52. $priceComplementaryRepository = $this->doctrine->getRepository(PriceComplementary::class);
  53. $price = $priceComplementaryRepository->getCurrentPrice(PriceComplementaryEnum::MINIMUM->value);
  54. if (!$price || !($price instanceof PriceComplementary)) {
  55. throw new \Exception('Price not found');
  56. }
  57. $minimum = $price->getRateTTC();
  58. $sousTotal = $fraisMeteo;
  59. $remainingDistance = $distance;
  60. if ($distance <= 1000) {
  61. $tarifMetriqueHT = $tarifMetrique[1.00];
  62. $sousTotal = ($tarifMetriqueHT * $distance / 2) + $minimum;
  63. } else {
  64. do {
  65. $ceil = ceil($remainingDistance / 1000);
  66. $floor = floor($remainingDistance / 1000);
  67. $multiple = 1000;
  68. $rest = $remainingDistance - $floor * 1000;
  69. if ($rest) {
  70. $multiple = $rest;
  71. }
  72. $tarifMetriqueHT = $tarifMetrique[$ceil];
  73. $sousTotal = $sousTotal + ($tarifMetriqueHT * $multiple);
  74. $remainingDistance = $remainingDistance - $multiple;
  75. } while ($remainingDistance > 0);
  76. }
  77. return $sousTotal;
  78. }
  79. /**
  80. * Get options.
  81. *
  82. * @return array<string, mixed>
  83. */
  84. public function getOptions(Delivery $delivery, float $sousTotal): array
  85. {
  86. /**
  87. * @var PriceComplementaryRepository $priceComplementaryRepository
  88. */
  89. $priceComplementaryRepository = $this->doctrine->getRepository(PriceComplementary::class);
  90. /**
  91. * @var array<int, PriceComplementary> $prices
  92. */
  93. $prices = $priceComplementaryRepository->getCurrents();
  94. $options = [];
  95. foreach (PriceComplementaryEnum::cases() as $case) {
  96. foreach ($prices as $price) {
  97. if ($case->value == $price->getOptionRate()) {
  98. $options[$case->value] = $price->getRateTTC();
  99. }
  100. }
  101. }
  102. $articles = $delivery->getDeliveryArticles();
  103. $roundTrip = false;
  104. $brittle = $floor = $insurance = $adValorem = 0;
  105. foreach ($articles as $article) {
  106. if ($article->isRoundTrip()) {
  107. $roundTrip = $sousTotal / 2;
  108. }
  109. if ($article->isBrittle()) {
  110. $brittle += $options[PriceComplementaryEnum::BRITTLE->value];
  111. }
  112. if ($article->isInsurance()) {
  113. $insurance += $options[PriceComplementaryEnum::INSURANCE->value];
  114. }
  115. if ($article->isAdValorem()) {
  116. $adValorem += $sousTotal * $options[PriceComplementaryEnum::ADVALOREM->value] / 100;
  117. }
  118. }
  119. $sender = $delivery->getSender();
  120. if (!$sender) {
  121. throw new \Exception('Sender not found', Response::HTTP_NOT_FOUND);
  122. }
  123. $floorSender = $sender->getFloor();
  124. if ($floorSender && $floorSender > 0) {
  125. $floor += $options[PriceComplementaryEnum::FLOOR->value];
  126. }
  127. $recipient = $delivery->getRecipient();
  128. if (!$recipient) {
  129. throw new \Exception('Recipient not found', Response::HTTP_NOT_FOUND);
  130. }
  131. $floorRecipient = $recipient->getFloor();
  132. if ($floorRecipient && $floorRecipient > 0) {
  133. $floor += $options[PriceComplementaryEnum::FLOOR->value];
  134. }
  135. $additionalArticle = count($articles) > 1 ? $options[PriceComplementaryEnum::ADDITIONAL_ARTICLE->value] * count($articles) : 0;
  136. return [
  137. 'roundTrip' => $roundTrip,
  138. 'brittle' => $brittle,
  139. 'floor' => $floor,
  140. 'insurance' => $insurance,
  141. 'adValorem' => $adValorem,
  142. 'additionalArticle' => $additionalArticle,
  143. 'total' => $roundTrip + $brittle + $floor + $insurance + $adValorem + $additionalArticle,
  144. ];
  145. }
  146. /**
  147. * Check if is electric.
  148. */
  149. public function isElectric(Delivery $delivery): bool
  150. {
  151. $vehicleType = $delivery->getVehicleType();
  152. $electrics = [VehicleType::ELECTRIC_BYCICLE, VehicleType::ELECTRIC_TWO_WHEELER];
  153. // if (in_array($vehicleType, $electrics)) {
  154. if ($vehicleType->getEnergy()->getName() == "électrique")
  155. return true;
  156. return false;
  157. }
  158. public function getFuelSurcharge(): float
  159. {
  160. /** TODO index - 2 */
  161. $index2 = 102;
  162. /** TODO index */
  163. $index = 100;
  164. /** TODO ponderation */
  165. $ponderation = 0.1;
  166. return ((($index2 - $index) / $index) * 100) * $ponderation;
  167. }
  168. public function setDeliverySessionData(bool $isPro, bool $send, ?int $deliveryId): void
  169. {
  170. if (!$deliveryId) {
  171. throw new \Exception('DeliveryId not found', Response::HTTP_NOT_FOUND);
  172. }
  173. $session = $this->requestStack->getSession();
  174. $session->set('isPro', $isPro);
  175. $session->set('send', $send);
  176. $session->set('deliveryId', $deliveryId);
  177. }
  178. /**
  179. * @return array<string, mixed>
  180. */
  181. public function getDeliverySessionData(): array
  182. {
  183. $session = $this->requestStack->getSession();
  184. return [
  185. 'isPro' => $session->get('isPro', 0),
  186. 'send' => $session->get('send', 0),
  187. 'deliveryId' => $session->get('deliveryId', 0),
  188. ];
  189. }
  190. public function getThermicCost(Delivery $delivery): float
  191. {
  192. return $this->isElectric($delivery) ? 0 : $this->getFuelSurcharge();
  193. }
  194. /**
  195. * TODO getDiscount.
  196. */
  197. public function getDiscount(): int
  198. {
  199. return 0;
  200. }
  201. public function getTotalHT(Delivery $delivery, int $distance, float $fraisMeteo, float $electricFee): float
  202. {
  203. $sousTotalHT = $this->getSousTotalHT($distance, $fraisMeteo);
  204. $options = $this->getOptions($delivery, $sousTotalHT);
  205. $thermic = $this->getThermicCost($delivery);
  206. $electric = $this->isElectric($delivery) ? $electricFee : 0;
  207. $discount = $this->getDiscount();
  208. return $sousTotalHT + $options['total'] - $discount + $thermic + $electric;
  209. }
  210. public function getTotalTTC(Delivery $delivery, int $distance, float $fraisMeteo, float $electricFee, float $tva): float
  211. {
  212. $sousTotalTTC = $this->getTotalHT($delivery, $distance, $fraisMeteo, $electricFee);
  213. return round($sousTotalTTC + ($tva * $sousTotalTTC), 2);
  214. }
  215. /**
  216. * @return ?array{totalTTC: float}
  217. */
  218. public function getTotals(Delivery $delivery)
  219. {
  220. return $delivery->getDeliveryTotals();
  221. }
  222. /**
  223. * Get TVA.
  224. *
  225. * @throws \Exception
  226. */
  227. public function getTVA(): float
  228. {
  229. /**
  230. * @var TaxRepository $taxRepository
  231. */
  232. $taxRepository = $this->doctrine->getRepository(Tax::class);
  233. /**
  234. * @var ?Tax $tva
  235. */
  236. $tva = $taxRepository->getCurrent(TaxEnum::NORMAL->value);
  237. if (!$tva) {
  238. throw new \Exception('TVA not found');
  239. }
  240. return $tva->getTauxPercent();
  241. }
  242. /**
  243. * get Price.
  244. *
  245. * @throws \Exception
  246. */
  247. public function getPrice(PriceComplementaryEnum $price): float
  248. {
  249. /**
  250. * @var PriceComplementaryRepository $priceComplementaryRepository
  251. */
  252. $priceComplementaryRepository = $this->doctrine->getRepository(PriceComplementary::class);
  253. $price = $priceComplementaryRepository->getCurrentPrice($price->value);
  254. if (null === $price || !($price instanceof PriceComplementary)) {
  255. throw new \Exception('Price not found');
  256. }
  257. return $price->getRateTTC();
  258. }
  259. /**
  260. * @throws \Exception
  261. */
  262. public function publishMessage(
  263. ?int $id, MercureToEnum $to, MercureTypeEnum $type, mixed $message, string $nextPost = null, string $nextGet = null
  264. ): void {
  265. if (!$id) {
  266. throw new \Exception('Id not found', Response::HTTP_NOT_FOUND);
  267. }
  268. $data = [
  269. 'to' => $to->value,
  270. 'type' => $type,
  271. 'message' => $message,
  272. ];
  273. if ($nextPost) {
  274. $data['nextPost'] = $nextPost;
  275. }
  276. if ($nextGet) {
  277. $data['nextGet'] = $nextGet;
  278. }
  279. $data['topic'] = sprintf('http://nibuco/%s/%s', $to->value, $id);
  280. $json = json_encode($data);
  281. if (!$json) {
  282. throw new \Exception('Json error', Response::HTTP_BAD_REQUEST);
  283. }
  284. $update = new Update(
  285. $data['topic'],
  286. $json
  287. );
  288. $this->hub->publish($update);
  289. $this->logger->info(\sprintf('MERCURE : Publish message to %s for type %s (id: %d)', $to->value, $type->value, $id));
  290. }
  291. }