src/Sage/Action/Customer/UpsertCustomerAction.php line 52

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Sage\Action\Customer;
  4. use App\Entity\Addressing\Address;
  5. use App\Entity\Addressing\AddressType;
  6. use App\Entity\ClinicalManager\ClinicalManager;
  7. use App\Entity\Customer\Customer;
  8. use App\Entity\Customer\CustomerGroup;
  9. use App\Entity\Customer\CustomerGroupInterface;
  10. use App\Entity\Distributor\Distributor;
  11. use App\Entity\Doctor\Doctor;
  12. use App\Entity\Product\Product;
  13. use App\Entity\Product\ReductionProduct;
  14. use App\Entity\Taxonomy\ReductionTaxon;
  15. use App\Entity\Taxonomy\Taxon;
  16. use App\Entity\User\AdminRoleInterface;
  17. use App\Entity\User\AdminUser;
  18. use App\Entity\User\ShopUser;
  19. use App\Entity\User\ShopUserRoleInterface;
  20. use App\Factory\ApiLoggerFactoryInterface;
  21. use App\Factory\ShopUserFactoryInterface;
  22. use App\Repository\CustomerRepository;
  23. use App\Repository\ProductRepository;
  24. use App\Repository\TaxonRepository;
  25. use App\Sage\Service\CustomerServiceInterface;
  26. use App\Service\Wallet\WalletRevenueSyncServiceInterface;
  27. use BitBag\SyliusAclPlugin\Entity\RoleInterface;
  28. use BitBag\SyliusAclPlugin\Repository\RoleRepositoryInterface;
  29. use DateTimeImmutable;
  30. use Doctrine\Persistence\ObjectManager;
  31. use Safe\DateTime;
  32. use Safe\Exceptions\JsonException;
  33. use Sylius\Bundle\CoreBundle\Doctrine\ORM\AddressRepository;
  34. use Sylius\Component\Resource\Factory\FactoryInterface;
  35. use Sylius\Component\Resource\Repository\RepositoryInterface;
  36. use Sylius\Component\User\Canonicalizer\CanonicalizerInterface;
  37. use Symfony\Component\HttpFoundation\JsonResponse;
  38. use Symfony\Component\HttpFoundation\Request;
  39. use Symfony\Component\HttpFoundation\Response;
  40. use Throwable;
  41. use function array_key_exists;
  42. use function count;
  43. use function is_numeric;
  44. use function is_string;
  45. use function Safe\json_encode;
  46. use function trim;
  47. final readonly class UpsertCustomerAction
  48. {
  49.     public function __construct(
  50.         private CustomerServiceInterface $customerService,
  51.         private CustomerRepository $customerRepository,
  52.         private RepositoryInterface $customerGroupRepository,
  53.         private FactoryInterface $customerFactory,
  54.         private ObjectManager $customerManager,
  55.         private ProductRepository $productRepository,
  56.         private TaxonRepository $taxonRepository,
  57.         private FactoryInterface $reductionProductFactory,
  58.         private FactoryInterface $reductionTaxonFactory,
  59.         private AddressRepository $addressRepository,
  60.         private FactoryInterface $addressFactory,
  61.         private FactoryInterface $doctorFactory,
  62.         private FactoryInterface $distributorFactory,
  63.         private FactoryInterface $clinicalManagerFactory,
  64.         private CanonicalizerInterface $canonicalizer,
  65.         private ShopUserFactoryInterface $shopUserFactory,
  66.         private FactoryInterface $adminUserFactory,
  67.         private RoleRepositoryInterface $roleRepository,
  68.         private ApiLoggerFactoryInterface $apiLoggerFactory,
  69.         private ObjectManager $apiLoggerManager,
  70.         private WalletRevenueSyncServiceInterface $walletRevenueSyncService,
  71.     ) {
  72.     }
  73.     /** @throws JsonException */
  74.     public function __invoke(Request $request): Response
  75.     {
  76.         $apiLogger $this->apiLoggerFactory->createNewFromRequest('UpsertCustomerAction'$request);
  77.         $params $request->request->all();
  78.         $customersParams = ! isset($params['customers']) ? [$params] : $params['customers'];
  79.         $errors $this->customerService->validate($customersParams);
  80.         if (count($errors) > 0) {
  81.             $apiLogger->setResponse(json_encode($errors));
  82.             $apiLogger->setStatusCode(Response::HTTP_BAD_REQUEST);
  83.             $this->apiLoggerManager->persist($apiLogger);
  84.             $this->apiLoggerManager->flush();
  85.             return new JsonResponse([
  86.                 'status' => 'error',
  87.                 'errors' => $errors,
  88.             ], Response::HTTP_BAD_REQUEST);
  89.         }
  90.         $response = [];
  91.         foreach ($customersParams as $value) {
  92.             $id $this->upsertCustomer($value);
  93.             $response[] = ['id' => $id'idSage' => $value['idSage']];
  94.         }
  95.         $apiLogger->setResponse(json_encode($response));
  96.         $apiLogger->setStatusCode(Response::HTTP_OK);
  97.         $this->apiLoggerManager->persist($apiLogger);
  98.         $this->apiLoggerManager->flush();
  99.         return new JsonResponse([
  100.             'status' => 'success',
  101.             'data' => $response,
  102.         ], Response::HTTP_OK);
  103.     }
  104.     private function upsertCustomer(array $params): int|null
  105.     {
  106.         if (! isset($params['group'])) {
  107.             $params['group'] = CustomerGroupInterface::DOCTOR// Default group is doctor
  108.         }
  109.         /** @var CustomerGroup $customerGroup */
  110.         $customerGroup $this->customerGroupRepository->findOneBy(['code' => $params['group']]);
  111.         if (! isset($params['id'])) {
  112.             /** @var Customer $customer */
  113.             $customer $this->customerFactory->createNew();
  114.             $customer->setIdSage($params['idSage']);
  115.         } else {
  116.             /** @var Customer $customer */
  117.             $customer $this->customerRepository->find($params['id']);
  118.         }
  119.         $email trim($params['email']);
  120.         $emailCanonical $this->canonicalizer->canonicalize($email);
  121.         $customer->setGroup($customerGroup);
  122.         $customer->setEmail($email);
  123.         $customer->setEmailCanonical($emailCanonical);
  124.         $customer->setLastName($params['name']);
  125.         $customer->setPhoneNumber($params['phoneNumber']);
  126.         $customer->setSocialReason($params['socialReason']);
  127.         $customer->setInterCommunityTvaNumber($params['interCommunityTvaNumber']);
  128.         $customer->setCity($params['city']);
  129.         $customer->setCountry($params['country']);
  130.         /** @var ?ShopUser $shopUser */
  131.         $shopUser $customer->getUser();
  132.         if ($shopUser === null) {
  133.             /** @var ShopUser $shopUser */
  134.             $shopUser $this->shopUserFactory->createNew();
  135.             $shopUser->setCustomer($customer);
  136.             $customer->setUser($shopUser);
  137.             $shopUser->addRole(ShopUserRoleInterface::USER);
  138.             $shopUser->setEnabled(false);
  139.             $shopUser->setLocked(true);
  140.             $shopUser->setDisabledAt(new DateTime());
  141.         }
  142.         $shopUser->setUsername($email);
  143.         $shopUser->setUsernameCanonical($emailCanonical);
  144.         foreach (CustomerGroupInterface::ALL as $role) {
  145.             $shopUser->removeRole($role);
  146.         }
  147.         switch ($customerGroup->getCode()) {
  148.             case CustomerGroupInterface::DOCTOR:
  149.                 $shopUser->addRole(ShopUserRoleInterface::DOCTOR);
  150.                 $doctor $customer->getDoctor();
  151.                 if ($doctor === null) {
  152.                     /** @var Doctor $doctor */
  153.                     $doctor $this->doctorFactory->createNew();
  154.                     $customer->setDoctor($doctor);
  155.                 }
  156.                 $customer->setClinicalManager(null);
  157.                 $customer->setDistributor(null);
  158.                 $customer->setAdminUser(null);
  159.                 break;
  160.             case CustomerGroupInterface::DISTRIBUTOR:
  161.                 $shopUser->addRole(ShopUserRoleInterface::DISTRIBUTOR);
  162.                 $distributor $customer->getDistributor();
  163.                 if ($distributor === null) {
  164.                     /** @var Distributor $distributor */
  165.                     $distributor $this->distributorFactory->createNew();
  166.                     $customer->setDistributor($distributor);
  167.                 }
  168.                 $customer->setClinicalManager(null);
  169.                 $customer->setDoctor(null);
  170.                 $customer->setAdminUser(null);
  171.                 break;
  172.             case CustomerGroupInterface::CLINICAL_MANAGER:
  173.                 $shopUser->addRole(ShopUserRoleInterface::CLINICAL_MANAGER);
  174.                 $clinicalManager $customer->getClinicalManager();
  175.                 if ($clinicalManager === null) {
  176.                     /** @var ClinicalManager $clinicalManager */
  177.                     $clinicalManager $this->clinicalManagerFactory->createNew();
  178.                     $customer->setClinicalManager($clinicalManager);
  179.                 }
  180.                 $customer->setClinicalManager($clinicalManager);
  181.                 $customer->setDistributor(null);
  182.                 $customer->setDoctor(null);
  183.                 $adminUser $customer->getAdminUser();
  184.                 if ($adminUser === null) {
  185.                     /** @var AdminUser $adminUser */
  186.                     $adminUser $this->adminUserFactory->createNew();
  187.                     $customer->setAdminUser($adminUser);
  188.                     $adminUser->setEnabled(false);
  189.                     $adminUser->setLocked(true);
  190.                 }
  191.                 $adminUser->setLastName($params['name']);
  192.                 $adminUser->setEmail($email);
  193.                 $adminUser->setEmailCanonical($emailCanonical);
  194.                 $adminUser->setUsername($email);
  195.                 $adminUser->setUsernameCanonical($emailCanonical);
  196.                 $adminUser->setLocaleCode('fr');
  197.                 $adminUser->setEnablePermissionChecker(true);
  198.                 /** @var RoleInterface $roleResource */
  199.                 $roleResource $this->roleRepository->findOneBy(['code' => AdminRoleInterface::CLINICAL_MANAGER]);
  200.                 $adminUser->addRoleResource($roleResource);
  201.                 break;
  202.         }
  203.         if (isset($params['reductionProducts'])) {
  204.             $this->insertProductReductions($params$customer);
  205.         }
  206.         if (isset($params['reductionTaxons'])) {
  207.             $this->insertTaxonReductions($params$customer);
  208.         }
  209.         if (isset($params['addresses'])) {
  210.             $this->insertAddresses($params$customer);
  211.         }
  212.         $this->customerManager->persist($customer);
  213.         $this->customerManager->flush();
  214.         $this->logRevenueAndGrantPointsFromSync($customer$params);
  215.         return $customer->getId();
  216.     }
  217.     private function logRevenueAndGrantPointsFromSync(Customer $customer, array $params): void
  218.     {
  219.         if (! array_key_exists('ca'$params) || ! is_numeric($params['ca']) || $params['ca'] <= 0) {
  220.             return;
  221.         }
  222.         $revenue = (float) $params['ca'];
  223.         $currency = isset($params['devise']) && is_string($params['devise']) ? $params['devise'] : 'EUR';
  224.         $dateCalcul null;
  225.         if (isset($params['date_calcul']) && $params['date_calcul'] !== null && $params['date_calcul'] !== '') {
  226.             try {
  227.                 $dateCalcul = new DateTimeImmutable($params['date_calcul']);
  228.             } catch (Throwable) {
  229.                 // ignore invalid date
  230.             }
  231.         }
  232.         $this->walletRevenueSyncService->logRevenueAndGrantPoints($customer$revenue$currency$dateCalcul);
  233.     }
  234.     private function insertProductReductions(array $paramsCustomer $customer): void
  235.     {
  236.         $customer->clearReductionProducts();
  237.         foreach ($params['reductionProducts'] as $productReduction) {
  238.             /** @var Product $product */
  239.             $product $this->productRepository->findOneBy(['code' => $productReduction['productCode']]);
  240.             /** @var ReductionProduct $reductionProduct */
  241.             $reductionProduct $this->reductionProductFactory->createNew();
  242.             $reductionProduct->addProduct($product);
  243.             $reductionProduct->setReductionType($productReduction['type']);
  244.             $reductionProduct->setReductionValue((int) $productReduction['value']);
  245.             $reductionProduct->setCustomer($customer);
  246.             $customer->addReductionProduct($reductionProduct);
  247.         }
  248.     }
  249.     private function insertTaxonReductions(array $paramsCustomer $customer): void
  250.     {
  251.         $customer->clearReductionTaxons();
  252.         foreach ($params['reductionTaxons'] as $taxonReduction) {
  253.             /** @var Taxon $taxon */
  254.             $taxon $this->taxonRepository->findOneBy(['code' => $taxonReduction['taxonCode']]);
  255.             /** @var ReductionTaxon $reductionTaxon */
  256.             $reductionTaxon $this->reductionTaxonFactory->createNew();
  257.             $reductionTaxon->addTaxon($taxon);
  258.             $reductionTaxon->setReductionType($taxonReduction['type']);
  259.             $reductionTaxon->setReductionValue((int) $taxonReduction['value']);
  260.             $reductionTaxon->setCustomer($customer);
  261.             $customer->addReductionTaxon($reductionTaxon);
  262.         }
  263.     }
  264.     private function insertAddresses(array $paramsCustomer $customer): void
  265.     {
  266.         foreach ($params['addresses'] as $addressParams) {
  267.             $customer->addAddress(
  268.                 $this->insertAddress($addressParams$customerAddressType::BILLING),
  269.             );
  270.             $customer->setDefaultAddress(
  271.                 $this->insertAddress($addressParams$customerAddressType::SHIPPING),
  272.             );
  273.         }
  274.     }
  275.     private function insertAddress(array $paramsCustomer $customerstring $type): Address
  276.     {
  277.         /** @var ?Address $address */
  278.         $address $this->addressRepository->findOneBy(['idSage' => $params['idSage'], 'type' => $type]);
  279.         if ($address === null) {
  280.             /** @var Address $address */
  281.             $address $this->addressFactory->createNew();
  282.             $address->setIdSage($params['idSage']);
  283.             $address->setType($type);
  284.         }
  285.         $address->setFirstName($params['name']);
  286.         $address->setLastName($params['name']);
  287.         $address->setPhoneNumber($params['phoneNumber']);
  288.         $address->setStreet($params['street']);
  289.         $address->setCity($params['city']);
  290.         $address->setPostcode($params['postCode']);
  291.         $address->setCountryCode($params['countryCode']);
  292.         $address->setCustomer($customer);
  293.         return $address;
  294.     }
  295. }