src/Controller/DistributorsController.php line 381

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Addresses;
  4. use App\Entity\ApiDetails;
  5. use App\Entity\AvailabilityTracker;
  6. use App\Entity\ChatMessages;
  7. use App\Entity\Clinics;
  8. use App\Entity\ClinicUsers;
  9. use App\Entity\Countries;
  10. use App\Entity\DistributorProducts;
  11. use App\Entity\Distributors;
  12. use App\Entity\DistributorUserPermissions;
  13. use App\Entity\DistributorUsers;
  14. use App\Entity\Notifications;
  15. use App\Entity\OrderItems;
  16. use App\Entity\Orders;
  17. use App\Entity\ProductManufacturers;
  18. use App\Entity\Products;
  19. use App\Entity\ProductsSpecies;
  20. use App\Entity\RefreshTokens;
  21. use App\Entity\RestrictedDomains;
  22. use App\Entity\Tracking;
  23. use App\Entity\UserPermissions;
  24. use App\Form\AddressesFormType;
  25. use App\Form\DistributorFormType;
  26. use App\Form\DistributorProductsFormType;
  27. use App\Form\DistributorUsersFormType;
  28. use App\Services\PaginationManager;
  29. use Doctrine\ORM\EntityManagerInterface;
  30. use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
  31. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  32. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  33. use Symfony\Component\HttpFoundation\JsonResponse;
  34. use Symfony\Component\HttpFoundation\Request;
  35. use Symfony\Component\HttpFoundation\RequestStack;
  36. use Symfony\Component\HttpFoundation\Response;
  37. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  38. use Symfony\Component\Mailer\MailerInterface;
  39. use Symfony\Component\Mime\Email;
  40. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  41. use Symfony\Component\Process\Exception\ProcessFailedException;
  42. use Symfony\Component\Process\Process;
  43. use Symfony\Component\Routing\Annotation\Route;
  44. use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
  45. class DistributorsController extends AbstractController
  46. {
  47.     private $em;
  48.     const ITEMS_PER_PAGE 10;
  49.     private $pageManager;
  50.     private $requestStack;
  51.     private $plainPassword;
  52.     private $encryptor;
  53.     private $mailer;
  54.     public function __construct(EntityManagerInterface $emPaginationManager $paginationRequestStack $requestStackEncryptor $encryptorMailerInterface $mailer) {
  55.         $this->em $em;
  56.         $this->pageManager $pagination;
  57.         $this->requestStack $requestStack;
  58.         $this->encryptor $encryptor;
  59.         $this->mailer $mailer;
  60.     }
  61.     #[Route('/distributors'name'distributors')]
  62.     public function index(): Response
  63.     {
  64.         return $this->render('frontend/distributors/index.html.twig', [
  65.             'controller_name' => 'DistributorsController',
  66.         ]);
  67.     }
  68.     #[Route('/distributors/register'name'distributor_reg')]
  69.     public function distributorReg(Request $request): Response
  70.     {
  71.         $countries $this->em->getRepository(Countries::class)->findBy([
  72.             'isActive' => 1,
  73.         ]);
  74.         $form $this->createRegisterForm();
  75.         return $this->render('frontend/distributors/register.html.twig', [
  76.             'form' => $form->createView(),
  77.             'countries' => $countries
  78.         ]);
  79.     }
  80.     #[Route('/distributors/register/check-email'name'distributor_check_email')]
  81.     public function distributorsCheckEmailAction(Request $request): Response
  82.     {
  83.         $email $request->request->get('email');
  84.         $domainName explode('@'$email);
  85.         $response['response'] = true;
  86.         $firstName '';
  87.         $restrictedDomains $this->em->getRepository(RestrictedDomains::class)->arrayFindAll();
  88.         foreach($restrictedDomains as $restrictedDomain)
  89.         {
  90.             if(md5($domainName[1]) == md5($restrictedDomain->getName()))
  91.             {
  92.                 $response['response'] = false;
  93.                 $response['restricted'] = true;
  94.                 return new JsonResponse($response);
  95.             }
  96.         }
  97.         $distributor $this->em->getRepository(Distributors::class)->findOneBy([
  98.             'hashedEmail' => md5($email),
  99.         ]);
  100.         $distributorDomain $this->em->getRepository(Distributors::class)->findOneBy([
  101.             'domainName' => md5($domainName[1]),
  102.         ]);
  103.         $distributorUsers $this->em->getRepository(DistributorUsers::class)->findOneBy([
  104.             'hashedEmail' => md5($email),
  105.         ]);
  106.         $clinic $this->em->getRepository(Clinics::class)->findOneBy([
  107.             'hashedEmail' => md5($email),
  108.         ]);
  109.         $clinicDomain $this->em->getRepository(Clinics::class)->findOneBy([
  110.             'domainName' => md5($domainName[1]),
  111.         ]);
  112.         $clinicUsers $this->em->getRepository(ClinicUsers::class)->findOneBy([
  113.             'hashedEmail' => md5($email),
  114.         ]);
  115.         if($clinicDomain != null)
  116.         {
  117.             $user $this->em->getRepository(ClinicUsers::class)->findOneBy([
  118.                 'clinic' => $clinicDomain->getId(),
  119.                 'isPrimary' => 1
  120.             ]);
  121.             $firstName $this->encryptor->decrypt($user->getFirstName());
  122.         }
  123.         if($distributorDomain != null)
  124.         {
  125.             $user $this->em->getRepository(DistributorUsers::class)->findOneBy([
  126.                 'distributor' => $distributorDomain->getId(),
  127.                 'isPrimary' => 1
  128.             ]);
  129.             $firstName $this->encryptor->decrypt($user->getFirstName());
  130.         }
  131.         $response['firstName'] = $firstName;
  132.         if($distributor != null || $distributorUsers != null || $clinic != null || $clinicUsers != null || $clinicDomain != null || $distributorDomain != null)
  133.         {
  134.             $response['response'] = false;
  135.             $response['restricted'] = false;
  136.         }
  137.         return new JsonResponse($response);
  138.     }
  139.     #[Route('/distributors/user/check-email'name'distributor_user_check_email')]
  140.     public function distributorsUserCheckEmailAction(Request $request): Response
  141.     {
  142.         $email $request->request->get('email');
  143.         $domainName explode('@'$email);
  144.         $response['response'] = true;
  145.         $firstName '';
  146.         $restrictedDomains $this->em->getRepository(RestrictedDomains::class)->arrayFindAll();
  147.         foreach($restrictedDomains as $restrictedDomain)
  148.         {
  149.             if(md5($domainName[1]) == md5($restrictedDomain->getName()))
  150.             {
  151.                 $response['response'] = false;
  152.                 $response['restricted'] = true;
  153.                 return new JsonResponse($response);
  154.             }
  155.         }
  156.         $distributorUsers $this->em->getRepository(DistributorUsers::class)->findOneBy([
  157.             'hashedEmail' => md5($email),
  158.         ]);
  159.         $clinic $this->em->getRepository(Clinics::class)->findOneBy([
  160.             'hashedEmail' => md5($email),
  161.         ]);
  162.         $clinicDomain $this->em->getRepository(Clinics::class)->findOneBy([
  163.             'domainName' => md5($domainName[1]),
  164.         ]);
  165.         $clinicUsers $this->em->getRepository(ClinicUsers::class)->findOneBy([
  166.             'hashedEmail' => md5($email),
  167.         ]);
  168.         if($distributorUsers != null || $clinic != null || $clinicUsers != null || $clinicDomain != null)
  169.         {
  170.             $response['response'] = false;
  171.             $response['restricted'] = false;
  172.         }
  173.         return new JsonResponse($response);
  174.     }
  175.     protected function createRegisterForm()
  176.     {
  177.         $distributors = new Distributors();
  178.         return $this->createForm(DistributorFormType::class, $distributors);
  179.     }
  180.     #[Route('/distributor/inventory'name'distributor_inventory')]
  181.     public function createDistributorInventoryForm()
  182.     {
  183.         $distributorProducts = new DistributorProducts();
  184.         return $this->createForm(DistributorProductsFormType::class, $distributorProducts);
  185.     }
  186.     #[Route('/distributor/addresses'name'distributor_addresses')]
  187.     public function createDistributorAddressesForm()
  188.     {
  189.         $addresses = new Addresses();
  190.         return $this->createForm(AddressesFormType::class, $addresses);
  191.     }
  192.     #[Route('/distributor/register/create'name'distributor_create')]
  193.     public function distributorCreateAction(Request $requestUserPasswordHasherInterface $passwordHasherMailerInterface $mailer): Response
  194.     {
  195.         $data $request->request;
  196.         $distributor $this->em->getRepository(Distributors::class)->findOneBy(['email' => $data->get('email')]);
  197.         $countries $this->em->getRepository(Countries::class)->find($data->get('country'));
  198.         $tracking $this->em->getRepository(Tracking::class)->find(3);
  199.         if($distributor == null) {
  200.             $distributors = new Distributors();
  201.             $plainTextPwd $this->generatePassword();
  202.             if (!empty($plainTextPwd)) {
  203.                 $domainName explode('@'$data->get('email'));
  204.                 $distributors->setDistributorName($this->encryptor->encrypt($data->get('distributor-name')));
  205.                 $distributors->setEmail($this->encryptor->encrypt($data->get('email')));
  206.                 $distributors->setHashedEmail(md5($data->get('email')));
  207.                 $distributors->setDomainName(md5($domainName[1]));
  208.                 $distributors->setTelephone($this->encryptor->encrypt($data->get('telephone')));
  209.                 $distributors->setIntlCode($this->encryptor->encrypt($data->get('intl-code')));
  210.                 $distributors->setIsoCode($this->encryptor->encrypt($data->get('iso-code')));
  211.                 $distributors->setAddressCountry($countries);
  212.                 $distributors->setTracking($tracking);
  213.                 $distributors->setIsApproved(0);
  214.                 $this->em->persist($distributors);
  215.                 $this->em->flush();
  216.                 // Create user
  217.                 $distributor $this->em->getRepository(Distributors::class)->findOneBy([
  218.                     'hashedEmail' => md5($data->get('email')),
  219.                 ]);
  220.                 $distributorUsers = new DistributorUsers();
  221.                 $hashed_pwd $passwordHasher->hashPassword($distributorUsers$plainTextPwd);
  222.                 $distributorUsers->setDistributor($distributor);
  223.                 $distributorUsers->setFirstName($this->encryptor->encrypt($data->get('first-name')));
  224.                 $distributorUsers->setLastName($this->encryptor->encrypt($data->get('last-name')));
  225.                 $distributorUsers->setPosition($this->encryptor->encrypt($data->get('position')));
  226.                 $distributorUsers->setEmail($this->encryptor->encrypt($data->get('email')));
  227.                 $distributorUsers->setHashedEmail(md5($data->get('email')));
  228.                 $distributorUsers->setTelephone($this->encryptor->encrypt($data->get('telephone')));
  229.                 $distributorUsers->setRoles(['ROLE_DISTRIBUTOR']);
  230.                 $distributorUsers->setPassword($hashed_pwd);
  231.                 $distributorUsers->setIsPrimary(1);
  232.                 $this->em->persist($distributorUsers);
  233.                 $this->em->flush();
  234.                 // Assign User Permissions
  235.                 $userPermissions $this->em->getRepository(UserPermissions::class)->findBy([
  236.                     'isDistributor' => 1,
  237.                 ]);
  238.                 foreach($userPermissions as $userPermission){
  239.                     $distributorUserPermissions = new DistributorUserPermissions();
  240.                     $distributorUserPermissions->setUser($distributorUsers);
  241.                     $distributorUserPermissions->setDistributor($distributors);
  242.                     $distributorUserPermissions->setPermission($userPermission);
  243.                     $this->em->persist($distributorUserPermissions);
  244.                 }
  245.                 $this->em->flush();
  246.                 // Send Email
  247.                 $body '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  248.                 $body .= '<tr><td colspan="2">Hi '$data->get('first_name') .',</td></tr>';
  249.                 $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  250.                 $body .= '<tr><td colspan="2">Please use the credentials below login to the Fluid Backend.</td></tr>';
  251.                 $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  252.                 $body .= '<tr>';
  253.                 $body .= '    <td><b>URL: </b></td>';
  254.                 $body .= '    <td><a href="https://'$_SERVER['HTTP_HOST'] .'/distributors/login">https://'$_SERVER['HTTP_HOST'] .'/distributor/login</a></td>';
  255.                 $body .= '</tr>';
  256.                 $body .= '<tr>';
  257.                 $body .= '    <td><b>Username: </b></td>';
  258.                 $body .= '    <td>'$data->get('email') .'</td>';
  259.                 $body .= '</tr>';
  260.                 $body .= '<tr>';
  261.                 $body .= '    <td><b>Password: </b></td>';
  262.                 $body .= '    <td>'$plainTextPwd .'</td>';
  263.                 $body .= '</tr>';
  264.                 $body .= '</table>';
  265.                 $subject 'Fluid Login Credentials';
  266.                 $to $data->get('email');
  267.                 exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($body) .'" "'$to .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  268.             }
  269.             $response '
  270.             <p class="text-center">
  271.                 Your Fluid account was successfully created, an email with your login credentials has been sent to your inbox.
  272.             </p>';
  273.         } else {
  274.             $response false;
  275.         }
  276.         return new JsonResponse($response);
  277.     }
  278.     #[Route('/distributors/dashboard'name'distributor_dashboard')]
  279.     #[Route('/distributors/account'name'distributor_account')]
  280.     #[Route('/distributors/about'name'distributor_about')]
  281.     #[Route('/distributors/operating-hours'name'distributor_operating_hours')]
  282.     #[Route('/distributors/refund-policy'name'distributor_refund_policy')]
  283.     #[Route('/distributors/sales-tax-policy'name'distributor_sales_tax_policy')]
  284.     #[Route('/distributors/shipping-policy'name'distributor_shipping_policy')]
  285.     #[Route('/distributors/manage-inventory'name'distributor_manage_inventory')]
  286.     #[Route('/distributors/users'name'distributor_get_users')]
  287.     #[Route('/distributors/order/{order_id}'name'distributor_order')]
  288.     #[Route('/distributors/orders/{distributor_id}'name'distributor_order_list')]
  289.     #[Route('/distributors/customers/1'name'distributor_customer_list')]
  290.     #[Route('/distributors/inventory/list'name'distributor_inventory_list')]
  291.     public function distributorDashboardAction(Request $request): Response
  292.     {
  293.         if($this->get('security.token_storage')->getToken() == null){
  294.             $this->addFlash('danger''Your session expired due to inactivity, please login.');
  295.             return $this->redirectToRoute('distributor_login');
  296.         }
  297.         $distributor $this->getUser()->getDistributor();
  298.         $user $this->getUser();
  299.         $username $distributor->getDistributorName();
  300.         $permissions = [];
  301.         foreach($user->getDistributorUserPermissions() as $permission){
  302.             $permissions[] = $permission->getPermission()->getId();
  303.         }
  304.         return $this->render('frontend/distributors/index.html.twig',[
  305.             'distributor' => $distributor,
  306.             'permissions' => json_encode($permissions),
  307.             'username' => $username,
  308.         ]);
  309.     }
  310.     #[Route('/sellers'name'sellers_page')]
  311.     public function sellersAction(Request $request): Response
  312.     {
  313.         $sellers $this->em->getRepository(Distributors::class)->findAll();
  314.         return $this->render('frontend/sellers.html.twig', [
  315.             'sellers' => $sellers,
  316.         ]);
  317.     }
  318.     #[Route('/distributor/update/personal-information'name'distributor_update_personal_information')]
  319.     public function distributorUpdatePersonalInformationAction(Request $request): Response
  320.     {
  321.         $data $request->request;
  322.         $username $this->get('security.token_storage')->getToken()->getUser()->getUserIdentifier();
  323.         $distributor $this->em->getRepository(Distributors::class)->findOneBy(['email' => $username]);
  324.         if($distributor != null) {
  325.             $distributor->setFirstName($data->get('first_name'));
  326.             $distributor->setLastName($data->get('last_name'));
  327.             $distributor->setTelephone($data->get('telephone'));
  328.             $distributor->setPosition($data->get('position'));
  329.             $this->em->persist($distributor);
  330.             $this->em->flush();
  331.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Personal details successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  332.         } else {
  333.             $response '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  334.         }
  335.         return new JsonResponse($response);
  336.     }
  337.     #[Route('/distributors/update/company-information'name'distributor_update_company_information')]
  338.     public function distributorUpdateCompanyInformationAction(Request $request): Response
  339.     {
  340.         $data $request->request->get('distributor_form');
  341.         $distributor $this->getUser()->getDistributor();
  342.         $countryId = (int) $data['addressCountry'];
  343.         $logo '';
  344.         $country $this->em->getRepository(Countries::class)->find($countryId);
  345.         $isApproved = (bool) $distributor->getIsApproved() ?? false;
  346.         $tradeLicense $_FILES['distributor_form']['name']['trade-license-file'];
  347.         $tradeLicenseNo $data['trade-license-no'];
  348.         $tradeLicenseExpDate $data['trade-license-exp-date'];
  349.         // Account approval required if reg docs change
  350.         if(
  351.             !empty($tradeLicense) || $tradeLicenseNo != $this->encryptor->decrypt($distributor->getTradeLicenseNo()) ||
  352.             $tradeLicenseExpDate != $distributor->getTradeLicenseExpDate()->format('Y-m-d')
  353.         )
  354.         {
  355.             $distributor->setIsApproved(0);
  356.             $isApproved false;
  357.         }
  358.         if($distributor != null)
  359.         {
  360.             $domainName explode('@'$data['email']);
  361.             $distributor->setDistributorName($this->encryptor->encrypt($data['distributor-name']));
  362.             $distributor->setTelephone($this->encryptor->encrypt($data['telephone']));
  363.             $distributor->setEmail($this->encryptor->encrypt($data['email']));
  364.             $distributor->setWebsite($this->encryptor->encrypt($data['website']));
  365.             $distributor->setDomainName(md5($domainName[1]));
  366.             $distributor->setAddressCountry($country);
  367.             $distributor->setAddressStreet($this->encryptor->encrypt($data['address-street']));
  368.             $distributor->setAddressCity($this->encryptor->encrypt($data['address-city']));
  369.             $distributor->setAddressPostalCode($this->encryptor->encrypt($data['address-postal-code']));
  370.             $distributor->setAddressState($this->encryptor->encrypt($data['address-state']));
  371.             $distributor->setIsoCode($this->encryptor->encrypt($data['iso-code']));
  372.             $distributor->setIntlCode($this->encryptor->encrypt($data['intl-code']));
  373.             $distributor->setManagerFirstName($this->encryptor->encrypt($data['manager-first-name']));
  374.             $distributor->setManagerLastName($this->encryptor->encrypt($data['manager-last-name']));
  375.             $distributor->setManagerIdNo($this->encryptor->encrypt($data['manager-id-no']));
  376.             $distributor->setManagerIdExpDate(new \DateTime($data['manager-id-exp-date']));
  377.             $distributor->setTradeLicenseNo($this->encryptor->encrypt($data['trade-license-no']));
  378.             $distributor->setTradeLicenseExpDate(new \DateTime($data['trade-license-exp-date']));
  379.             if(!empty($_FILES['distributor_form']['name']['trade-license-file']))
  380.             {
  381.                 $extension pathinfo($_FILES['distributor_form']['name']['trade-license-file'], PATHINFO_EXTENSION);
  382.                 $file $distributor->getId() . '-' uniqid() . '.' $extension;
  383.                 $targetFile __DIR__ '/../../public/documents/' $file;
  384.                 if(move_uploaded_file($_FILES['distributor_form']['tmp_name']['trade-license-file'], $targetFile))
  385.                 {
  386.                     $distributor->setTradeLicense($file);
  387.                 }
  388.             }
  389.             if(!empty($_FILES['distributor_form']['name']['logo']))
  390.             {
  391.                 $extension pathinfo($_FILES['distributor_form']['name']['logo'], PATHINFO_EXTENSION);
  392.                 $file $distributor->getId() . '-' uniqid() . '.' $extension;
  393.                 $targetFile __DIR__ '/../../public/images/logos/' $file;
  394.                 if (move_uploaded_file($_FILES['distributor_form']['tmp_name']['logo'], $targetFile))
  395.                 {
  396.                     $distributor->setLogo($file);
  397.                     $logo $file;
  398.                 }
  399.             }
  400.             $this->em->persist($distributor);
  401.             $this->em->flush();
  402.             // Send Approval Email
  403.             if(!$isApproved)
  404.             {
  405.                 $orderUrl $this->getParameter('app.base_url') . '/admin/distributor/'$distributor->getId();
  406.                 $html '<p>Please <a href="'$orderUrl .'">click here</a> to view the distributors details.</p><br>';
  407.                 $html $this->forward('App\Controller\ResetPasswordController::emailFooter', [
  408.                     'html'  => $html,
  409.                 ]);
  410.                 $subject 'Fluid - Account Approval Request';
  411.                 $to $this->getParameter('app.email_admin');
  412.                 exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($html) .'" "'$to .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  413.             }
  414.             $message '<b><i class="fa-solid fa-circle-check"></i></i></b> Company details successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  415.         }
  416.         else
  417.         {
  418.             $message '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  419.         }
  420.         $response = [
  421.             'message' => $message,
  422.             'logo' => $logo,
  423.         ];
  424.         return new JsonResponse($response);
  425.     }
  426.     #[Route('/distributors/download/trade-license/{tradeLicense}'name'distributors_download_trade_license')]
  427.     public function distributorDownloadTradeLicenseAction(Request $request)
  428.     {
  429.         $path __DIR__ '/../../public/documents/';
  430.         $tradeLicense $path $request->get('tradeLicense');
  431.         $response = new BinaryFileResponse($tradeLicense);
  432.         $response->setContentDisposition(
  433.             ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  434.             basename($tradeLicense)
  435.         );
  436.         return $response;
  437.     }
  438.     #[Route('/distributors/update/about_us'name'distributor_update_about_us')]
  439.     public function distributorUpdateAboutUsAction(Request $request): Response
  440.     {
  441.         $data $request->request;
  442.         $distributor $this->getUser()->getDistributor();
  443.         if($distributor != null)
  444.         {
  445.             $about $data->get('about-us');
  446.             if(!empty($about))
  447.             {
  448.                 $distributor->setAbout($about);
  449.                 $this->em->persist($distributor);
  450.                 $this->em->flush();
  451.             }
  452.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> About us successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  453.         }
  454.         else
  455.         {
  456.             $response '<b><i class="fas fa-check-circle"></i> An error occurred.';
  457.         }
  458.         return new JsonResponse($response);
  459.     }
  460.     #[Route('/distributors/update/operating_hours'name'distributor_update_operating_hours')]
  461.     public function distributorUpdateOperatingHoursAction(Request $request): Response
  462.     {
  463.         $data $request->request;
  464.         $distributor $this->getUser()->getDistributor();
  465.         if($distributor != null)
  466.         {
  467.             if(!empty($data->get('operating-hours')))
  468.             {
  469.                 $distributor->setOperatingHours($data->get('operating-hours'));
  470.             }
  471.             $this->em->persist($distributor);
  472.             $this->em->flush();
  473.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Operating hours successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  474.         }
  475.         else
  476.         {
  477.             $response '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  478.         }
  479.         return new JsonResponse($response);
  480.     }
  481.     #[Route('/distributors/update/refund_policy'name'distributor_update_refund_policy')]
  482.     public function distributorUpdateRefundPolicyAction(Request $request): Response
  483.     {
  484.         $data $request->request;
  485.         $distributor $this->getUser()->getDistributor();
  486.         if($distributor != null)
  487.         {
  488.             if(!empty($data->get('refund-policy')))
  489.             {
  490.                 $distributor->setRefundPolicy($data->get('refund-policy'));
  491.             }
  492.             $this->em->persist($distributor);
  493.             $this->em->flush();
  494.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Refund policy successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  495.         }
  496.         else
  497.         {
  498.             $response '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  499.         }
  500.         return new JsonResponse($response);
  501.     }
  502.     #[Route('/distributors/update/sales_tax_policy'name'distributor_update_sales_tax_policy')]
  503.     public function distributorUpdateSalesTaxPolicyAction(Request $request): Response
  504.     {
  505.         $data $request->request;
  506.         $distributor $this->getUser()->getDistributor();
  507.         if($distributor != null)
  508.         {
  509.             if(!empty($data->get('sales-tax-policy')))
  510.             {
  511.                 $distributor->setSalesTaxPolicy($data->get('sales-tax-policy'));
  512.             }
  513.             $this->em->persist($distributor);
  514.             $this->em->flush();
  515.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Sales tax policy successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  516.         }
  517.         else
  518.         {
  519.             $response '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  520.         }
  521.         return new JsonResponse($response);
  522.     }
  523.     #[Route('/distributors/update/shipping_policy'name'distributor_update_shipping_policy')]
  524.     public function distributorUpdateShippingPolicyAction(Request $request): Response
  525.     {
  526.         $data $request->request;
  527.         $distributor $this->getUser()->getDistributor();
  528.         if($distributor != null)
  529.         {
  530.             if(!empty($data->get('shipping-policy')))
  531.             {
  532.                 $distributor->setShippingPolicy($data->get('shipping-policy'));
  533.             }
  534.             $this->em->persist($distributor);
  535.             $this->em->flush();
  536.             $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Shipping policy successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  537.         }
  538.         else
  539.         {
  540.             $response '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  541.         }
  542.         return new JsonResponse($response);
  543.     }
  544.     #[Route('/distributors/inventory-search'name'distributor_inventory_search')]
  545.     public function distributorInventorySearchAction(Request $request): Response
  546.     {
  547.         $products $this->em->getRepository(Products::class)->findBySearch($request->get('keyword'));
  548.         $select '<ul id="product_list">';
  549.         foreach($products as $product){
  550.             $id $product->getId();
  551.             $name $product->getName();
  552.             $dosage '';
  553.             $size '';
  554.             if(!empty($product->getDosage())) {
  555.                 $unit '';
  556.                 if(!empty($product->getUnit())) {
  557.                     $unit $product->getUnit();
  558.                 }
  559.                 $dosage ' | '$product->getDosage() . $unit;
  560.             }
  561.             if(!empty($product->getSize())) {
  562.                 $size ' | '$product->getSize();
  563.             }
  564.             $select .= "
  565.             <li 
  566.                 class=\"search-item\"
  567.                 data-product-id=\"$id\"
  568.                 data-product-name=\"$name\"
  569.                 data-action='click->products--distributor-products#onclickEditIcon'
  570.             >$name$dosage$size</li>
  571.             ";
  572.         }
  573.         $select .= '</ul>';
  574.         return new Response($select);
  575.     }
  576.     #[Route('/distributors/inventory-get'name'distributor_inventory_get')]
  577.     public function distributorGetInventoryAction(Request $request,TokenStorageInterface $tokenStorage): Response
  578.     {
  579.         $productId = (int) $request->request->get('product-id');
  580.         $products $this->em->getRepository(Products::class)->find($productId);
  581.         if($products != null)
  582.         {
  583.             $distributorId $this->getUser()->getDistributor()->getId();
  584.             $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  585.             $response = [];
  586.             $response['html'] = json_decode($this->forward('App\Controller\DistributorProductsController::getDistributorProductAction')
  587.             ->getContent());
  588.             $distributorProduct $this->em->getRepository(Distributors::class)
  589.                 ->getDistributorProduct($distributor->getId(), $productId);
  590.             if($distributorProduct != null)
  591.             {
  592.                 $response['distributor_id'] = $distributor->getId();
  593.                 $response['itemId'] = $distributorProduct[0]['distributorProducts'][0]['itemId'];
  594.                 $response['sku'] = $distributorProduct[0]['distributorProducts'][0]['sku'];
  595.                 $response['unit_price'] = $distributorProduct[0]['distributorProducts'][0]['unitPrice'];
  596.                 $response['stock_count'] = $distributorProduct[0]['distributorProducts'][0]['stockCount'];
  597.                 $response['expiry_date'] = '';
  598.                 $response['tax_exempt'] = $distributorProduct[0]['distributorProducts'][0]['taxExempt'];
  599.                 $response['product'] = $distributorProduct[0]['distributorProducts'][0]['product'];
  600.                 if($distributorProduct[0]['distributorProducts'][0]['expiryDate'] != null)
  601.                 {
  602.                     $response['expiry_date'] = $distributorProduct[0]['distributorProducts'][0]['expiryDate']->format('Y-m-d');
  603.                 }
  604.             }
  605.             else
  606.             {
  607.                 $product $this->em->getRepository(Products::class)->find($productId);
  608.                 $response['distributor_id'] = $distributor->getId();
  609.                 $response['sku'] = '';
  610.                 $response['distributor_no'] = '';
  611.                 $response['unit_price'] = '';
  612.                 $response['stock_count'] = '';
  613.                 $response['expiry_date'] = '';
  614.                 $response['tax_exempt'] = 0;
  615.                 $response['product'] = [
  616.                     'dosage' => $product->getDosage(),
  617.                     'size' => $product->getSize(),
  618.                     'unit' => $product->getUnit(),
  619.                     'activeIngredient' => $product->getActiveIngredient(),
  620.                 ];
  621.             }
  622.         }
  623.         else
  624.         {
  625.             $response['message'] = 'Inventory item not found';
  626.         }
  627.         return new JsonResponse($response);
  628.     }
  629.     #[Route('/distributors/inventory-update'name'distributor_inventory_update')]
  630.     public function distributorUpdateInventoryAction(Request $requestMailerInterface $mailer): Response
  631.     {
  632.         $data $request->request->get('distributor_products_form');
  633.         $product $this->em->getRepository(Products::class)->find($data['product']);
  634.         $distributor $this->em->getRepository(Distributors::class)->find($data['distributor']);
  635.         $distributorProducts $this->em->getRepository(DistributorProducts::class)->findOneBy(
  636.             [
  637.                 'product' => $data['product'],
  638.                 'distributor' => $data['distributor']
  639.             ]
  640.         );
  641.         $tracking false;
  642.         $response['unitPrice'] = 0.00;
  643.         $response['stockLevel'] = 0;
  644.         if($distributorProducts == null){
  645.             $distributorProducts = new DistributorProducts();
  646.         } else {
  647.             if($distributorProducts->getStockCount() == 0){
  648.                 $tracking true;
  649.             }
  650.         }
  651.         if(!empty($data['product']) && !empty($data['distributor'])){
  652.             $trackingId $distributor->getTracking()->getId();
  653.             $distributorProducts->setDistributor($distributor);
  654.             $distributorProducts->setProduct($product);
  655.             $distributorProducts->setSku($data['sku']);
  656.             $distributorProducts->setItemId($data['itemId']);
  657.             $distributorProducts->setTaxExempt($data['taxExempt']);
  658.             $distributorProducts->setIsActive(1);
  659.             $taxExempt 0;
  660.             if(!empty($data['taxExempt'])){
  661.                 $taxExempt $data['taxExempt'];
  662.             }
  663.             $distributorProducts->setTaxExempt($taxExempt);
  664.             if($trackingId == 3)
  665.             {
  666.                 $distributorProducts->setUnitPrice($data['unitPrice']);
  667.                 $distributorProducts->setStockCount((int)$data['stockCount']);
  668.             }
  669.             // Get stock and price from API
  670.             if($trackingId == 1){
  671.                 // Retrieve price & stock from api
  672.                 $distributorId $distributor->getId();
  673.                 $priceStockLevels json_decode($this->forward('App\Controller\ProductsController::zohoRetrieveItem',[
  674.                     'distributorId' => $distributorId,
  675.                     'itemId' => $data['itemId'],
  676.                 ])->getContent(), true);
  677.                 $response['unitPrice'] = $priceStockLevels['unitPrice'] ?? 0.00;
  678.                 $response['stockLevel'] = $priceStockLevels['stockLevel'] ?? 0;
  679.                 $distributorProducts->setUnitPrice($response['unitPrice']);
  680.                 $distributorProducts->setStockCount($response['stockLevel']);
  681.             }
  682.             $this->em->persist($distributorProducts);
  683.             $this->em->flush();
  684.             // Update parent stock level
  685.             $stockCount $this->em->getRepository(DistributorProducts::class)->getProductStockCount($product->getId());
  686.             $product->setStockCount($stockCount[0][1]);
  687.             // Get the lowest price
  688.             $lowestPrice $this->em->getRepository(DistributorProducts::class)->getLowestPrice($product->getId());
  689.             $product->setUnitPrice($lowestPrice[0]['unitPrice'] ?? 0.00);
  690.             $this->em->persist($product);
  691.             $this->em->flush();
  692.             // Availability Tracker
  693.             $availabilityTracker '';
  694.             if($tracking){
  695.                 $availabilityTracker $this->em->getRepository(AvailabilityTracker::class)->findBy([
  696.                     'product' => $product->getId(),
  697.                     'distributor' => $data['distributor'],
  698.                     'isSent' => 0,
  699.                 ]);
  700.                 foreach($availabilityTracker as $tracker){
  701.                     $methodId $tracker->getCommunication()->getCommunicationMethod()->getId();
  702.                     $sendTo $tracker->getCommunication()->getSendTo();
  703.                     $product $tracker->getProduct();
  704.                     // In app notifications
  705.                     if($methodId == 1){
  706.                         $notifications = new Notifications();
  707.                         $notifications->setClinic($tracker->getClinic());
  708.                         $notifications->setIsRead(0);
  709.                         $notifications->setIsReadDistributor(0);
  710.                         $notifications->setIsActive(1);
  711.                         $notifications->setAvailabilityTracker($tracker);
  712.                         $this->em->persist($notifications);
  713.                         $this->em->flush();
  714.                         // Get the newly created notification
  715.                         $notification '
  716.                         <table class="w-100">
  717.                             <tr>
  718.                                 <td><span class="badge bg-success me-3">New Stock</span></td>
  719.                                 <td>'$product->getName() .' '$product->getDosage() . $product->getUnit() .'</td>
  720.                                 <td>
  721.                                     <a href="#" class="delete-notification" data-notification-id="'$notifications->getId() .'">
  722.                                         <i class="fa-solid fa-xmark text-black-25 ms-3 float-end"></i>
  723.                                     </a>
  724.                                 </td>
  725.                             </tr>
  726.                         </table>';
  727.                         $notifications $this->em->getRepository(Notifications::class)->find($notifications->getId());
  728.                         $notifications->setNotification($notification);
  729.                         $this->em->persist($notifications);
  730.                         $this->em->flush();
  731.                     // Email notifications
  732.                     } elseif($methodId == 2){
  733.                         $body '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  734.                         $body .= '<tr><td colspan="2">'$product->getName() .' '$product->getDosage() . $product->getUnit() .' is back in stock</td></tr>';
  735.                         $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  736.                         $body .= '<tr>';
  737.                         $body .= '    <td><b>Distributor: </b></td>';
  738.                         $body .= '    <td>'$tracker->getDistributor()->getDistributorName() .'</td>';
  739.                         $body .= '</tr>';
  740.                         $body .= '<tr>';
  741.                         $body .= '    <td><b>Stock Level: </b></td>';
  742.                         $body .= '    <td>'$tracker->getProduct()->getDistributorProducts()[0]->getStockCount() .'</td>';
  743.                         $body .= '</tr>';
  744.                         $body .= '</table>';
  745.                         $subject 'Fluid Stock Level Update';
  746.                         $to $sendTo;
  747.                         exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($body) .'" "'$to .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  748.                     // Text notifications
  749.                     } elseif($methodId == 3){
  750.                     }
  751.                     $availabilityTracker $this->em->getRepository(AvailabilityTracker::class)->find($tracker->getId());
  752.                     $availabilityTracker->setIsSent(1);
  753.                     $this->em->persist($availabilityTracker);
  754.                     $this->em->flush();
  755.                 }
  756.             }
  757.             $response['flash'] = '<b><i class="fa-solid fa-circle-check"></i></i></b> '$product->getName() .' successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  758.         } else {
  759.             $response['flash'] = 'An error occurred';
  760.         }
  761.         return new JsonResponse($response);
  762.     }
  763.     #[Route('/distributors/error'name'distributor_error_500')]
  764.     public function distributor500ErrorAction(Request $request): Response
  765.     {
  766.         $id $this->getUser()->getDistributor()->getId();
  767.         if($id == null){
  768.             return $this->render('security/login.html.twig', [
  769.                 'last_username' => '',
  770.                 'error' => '',
  771.                 'csrf_token_intention' => 'authenticate',
  772.                 'user_type' => 'distributors',
  773.             ]);
  774.         }
  775.         return $this->render('bundles/TwigBundle/Exception/error500.html.twig',[
  776.             'type' => 'distributors',
  777.             'id' => $id,
  778.         ]);
  779.     }
  780.     #[Route('/distributors/zoho/set/refresh-token'name'zoho_set_refresh_token')]
  781.     public function setZohoRefreshTokenAction(Request $request): Response
  782.     {
  783.         $distributorId $this->getUser()->getDistributor()->getId();
  784.         $apiDetails $this->em->getRepository(ApiDetails::class)->findOneBy([
  785.             'distributor' => $distributorId,
  786.         ]);
  787.         $code $request->query->get('code');
  788.         $error $request->query->get('error');
  789.         if($code != null) {
  790.             $curl curl_init();
  791.             $clientId $this->encryptor->decrypt($apiDetails->getClientId());
  792.             $clientSecret $this->encryptor->decrypt($apiDetails->getClientSecret());
  793.             $endpoint 'https://accounts.zoho.com/oauth/v2/token?code=' $code '&client_id=' $clientId '&';
  794.             $endpoint .= 'client_secret=' $clientSecret '&redirect_uri=https://fluid.vet/distributors/zoho/set/refresh-token&';
  795.             $endpoint .= 'grant_type=authorization_code';
  796.             curl_setopt_array($curl, [
  797.                 CURLOPT_URL => $endpoint,
  798.                 CURLOPT_RETURNTRANSFER => true,
  799.                 CURLOPT_ENCODING => '',
  800.                 CURLOPT_MAXREDIRS => 10,
  801.                 CURLOPT_TIMEOUT => 0,
  802.                 CURLOPT_FOLLOWLOCATION => true,
  803.                 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  804.                 CURLOPT_CUSTOMREQUEST => 'POST'
  805.             ]);
  806.             $json curl_exec($curl);
  807.             curl_close($curl);
  808.             $response json_decode($jsontrue);
  809.             if(array_key_exists('refresh_token'$response)){
  810.                 $session $this->requestStack->getSession();
  811.                 $session->set('accessToken'$response['access_token']);
  812.                 $session->set('refreshToken'$response['refresh_token']);
  813.                 $refreshToken = new RefreshTokens();
  814.                 $api $this->getUser()->getDistributor()->getApiDetails();
  815.                 $refreshToken->setToken($response['refresh_token']);
  816.                 $refreshToken->setApiDetails($api);
  817.                 $this->em->persist($refreshToken);
  818.                 $this->em->flush();
  819.                 return $this->redirectToRoute('distributor_manage_inventory');
  820.             } elseif(array_key_exists('error'$response)){
  821.                 echo $response['error'];
  822.             }
  823.         } elseif($error != null){
  824.             echo $error;
  825.             file_put_contents(__DIR__ '/../../public/zoho.log'date('Y-m-d H:i:s') .': '$error "\n"FILE_APPEND);
  826.         }
  827.         return new JsonResponse('');
  828.     }
  829.     #[Route('/distributors/get/refresh-token'name'distributor_get_access_token')]
  830.     public function distributorGetRefreshTokenAction(Request $request): Response
  831.     {
  832.         $id $this->getUser()->getDistributor()->getId();
  833.         $button false;
  834.         $token false;
  835.         $error false;
  836.         if($id == null){
  837.             return $this->render('security/login.html.twig', [
  838.                 'last_username' => '',
  839.                 'error' => '',
  840.                 'csrf_token_intention' => 'authenticate',
  841.                 'user_type' => 'distributors',
  842.             ]);
  843.         }
  844.         $api $this->em->getRepository(ApiDetails::class)->findOneBy([
  845.             'distributor' => $id,
  846.         ]);
  847.         // Check client id & secret exist
  848.         if($api == null){
  849.             $error true;
  850.         } else {
  851.             $refreshTokens $api->getRefreshTokens();
  852.             if(count($refreshTokens) == 0){
  853.                 $button true;
  854.             } else {
  855.                 $token true;
  856.             }
  857.         }
  858.         return new JsonResponse([
  859.             'token' => $token,
  860.             'button' => $button,
  861.             'error' => $error
  862.         ]);
  863.     }
  864.     #[Route('/distributors/zoho/get/access-token'name'clinics_get_zoho_access_token')]
  865.     public function clinicsGetAccessTokenAction(Request $request): Response
  866.     {
  867.         $distributorId $this->getUser()->getDistributor()->getId();
  868.         $apiDetails $this->em->getRepository(ApiDetails::class)->findOneBy([
  869.             'distributor' => $distributorId,
  870.         ]);
  871.         $code $request->get('code');
  872.         $error $request->get('error');
  873.         if($code != null) {
  874.             $curl curl_init();
  875.             $clientId $this->encryptor->decrypt($apiDetails->getClientId());
  876.             $clientSecret $this->encryptor->decrypt($apiDetails->getClientSecret());
  877.             $endpoint 'https://accounts.zoho.com/oauth/v2/token?code=' $code '&client_id=' $clientId '&';
  878.             $endpoint .= 'client_secret=' $clientSecret '&redirect_uri=https://fluid.vet/clinics/zoho/access-token&';
  879.             $endpoint .= 'grant_type=authorization_code';
  880.             curl_setopt_array($curl, [
  881.                 CURLOPT_URL => $endpoint,
  882.                 CURLOPT_RETURNTRANSFER => true,
  883.                 CURLOPT_ENCODING => '',
  884.                 CURLOPT_MAXREDIRS => 10,
  885.                 CURLOPT_TIMEOUT => 0,
  886.                 CURLOPT_FOLLOWLOCATION => true,
  887.                 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  888.                 CURLOPT_CUSTOMREQUEST => 'POST'
  889.             ]);
  890.             $json curl_exec($curl);
  891.             curl_close($curl);
  892.             $response json_decode($jsontrue);
  893.             if(array_key_exists('refresh_token'$response)){
  894.                 $session $this->requestStack->getSession();
  895.                 $session->set('accessToken'$response['access_token']);
  896.                 $session->set('refreshToken'$response['refresh_token']);
  897.                 $refreshToken = new RefreshTokens();
  898.                 $distributor $this->getUser()->getDistributor();
  899.                 $refreshToken->setToken($response['refresh_token']);
  900.                 $refreshToken->setDistributor($distributor);
  901.                 $this->em->persist($refreshToken);
  902.                 $this->em->flush();
  903.                 $this->redirectToRoute('distributor_manage_inventory');
  904.             } elseif(array_key_exists('error'$response)){
  905.                 echo $response['error'];
  906.             }
  907.         } elseif($error != null){
  908.             echo $error;
  909.         }
  910.         return new JsonResponse('');
  911.     }
  912.     #[Route('/distributors/update-tracking-id'name'update_tracking_id')]
  913.     public function updateTrackingIdAction(Request $request): Response
  914.     {
  915.         $distributorId $this->getUser()->getDistributor()->getId();
  916.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  917.         $tracking $this->em->getRepository(Tracking::class)->find((int)$request->request->get('tracking-id'));
  918.         $distributor->setTracking($tracking);
  919.         $this->em->persist($distributor);
  920.         $this->em->flush();
  921.         $response '<b><i class="fa-solid fa-circle-check"></i></i></b> Stock Tracking Method successfully saved.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  922.         return new JsonResponse($response);
  923.     }
  924.     #[Route('/distributors/download/inventory'name'download_inventory_csv')]
  925.     public function downloadInventoryAction(Request $request): Response
  926.     {
  927.         $distributorId $this->getUser()->getDistributor()->getId();
  928.         $distributorProducts $this->em->getRepository(DistributorProducts::class)->findBy([
  929.             'distributor' => $distributorId,
  930.         ]);
  931.         $fileName __DIR__ ."/../../public/csv/distributors/inventory-"$distributorId .".csv";
  932.         $fp fopen($fileName"w+");
  933.         $line = [
  934.             'ID#',
  935.             'Name',
  936.             'Dosage',
  937.             'Stock Level',
  938.             'Unit Price',
  939.         ];
  940.         fputcsv($fp$line',');
  941.         foreach ($distributorProducts as $distributorProduct)
  942.         {
  943.             $line = [
  944.                 $distributorProduct->getId(),
  945.                 $distributorProduct->getProduct()->getName(),
  946.                 $distributorProduct->getProduct()->getDosage(),
  947.                 $distributorProduct->getStockCount(),
  948.                 $distributorProduct->getUnitPrice(),
  949.             ];
  950.             fputcsv($fp$line',');
  951.         }
  952.         fclose($fp);
  953.         return $this->file($fileName);
  954.     }
  955.     #[Route('/distributors/upload/inventory'name'upload_inventory_csv')]
  956.     public function uploadInventoryAction(Request $request): Response
  957.     {
  958.         $distributorId $this->getUser()->getDistributor()->getId();
  959.         $filePath __DIR__ .'/../../public/csv/distributors/';
  960.         $fileName 'inventory-'$distributorId .'.csv';
  961.         $uploadedFile $_FILES['file'];
  962.         $fileType strtolower(pathinfo($filePath $fileName,PATHINFO_EXTENSION));
  963.         $i 0;
  964.         if($fileType == 'csv')
  965.         {
  966.             if(move_uploaded_file($uploadedFile['tmp_name'], $filePath $fileName))
  967.             {
  968.                 $process = new Process([
  969.                     __DIR__ '/../../bin/console',
  970.                     'app:update-inventory',
  971.                     14
  972.                 ]);
  973.                 $process->run();
  974.                 // executes after the command finishes
  975.                 if (!$process->isSuccessful()) {
  976.                     throw new ProcessFailedException($process);
  977.                 }
  978.             };
  979.         }
  980.         $response['flash'] = '<b><i class="fa-solid fa-circle-check"></i></i></b> Inventory Successfully saved.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  981.         return new JsonResponse($response);
  982.     }
  983.     #[Route('/distributors/get/company-information'name'get_company_information')]
  984.     public function getCompanyInformation(Request $request): Response
  985.     {
  986.         $distributorId $this->getUser()->getDistributor()->getId();
  987.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  988.         $countries $this->em->getRepository(Countries::class)->findAll();
  989.         $html $this->render('frontend/distributors/company_information.html.twig', [
  990.             'distributor' => $distributor,
  991.             'countries' => $countries,
  992.         ])->getContent();
  993.         return new JsonResponse($html);
  994.     }
  995.     #[Route('/distributors/get/about'name'get_about')]
  996.     public function getAbout(Request $request): Response
  997.     {
  998.         $distributorId $this->getUser()->getDistributor()->getId();
  999.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1000.         $html $this->render('frontend/distributors/about.html.twig', [
  1001.             'distributor' => $distributor,
  1002.         ])->getContent();
  1003.         return  new JsonResponse($html);
  1004.     }
  1005.     #[Route('/distributors/get/operating-hours'name'get_distributor_operating_hours')]
  1006.     public function getDistributorOperatingHours(Request $request): Response
  1007.     {
  1008.         $distributorId $this->getUser()->getDistributor()->getId();
  1009.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1010.         $html $this->render('frontend/distributors/operating_hours.html.twig', [
  1011.             'distributor' => $distributor,
  1012.         ])->getContent();
  1013.         return  new JsonResponse($html);
  1014.     }
  1015.     #[Route('/distributors/get/refund-policy'name'get_distributor_refund_policy')]
  1016.     public function getDistributorRefundPolicy(Request $request): Response
  1017.     {
  1018.         $distributorId $this->getUser()->getDistributor()->getId();
  1019.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1020.         $html $this->render('frontend/distributors/refund_policy.html.twig', [
  1021.             'distributor' => $distributor,
  1022.         ])->getContent();
  1023.         return  new JsonResponse($html);
  1024.     }
  1025.     #[Route('/distributors/get/sales-tax-policy'name'get_distributor_sales_tax_policy')]
  1026.     public function getDistributorSalesTaxPolicy(Request $request): Response
  1027.     {
  1028.         $distributorId $this->getUser()->getDistributor()->getId();
  1029.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1030.         $html $this->render('frontend/distributors/sales_tax_policy.html.twig', [
  1031.             'distributor' => $distributor,
  1032.         ])->getContent();
  1033.         return  new JsonResponse($html);
  1034.     }
  1035.     #[Route('/distributors/get/shipping-policy'name'get_distributor_shipping_policy')]
  1036.     public function getDistributorShippingPolicy(Request $request): Response
  1037.     {
  1038.         $distributorId $this->getUser()->getDistributor()->getId();
  1039.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1040.         $html $this->render('frontend/distributors/shipping_policy.htm.twig', [
  1041.             'distributor' => $distributor,
  1042.         ])->getContent();
  1043.         return  new JsonResponse($html);
  1044.     }
  1045.     public function generateInventoryXl($orderId$distributorId$status)
  1046.     {
  1047.         $distributor $this->em->getRepository(Distributors::class)->find($distributorId);
  1048.         $currency $distributor->getAddressCountry()->getCurrency();
  1049.         $orderItems $this->em->getRepository(OrderItems::class)->findByDistributorOrder(
  1050.             (int) $orderId,
  1051.             (int) $distributorId,
  1052.             $status
  1053.         );
  1054.         if(count($orderItems) == 0){
  1055.             return '';
  1056.         }
  1057.         $order $this->em->getRepository(Orders::class)->find($orderId);
  1058.         $billingAddress $this->em->getRepository(Addresses::class)->find($order->getBillingAddress());
  1059.         $shippingAddress $this->em->getRepository(Addresses::class)->find($order->getAddress());
  1060.         $orderStatus $this->em->getRepository(OrderStatus::class)->findOneBy([
  1061.             'orders' => $orderId,
  1062.             'distributor' => $distributorId
  1063.         ]);
  1064.         $sumTotal $this->em->getRepository(OrderItems::class)->findSumTotalOrderItems($orderId$distributorId);
  1065.         $order->setSubTotal($sumTotal[0]['totals']);
  1066.         $order->setTotal($sumTotal[0]['totals'] +  + $order->getDeliveryFee() + $order->getTax());
  1067.         $this->em->persist($order);
  1068.         $this->em->flush();
  1069.         $additionalNotes '';
  1070.         if($order->getNotes() != null){
  1071.             $additionalNotes '
  1072.             <div style="padding-top: 20px; padding-right: 30px; line-height: 30px">
  1073.                 <b>Additional Notes</b><br>
  1074.                 '$order->getNotes() .'
  1075.             </div>';
  1076.         }
  1077.         $address '';
  1078.         if($distributor->getAddressStreet() != null){
  1079.             $address .= $this->encryptor->decrypt($distributor->getAddressStreet()) .'<br>';
  1080.         }
  1081.         if($distributor->getAddressCity() != null){
  1082.             $address .= $this->encryptor->decrypt($distributor->getAddressCity()) .'<br>';
  1083.         }
  1084.         if($distributor->getAddressPostalCode() != null){
  1085.             $address .= $this->encryptor->decrypt($distributor->getAddressPostalCode()) .'<br>';
  1086.         }
  1087.         if($distributor->getAddressState() != null){
  1088.             $address .= $this->encryptor->decrypt($distributor->getAddressState()) .'<br>';
  1089.         }
  1090.         if($distributor->getAddressCountry() != null){
  1091.             $address .= $this->encryptor->decrypt($distributor->getAddressStreet()) .'<br>';
  1092.         }
  1093.         $snappy = new Pdf(__DIR__ .'/../../vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64');
  1094.         $html '
  1095.         <table style="width: 100%; border: none; border-collapse: collapse; font-size: 12px">
  1096.             <tr>
  1097.                 <td style=" line-height: 25px">
  1098.                     <img 
  1099.                         src="'__DIR__ .'/../../public/images/logos/'$distributor->getLogo() .'"
  1100.                         style="width:100%; max-width: 200px"
  1101.                     >
  1102.                     <br>
  1103.                     '$this->encryptor->decrypt($distributor->getDistributorName()) .'<br>
  1104.                     '$address .'
  1105.                     '$this->encryptor->decrypt($distributor->getTelephone()) .'<br>
  1106.                     '$this->encryptor->decrypt($distributor->getEmail()) .'
  1107.                 </td>
  1108.                 <td style="text-align: right">
  1109.                     <h1>PURCHASE ORDER</h1>
  1110.                     <table style="width: auto;margin-right: 0px;margin-left: auto; text-align: right;font-size: 12px">
  1111.                         <tr>
  1112.                             <td>
  1113.                                 DATE:
  1114.                             </td>
  1115.                             <td style="padding-left: 20px; line-height: 25px">
  1116.                                 'date('Y-m-d') .'
  1117.                             </td>
  1118.                         </tr>
  1119.                         <tr>
  1120.                             <td>
  1121.                                 PO#:
  1122.                             </td>
  1123.                             <td style="line-height: 25px">
  1124.                                 '$orderItems[0]->getPoNumber() .'
  1125.                             </td>
  1126.                         </tr>
  1127.                         <tr>
  1128.                             <td>
  1129.                                 Status:
  1130.                             </td>
  1131.                             <td style="line-height: 25px">
  1132.                                 '$status .'
  1133.                             </td>
  1134.                         </tr>  
  1135.                     </table>
  1136.                 </td>
  1137.             </tr>
  1138.             <tr>
  1139.                 <td colspan="2">
  1140.                     &nbsp;
  1141.                 </td>
  1142.             </tr>
  1143.             <tr>
  1144.                 <td style="width: 50%; vertical-align: top">
  1145.                     <table style="width: 80%; border-collapse: collapse;font-size: 12px">
  1146.                         <tr style="background: #54565a; color: #fff; border: solid 1px #54565a;">
  1147.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1148.                                 Vendor
  1149.                             </th>
  1150.                         </tr>
  1151.                         <tr>
  1152.                             <td style="padding-top: 10px; line-height: 25px">
  1153.                                 '$this->encryptor->decrypt($billingAddress->getClinicName()) .'<br>
  1154.                                 '$this->encryptor->decrypt($billingAddress->getAddress()) .'<br>
  1155.                                 '$this->encryptor->decrypt($billingAddress->getPostalCode()) .'<br>
  1156.                                 '$this->encryptor->decrypt($billingAddress->getCity()) .'<br>
  1157.                                 '$this->encryptor->decrypt($billingAddress->getState()) .'<br>
  1158.                             </td>
  1159.                         </tr>
  1160.                     </table>
  1161.                 </td>
  1162.                 <td style="width: 50%; vertical-align: top">
  1163.                     <table style="width: 80%; border-collapse: collapse; margin-left: auto;margin-right: 0; font-size: 12px">
  1164.                         <tr style="background: #54565a; color: #fff">
  1165.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1166.                                 Deliver To
  1167.                             </th>
  1168.                         </tr>
  1169.                         <tr>
  1170.                             <td style="padding-top: 10px; line-height: 25px">
  1171.                                 '$this->encryptor->decrypt($shippingAddress->getClinicName()) .'<br>
  1172.                                 '$this->encryptor->decrypt($shippingAddress->getAddress()) .'<br>
  1173.                                 '$this->encryptor->decrypt($shippingAddress->getPostalCode()) .'<br>
  1174.                                 '$this->encryptor->decrypt($shippingAddress->getCity()) .'<br>
  1175.                                 '$this->encryptor->decrypt($shippingAddress->getState()) .'<br>
  1176.                             </td>
  1177.                         </tr>
  1178.                     </table>
  1179.                 </td>
  1180.             </tr>
  1181.             <tr>
  1182.                 <td colspan="2">
  1183.                     &nbsp;
  1184.                 </td>
  1185.             </tr>
  1186.             <tr>
  1187.                 <td colspan="2">
  1188.                     <table style="width: 100%; border-collapse: collapse; font-size: 12px">
  1189.                         <tr style="background: #54565a; color: #fff">
  1190.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1191.                                 #SKU
  1192.                             </th>
  1193.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1194.                                 Description
  1195.                             </th>
  1196.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1197.                                 Qty
  1198.                             </th>
  1199.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1200.                                 Unit Priice
  1201.                             </th>
  1202.                             <th style="padding: 8px; border: solid 1px #54565a;">
  1203.                                 Total
  1204.                             </th>
  1205.                         </tr>';
  1206.         foreach($orderItems as $item) {
  1207.             $quantity $item->getQuantity();
  1208.             // Use quantity delivered once delivered
  1209.             if($orderStatus->getId() >= 7){
  1210.                 $quantity $item->getQuantityDelivered();
  1211.             }
  1212.             if ($item->getIsAccepted() == 1) {
  1213.                 $name $item->getName() . ': ';
  1214.                 $dosage $item->getProduct()->getDosage() . $item->getProduct()->getUnit() . ', ' $item->getProduct()->getSize() . ' Count';
  1215.                 if ($item->getProduct()->getForm() == 'Each') {
  1216.                     $dosage $item->getProduct()->getSize() . $item->getProduct()->getUnit();
  1217.                 }
  1218.                 $html .= '
  1219.                             <tr>
  1220.                                 <td style="padding: 8px; border: solid 1px #54565a;text-align: center">
  1221.                                     ' $item->getProduct()->getDistributorProducts()[0]->getSku() . '
  1222.                                 </td>
  1223.                                 <td style="padding: 8px; border: solid 1px #54565a;">
  1224.                                     ' $name $dosage '
  1225.                                 </td>
  1226.                                 <td style="padding: 8px; border: solid 1px #54565a;text-align: center">
  1227.                                     ' $quantity '
  1228.                                 </td>
  1229.                                 <td style="padding: 8px; border: solid 1px #54565a;text-align: right; padding-right: 8px; width: 10%">
  1230.                                     ' $currency .' 'number_format($item->getUnitPrice(), 2) . '
  1231.                                 </td>
  1232.                                 <td style="padding: 8px; border: solid 1px #54565a;text-align: right; padding-right: 8px; width: 10%">
  1233.                                     '$currency .' 'number_format($item->getTotal(), 2) . '
  1234.                                 </td>
  1235.                             </tr>';
  1236.             }
  1237.         }
  1238.         $html .= '
  1239.                         <tr>
  1240.                             <td colspan="3" rowspan="4" style="padding: 8px; padding-top: 16px; border: none;">
  1241.                                 '$additionalNotes .'
  1242.                             </td>
  1243.                             <td style="padding: 8px; padding-top: 16px; border: none;text-align: right">
  1244.                                 Subtotal
  1245.                             </td>
  1246.                             <td style="padding: 8px; padding-top: 16px;text-align: right; border: none">
  1247.                                 '$currency .' 'number_format($order->getSubTotal(),2) .'
  1248.                             </td>
  1249.                         </tr>';
  1250.         if($order->getDeliveryFee() > 0) {
  1251.             $html .= '
  1252.                             <tr>
  1253.                                 <td style="padding: 8px; border: none;text-align: right">
  1254.                                     Delivery
  1255.                                 </td>
  1256.                                 <td style="padding: 8px;text-align: right; border: none">
  1257.                                     ' $currency .' 'number_format($order->getDeliveryFee(), 2) . '
  1258.                                 </td>
  1259.                             </tr>';
  1260.         }
  1261.         if($order->getTax() > 0) {
  1262.             $html .= '
  1263.                             <tr>
  1264.                                 <td style="padding: 8px; border: none;text-align: right">
  1265.                                     Tax
  1266.                                 </td>
  1267.                                 <td style="padding: 8px; border:none; text-align: right">
  1268.                                     ' $currency .' 'number_format($order->getTax(), 2) . '
  1269.                                 </td>
  1270.                             </tr>';
  1271.         }
  1272.         $html .= '
  1273.                         <tr>
  1274.                             <td style="padding: 8px; border: none;text-align: right">
  1275.                                 <b>Total</b>
  1276.                             </td>
  1277.                             <td style="padding: 8px;text-align: right; border: none">
  1278.                                 <b>'$currency .' 'number_format($order->getTotal(),2) .'</b>
  1279.                             </td>
  1280.                         </tr>
  1281.                     </table>
  1282.                 </td>
  1283.             </tr>
  1284.         </table>';
  1285.         $file uniqid() .'.pdf';
  1286.         $snappy->generateFromHtml($html,'pdf/'$file,['page-size' => 'A4']);
  1287.         $orderStatus->setPoFile($file);
  1288.         $this->em->persist($orderStatus);
  1289.         $this->em->flush();
  1290.         return $orderStatus->getPoFile();
  1291.     }
  1292.     private function generatePassword()
  1293.     {
  1294.         $sets = [];
  1295.         $sets[] = 'abcdefghjkmnpqrstuvwxyz';
  1296.         $sets[] = 'ABCDEFGHJKMNPQRSTUVWXYZ';
  1297.         $sets[] = '23456789';
  1298.         $sets[] = '!@$%*?';
  1299.         $all '';
  1300.         $password '';
  1301.         foreach ($sets as $set) {
  1302.             $password .= $set[array_rand(str_split($set))];
  1303.             $all .= $set;
  1304.         }
  1305.         $all str_split($all);
  1306.         for ($i 0$i 16 count($sets); $i++) {
  1307.             $password .= $all[array_rand($all)];
  1308.         }
  1309.         $this->plainPassword str_shuffle($password);
  1310.         return $this->plainPassword;
  1311.     }
  1312.     public function createDistributorUserForm()
  1313.     {
  1314.         $distributorUsers = new DistributorUsers();
  1315.         return $this->createForm(DistributorUsersFormType::class, $distributorUsers);
  1316.     }
  1317.     public function getPagination($pageId$results$distributorId)
  1318.     {
  1319.         $currentPage = (int)$pageId;
  1320.         $lastPage $this->pageManager->lastPage($results);
  1321.         $pagination '
  1322.         <!-- Pagination -->
  1323.         <div class="row mt-3">
  1324.             <div class="col-12">';
  1325.         if ($lastPage 1) {
  1326.             $previousPageNo $currentPage 1;
  1327.             $url '/distributors/users';
  1328.             $previousPage $url $previousPageNo;
  1329.             $pagination .= '
  1330.             <nav class="custom-pagination">
  1331.                 <ul class="pagination justify-content-center">
  1332.             ';
  1333.             $disabled 'disabled';
  1334.             $dataDisabled 'true';
  1335.             // Previous Link
  1336.             if ($currentPage 1) {
  1337.                 $disabled '';
  1338.                 $dataDisabled 'false';
  1339.             }
  1340.             
  1341.             $pagination .= '
  1342.             <li class="page-item ' $disabled '">
  1343.                 <a 
  1344.                     class="user-pagination" 
  1345.                     aria-disabled="' $dataDisabled '" 
  1346.                     data-page-id="' $currentPage '" 
  1347.                     data-distributor-id="' $distributorId '"
  1348.                     href="' $previousPage '"
  1349.                 >
  1350.                     <span aria-hidden="true">&laquo;</span> <span class="d-none d-sm-inline">Previous</span>
  1351.                 </a>
  1352.             </li>';
  1353.             for ($i 1$i <= $lastPage$i++) {
  1354.                 $active '';
  1355.                 if ($i == (int)$currentPage) {
  1356.                     $active 'active';
  1357.                     $pageId '<input type="hidden" id="page_no" value="' $currentPage '">';
  1358.                 }
  1359.                 $pagination .= '
  1360.                 <li class="page-item ' $active '">
  1361.                     <a 
  1362.                         class="user-pagination" 
  1363.                         data-page-id="' $i '" 
  1364.                         href="' $url '"
  1365.                         data-distributor-id="' $distributorId '"
  1366.                     >' $i '</a>
  1367.                 </li>';
  1368.             }
  1369.             $disabled 'disabled';
  1370.             $dataDisabled 'true';
  1371.             if ($currentPage $lastPage) {
  1372.                 $disabled '';
  1373.                 $dataDisabled 'false';
  1374.             }
  1375.             $pagination .= '
  1376.             <li class="page-item ' $disabled '">
  1377.                 <a 
  1378.                     class="user-pagination" 
  1379.                     aria-disabled="' $dataDisabled '" 
  1380.                     data-page-id="' $currentPage '" 
  1381.                     href="' $url '"
  1382.                     data-distributor-id="' $distributorId '"
  1383.                 >
  1384.                     <span class="d-none d-sm-inline">Next</span> <span aria-hidden="true">&raquo;</span>
  1385.                 </a>
  1386.             </li>';
  1387.             $pagination .= '
  1388.                     </ul>
  1389.                 </nav>';
  1390.         }
  1391.         $pagination .= '
  1392.             </div>
  1393.         </div>';
  1394.         return $pagination;
  1395.     }
  1396. }