src/Controller/DistributorsController.php line 75

  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Addresses;
  4. use App\Entity\AiProducts;
  5. use App\Entity\AiProductsSpecies;
  6. use App\Entity\Api;
  7. use App\Entity\ApiDetails;
  8. use App\Entity\AvailabilityTracker;
  9. use App\Entity\Clinics;
  10. use App\Entity\ClinicUsers;
  11. use App\Entity\Countries;
  12. use App\Entity\CronJob;
  13. use App\Entity\DistributorProducts;
  14. use App\Entity\Distributors;
  15. use App\Entity\DistributorUserPermissions;
  16. use App\Entity\DistributorUsers;
  17. use App\Entity\Notifications;
  18. use App\Entity\Products;
  19. use App\Entity\RefreshTokens;
  20. use App\Entity\RestrictedDomains;
  21. use App\Entity\ScraperUrls;
  22. use App\Entity\Tracking;
  23. use App\Entity\UserPermissions;
  24. use App\Form\AddressesFormType;
  25. use App\Form\DistributorFormType;
  26. use App\Form\DistributorUsersFormType;
  27. use App\Services\PaginationManager;
  28. use Doctrine\ORM\EntityManagerInterface;
  29. use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
  30. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  31. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  32. use Symfony\Component\HttpFoundation\JsonResponse;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\HttpFoundation\RequestStack;
  35. use Symfony\Component\HttpFoundation\Response;
  36. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  37. use Symfony\Component\Mailer\MailerInterface;
  38. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  39. use Symfony\Component\Routing\Annotation\Route;
  40. use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
  41. class DistributorsController extends AbstractController
  42. {
  43. private $em;
  44. const ITEMS_PER_PAGE = 10;
  45. private $pageManager;
  46. private $requestStack;
  47. private $plainPassword;
  48. private $encryptor;
  49. private $mailer;
  50. public function __construct(EntityManagerInterface $em, PaginationManager $pagination, RequestStack $requestStack, Encryptor $encryptor, MailerInterface $mailer)
  51. {
  52. $this->em = $em;
  53. $this->pageManager = $pagination;
  54. $this->requestStack = $requestStack;
  55. $this->encryptor = $encryptor;
  56. $this->mailer = $mailer;
  57. }
  58. #[Route('/distributors/dashboard', name: 'distributor_dashboard')]
  59. #[Route('/distributors/account', name: 'distributor_account')]
  60. #[Route('/distributors/about', name: 'distributor_about')]
  61. #[Route('/distributors/operating-hours', name: 'distributor_operating_hours')]
  62. #[Route('/distributors/refund-policy', name: 'distributor_refund_policy')]
  63. #[Route('/distributors/sales-tax-policy', name: 'distributor_sales_tax_policy')]
  64. #[Route('/distributors/shipping-policy', name: 'distributor_shipping_policy')]
  65. #[Route('/distributors/manage-inventory', name: 'distributor_manage_inventory')]
  66. #[Route('/distributors/users', name: 'distributor_get_users')]
  67. #[Route('/distributors/order/{order_id}', name: 'distributor_order')]
  68. #[Route('/distributors/orders/{distributor_id}', name: 'distributor_order_list')]
  69. #[Route('/distributors/customers/1', name: 'distributor_customer_list')]
  70. #[Route('/distributors/inventory/list', name: 'distributor_inventory_list')]
  71. public function distributorDashboardAction(Request $request): Response
  72. {
  73. if($this->getUser()->getUserIdentifier() == null){
  74. $this->addFlash('danger', 'Your session expired due to inactivity, please login.');
  75. return $this->redirectToRoute('distributor_login');
  76. }
  77. $distributor = $this->getUser()->getDistributor();
  78. $user = $this->getUser();
  79. $username = $distributor->getDistributorName();
  80. $permissions = [];
  81. foreach($user->getDistributorUserPermissions() as $permission){
  82. $permissions[] = $permission->getPermission()->getId();
  83. }
  84. return $this->render('frontend/distributors/index.html.twig',[
  85. 'distributor' => $distributor,
  86. 'permissions' => json_encode($permissions),
  87. 'username' => $username,
  88. ]);
  89. }
  90. #[Route('/distributors/register', name: 'distributor_reg')]
  91. public function distributorReg(Request $request): Response
  92. {
  93. $countries = $this->em->getRepository(Countries::class)->findBy([
  94. 'isActive' => 1,
  95. ]);
  96. $form = $this->createRegisterForm();
  97. return $this->render('frontend/distributors/register.html.twig', [
  98. 'form' => $form->createView(),
  99. 'countries' => $countries
  100. ]);
  101. }
  102. #[Route('/sellers', name: 'sellers_page')]
  103. public function sellersAction(Request $request): Response
  104. {
  105. $sellers = $this->em->getRepository(Distributors::class)->findBy([
  106. 'isApproved' => true,
  107. ]);
  108. return $this->render('frontend/sellers.html.twig', [
  109. 'sellers' => $sellers,
  110. ]);
  111. }
  112. protected function createRegisterForm()
  113. {
  114. $distributors = new Distributors();
  115. return $this->createForm(DistributorFormType::class, $distributors);
  116. }
  117. #[Route('/distributors/register/check-email', name: 'distributor_check_email')]
  118. public function distributorsCheckEmailAction(Request $request): Response
  119. {
  120. $email = $request->request->get('email');
  121. $domainName = explode('@', $email);
  122. $response['response'] = true;
  123. $firstName = '';
  124. $restrictedDomains = $this->em->getRepository(RestrictedDomains::class)->arrayFindAll();
  125. foreach($restrictedDomains as $restrictedDomain)
  126. {
  127. if(md5($domainName[1]) == md5($restrictedDomain->getName()))
  128. {
  129. $response['response'] = false;
  130. $response['restricted'] = true;
  131. return new JsonResponse($response);
  132. }
  133. }
  134. $distributor = $this->em->getRepository(Distributors::class)->findOneBy([
  135. 'hashedEmail' => md5($email),
  136. ]);
  137. $distributorDomain = $this->em->getRepository(Distributors::class)->findOneBy([
  138. 'domainName' => md5($domainName[1]),
  139. ]);
  140. $distributorUsers = $this->em->getRepository(DistributorUsers::class)->findOneBy([
  141. 'hashedEmail' => md5($email),
  142. ]);
  143. $clinic = $this->em->getRepository(Clinics::class)->findOneBy([
  144. 'hashedEmail' => md5($email),
  145. ]);
  146. $clinicDomain = $this->em->getRepository(Clinics::class)->findOneBy([
  147. 'domainName' => md5($domainName[1]),
  148. ]);
  149. $clinicUsers = $this->em->getRepository(ClinicUsers::class)->findOneBy([
  150. 'hashedEmail' => md5($email),
  151. ]);
  152. if($clinicDomain != null)
  153. {
  154. $user = $this->em->getRepository(ClinicUsers::class)->findOneBy([
  155. 'clinic' => $clinicDomain->getId(),
  156. 'isPrimary' => 1
  157. ]);
  158. $firstName = $this->encryptor->decrypt($user->getFirstName());
  159. }
  160. if($distributorDomain != null)
  161. {
  162. $user = $this->em->getRepository(DistributorUsers::class)->findOneBy([
  163. 'distributor' => $distributorDomain->getId(),
  164. 'isPrimary' => 1
  165. ]);
  166. $firstName = $this->encryptor->decrypt($user->getFirstName());
  167. }
  168. $response['firstName'] = $firstName;
  169. if($distributor != null || $distributorUsers != null || $clinic != null || $clinicUsers != null || $clinicDomain != null || $distributorDomain != null)
  170. {
  171. $response['response'] = false;
  172. $response['restricted'] = false;
  173. }
  174. return new JsonResponse($response);
  175. }
  176. #[Route('/distributor/addresses', name: 'distributor_addresses')]
  177. public function createDistributorAddressesForm()
  178. {
  179. $addresses = new Addresses();
  180. return $this->createForm(AddressesFormType::class, $addresses);
  181. }
  182. #[Route('/distributor/register/create', name: 'distributor_create')]
  183. public function distributorCreateAction(Request $request, UserPasswordHasherInterface $passwordHasher, MailerInterface $mailer): Response
  184. {
  185. $data = $request->request;
  186. $distributor = $this->em->getRepository(Distributors::class)->findOneBy(['email' => $data->get('email')]);
  187. $countries = $this->em->getRepository(Countries::class)->find($data->get('country'));
  188. $tracking = $this->em->getRepository(Tracking::class)->find(3);
  189. if($distributor == null) {
  190. $distributors = new Distributors();
  191. $plainTextPwd = $this->generatePassword();
  192. if (!empty($plainTextPwd)) {
  193. $domainName = explode('@', $data->get('email'));
  194. $distributors->setDistributorName($this->encryptor->encrypt($data->get('distributor-name')));
  195. $distributors->setName($data->get('distributor-name'));
  196. $distributors->setEmail($this->encryptor->encrypt($data->get('email')));
  197. $distributors->setHashedEmail(md5($data->get('email')));
  198. $distributors->setDomainName(md5($domainName[1]));
  199. $distributors->setTelephone($this->encryptor->encrypt($data->get('telephone')));
  200. $distributors->setIntlCode($this->encryptor->encrypt($data->get('intl-code')));
  201. $distributors->setIsoCode($this->encryptor->encrypt($data->get('iso-code')));
  202. $distributors->setAddressCountry($countries);
  203. $distributors->setTracking($tracking);
  204. $distributors->setIsApproved(0);
  205. $this->em->persist($distributors);
  206. $this->em->flush();
  207. // Create user
  208. $distributor = $this->em->getRepository(Distributors::class)->findOneBy([
  209. 'hashedEmail' => md5($data->get('email')),
  210. ]);
  211. $distributorUsers = new DistributorUsers();
  212. $hashed_pwd = $passwordHasher->hashPassword($distributorUsers, $plainTextPwd);
  213. $distributorUsers->setDistributor($distributor);
  214. $distributorUsers->setFirstName($this->encryptor->encrypt($data->get('first-name')));
  215. $distributorUsers->setLastName($this->encryptor->encrypt($data->get('last-name')));
  216. $distributorUsers->setPosition($this->encryptor->encrypt($data->get('position')));
  217. $distributorUsers->setEmail($this->encryptor->encrypt($data->get('email')));
  218. $distributorUsers->setHashedEmail(md5($data->get('email')));
  219. $distributorUsers->setTelephone($this->encryptor->encrypt($data->get('telephone')));
  220. $distributorUsers->setRoles(['ROLE_DISTRIBUTOR']);
  221. $distributorUsers->setPassword($hashed_pwd);
  222. $distributorUsers->setIsPrimary(1);
  223. $this->em->persist($distributorUsers);
  224. $this->em->flush();
  225. // Assign User Permissions
  226. $userPermissions = $this->em->getRepository(UserPermissions::class)->findBy([
  227. 'isDistributor' => 1,
  228. ]);
  229. foreach($userPermissions as $userPermission){
  230. $distributorUserPermissions = new DistributorUserPermissions();
  231. $distributorUserPermissions->setUser($distributorUsers);
  232. $distributorUserPermissions->setDistributor($distributors);
  233. $distributorUserPermissions->setPermission($userPermission);
  234. $this->em->persist($distributorUserPermissions);
  235. }
  236. $this->em->flush();
  237. // Send Email
  238. $body = '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  239. $body .= '<tr><td colspan="2">Hi '. $data->get('first_name') .',</td></tr>';
  240. $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  241. $body .= '<tr><td colspan="2">Please use the credentials below login to the Fluid Backend.</td></tr>';
  242. $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  243. $body .= '<tr>';
  244. $body .= ' <td><b>URL: </b></td>';
  245. $body .= ' <td><a href="https://'. $_SERVER['HTTP_HOST'] .'/distributors/login">https://'. $_SERVER['HTTP_HOST'] .'/distributor/login</a></td>';
  246. $body .= '</tr>';
  247. $body .= '<tr>';
  248. $body .= ' <td><b>Username: </b></td>';
  249. $body .= ' <td>'. $data->get('email') .'</td>';
  250. $body .= '</tr>';
  251. $body .= '<tr>';
  252. $body .= ' <td><b>Password: </b></td>';
  253. $body .= ' <td>'. $plainTextPwd .'</td>';
  254. $body .= '</tr>';
  255. $body .= '</table>';
  256. $subject = 'Fluid Login Credentials';
  257. $to = $data->get('email');
  258. exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($body) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');
  259. }
  260. $response = '
  261. <div class="row pt-3">
  262. <div class="col-12 text-center mt-1 pt-3 pb-3" id="order_header">
  263. <h4 class="text-primary">Let\'s Create Your Account.</h4>
  264. <span class="text-primary">
  265. Your Fluid account was successfully created, an email with your login credentials has been sent to your inbox.
  266. </span>
  267. </div>';
  268. } else {
  269. $response = false;
  270. }
  271. return new JsonResponse($response);
  272. }
  273. #[Route('/distributors/get/company-information', name: 'get_company_information')]
  274. public function getCompanyInformation(Request $request): Response
  275. {
  276. $distributorId = $this->getUser()->getDistributor()->getId();
  277. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  278. $countries = $this->em->getRepository(Countries::class)->findAll();
  279. $html = $this->render('frontend/distributors/company_information.html.twig', [
  280. 'distributor' => $distributor,
  281. 'countries' => $countries,
  282. ])->getContent();
  283. return new JsonResponse($html);
  284. }
  285. private function generatePassword(): string
  286. {
  287. $curl = curl_init();
  288. curl_setopt_array($curl, array(
  289. CURLOPT_URL => 'https://www.dinopass.com/password/simple',
  290. CURLOPT_RETURNTRANSFER => true,
  291. CURLOPT_ENCODING => '',
  292. CURLOPT_MAXREDIRS => 10,
  293. CURLOPT_TIMEOUT => 0,
  294. CURLOPT_FOLLOWLOCATION => true,
  295. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  296. CURLOPT_CUSTOMREQUEST => 'GET',
  297. ));
  298. $response = curl_exec($curl);
  299. curl_close($curl);
  300. $this->plainPassword = $response;
  301. return $this->plainPassword;
  302. }
  303. public function createDistributorUserForm()
  304. {
  305. $distributorUsers = new DistributorUsers();
  306. return $this->createForm(DistributorUsersFormType::class, $distributorUsers);
  307. }
  308. #[Route('/distributors/update/company-information', name: 'distributor_update_company_information')]
  309. public function distributorUpdateCompanyInformationAction(Request $request): Response
  310. {
  311. $data = $request->request->all('distributor_form');
  312. $distributor = $this->getUser()->getDistributor();
  313. $countryId = (int) $data['addressCountry'];
  314. $logo = '';
  315. $country = $this->em->getRepository(Countries::class)->find($countryId);
  316. $isApproved = (bool) $distributor->getIsApproved() ?? false;
  317. $tradeLicense = $_FILES['distributor_form']['name']['trade-license-file'];
  318. $tradeLicenseNo = $data['trade-license-no'];
  319. $tradeLicenseExpDate = $data['trade-license-exp-date'];
  320. // Account approval required if reg docs change
  321. if(
  322. !empty($tradeLicense) || $tradeLicenseNo != $this->encryptor->decrypt($distributor->getTradeLicenseNo()) ||
  323. $tradeLicenseExpDate != $distributor->getTradeLicenseExpDate()->format('Y-m-d')
  324. )
  325. {
  326. $distributor->setIsApproved(0);
  327. $isApproved = false;
  328. }
  329. if($distributor != null)
  330. {
  331. $domainName = explode('@', $data['email']);
  332. $distributor->setDistributorName($this->encryptor->encrypt($data['distributor-name']));
  333. $distributor->setName($data['distributor-name']);
  334. $distributor->setTelephone($this->encryptor->encrypt($data['telephone']));
  335. $distributor->setEmail($this->encryptor->encrypt($data['email']));
  336. $distributor->setWebsite($this->encryptor->encrypt($data['website']));
  337. $distributor->setDomainName(md5($domainName[1]));
  338. $distributor->setAddressCountry($country);
  339. $distributor->setAddressStreet($this->encryptor->encrypt($data['address-street']));
  340. $distributor->setAddressCity($this->encryptor->encrypt($data['address-city']));
  341. $distributor->setAddressPostalCode($this->encryptor->encrypt($data['address-postal-code']));
  342. $distributor->setAddressState($this->encryptor->encrypt($data['address-state']));
  343. $distributor->setIsoCode($this->encryptor->encrypt($data['iso-code']));
  344. $distributor->setIntlCode($this->encryptor->encrypt($data['intl-code']));
  345. $distributor->setManagerFirstName($this->encryptor->encrypt($data['manager-first-name']));
  346. $distributor->setManagerLastName($this->encryptor->encrypt($data['manager-last-name']));
  347. $distributor->setManagerIdNo($this->encryptor->encrypt($data['manager-id-no']));
  348. $distributor->setManagerIdExpDate(new \DateTime($data['manager-id-exp-date']));
  349. $distributor->setTradeLicenseNo($this->encryptor->encrypt($data['trade-license-no']));
  350. $distributor->setTradeLicenseExpDate(new \DateTime($data['trade-license-exp-date']));
  351. if(!empty($_FILES['distributor_form']['name']['trade-license-file']))
  352. {
  353. $extension = pathinfo($_FILES['distributor_form']['name']['trade-license-file'], PATHINFO_EXTENSION);
  354. $file = $distributor->getId() . '-' . uniqid() . '.' . $extension;
  355. $targetFile = __DIR__ . '/../../public/documents/' . $file;
  356. if(move_uploaded_file($_FILES['distributor_form']['tmp_name']['trade-license-file'], $targetFile))
  357. {
  358. $distributor->setTradeLicense($file);
  359. }
  360. }
  361. if(!empty($_FILES['distributor_form']['name']['logo']))
  362. {
  363. $extension = pathinfo($_FILES['distributor_form']['name']['logo'], PATHINFO_EXTENSION);
  364. $file = $distributor->getId() . '-' . uniqid() . '.' . $extension;
  365. $targetFile = __DIR__ . '/../../public/images/logos/' . $file;
  366. if (move_uploaded_file($_FILES['distributor_form']['tmp_name']['logo'], $targetFile))
  367. {
  368. $distributor->setLogo($file);
  369. $logo = $file;
  370. }
  371. }
  372. $this->em->persist($distributor);
  373. $this->em->flush();
  374. // Send Approval Email
  375. if(!$isApproved)
  376. {
  377. $orderUrl = $this->getParameter('app.base_url') . '/admin/distributor/'. $distributor->getId();
  378. $html = '<p>Please <a href="'. $orderUrl .'">click here</a> to view the distributors details.</p><br>';
  379. $html = $this->forward('App\Controller\ResetPasswordController::emailFooter', [
  380. 'html' => $html,
  381. ]);
  382. $subject = 'Fluid - Account Approval Request';
  383. $to = $this->getParameter('app.email_admin');
  384. exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($html) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');
  385. }
  386. $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>';
  387. }
  388. else
  389. {
  390. $message = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  391. }
  392. $response = [
  393. 'message' => $message,
  394. 'logo' => $logo,
  395. ];
  396. return new JsonResponse($response);
  397. }
  398. #[Route('/distributors/download/trade-license/{tradeLicense}', name: 'distributors_download_trade_license')]
  399. public function distributorDownloadTradeLicenseAction(Request $request)
  400. {
  401. $path = __DIR__ . '/../../public/documents/';
  402. $tradeLicense = $path . $request->get('tradeLicense');
  403. $response = new BinaryFileResponse($tradeLicense);
  404. $response->setContentDisposition(
  405. ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  406. basename($tradeLicense)
  407. );
  408. return $response;
  409. }
  410. #[Route('/distributors/update/about_us', name: 'distributor_update_about_us')]
  411. public function distributorUpdateAboutUsAction(Request $request): Response
  412. {
  413. $data = $request->request;
  414. $distributor = $this->getUser()->getDistributor();
  415. if($distributor != null)
  416. {
  417. $about = $data->get('about-us');
  418. if(!empty($about))
  419. {
  420. $distributor->setAbout($about);
  421. $this->em->persist($distributor);
  422. $this->em->flush();
  423. }
  424. $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>';
  425. }
  426. else
  427. {
  428. $response = '<b><i class="fas fa-check-circle"></i> An error occurred.';
  429. }
  430. return new JsonResponse($response);
  431. }
  432. #[Route('/distributors/update/operating_hours', name: 'distributor_update_operating_hours')]
  433. public function distributorUpdateOperatingHoursAction(Request $request): Response
  434. {
  435. $data = $request->request;
  436. $distributor = $this->getUser()->getDistributor();
  437. if($distributor != null)
  438. {
  439. if(!empty($data->get('operating-hours')))
  440. {
  441. $distributor->setOperatingHours($data->get('operating-hours'));
  442. }
  443. $this->em->persist($distributor);
  444. $this->em->flush();
  445. $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>';
  446. }
  447. else
  448. {
  449. $response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  450. }
  451. return new JsonResponse($response);
  452. }
  453. #[Route('/distributors/update/refund_policy', name: 'distributor_update_refund_policy')]
  454. public function distributorUpdateRefundPolicyAction(Request $request): Response
  455. {
  456. $data = $request->request;
  457. $distributor = $this->getUser()->getDistributor();
  458. if($distributor != null)
  459. {
  460. if(!empty($data->get('refund-policy')))
  461. {
  462. $distributor->setRefundPolicy($data->get('refund-policy'));
  463. }
  464. $this->em->persist($distributor);
  465. $this->em->flush();
  466. $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>';
  467. }
  468. else
  469. {
  470. $response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  471. }
  472. return new JsonResponse($response);
  473. }
  474. #[Route('/distributors/update/sales_tax_policy', name: 'distributor_update_sales_tax_policy')]
  475. public function distributorUpdateSalesTaxPolicyAction(Request $request): Response
  476. {
  477. $data = $request->request;
  478. $distributor = $this->getUser()->getDistributor();
  479. if($distributor != null)
  480. {
  481. if(!empty($data->get('sales-tax-policy')))
  482. {
  483. $distributor->setSalesTaxPolicy($data->get('sales-tax-policy'));
  484. }
  485. $this->em->persist($distributor);
  486. $this->em->flush();
  487. $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>';
  488. }
  489. else
  490. {
  491. $response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  492. }
  493. return new JsonResponse($response);
  494. }
  495. #[Route('/distributors/update/shipping_policy', name: 'distributor_update_shipping_policy')]
  496. public function distributorUpdateShippingPolicyAction(Request $request): Response
  497. {
  498. $data = $request->request;
  499. $distributor = $this->getUser()->getDistributor();
  500. if($distributor != null)
  501. {
  502. if(!empty($data->get('shipping-policy')))
  503. {
  504. $distributor->setShippingPolicy($data->get('shipping-policy'));
  505. }
  506. $this->em->persist($distributor);
  507. $this->em->flush();
  508. $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>';
  509. }
  510. else
  511. {
  512. $response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';
  513. }
  514. return new JsonResponse($response);
  515. }
  516. #[Route('/distributors/get/about', name: 'get_about')]
  517. public function getAbout(Request $request): Response
  518. {
  519. $distributorId = $this->getUser()->getDistributor()->getId();
  520. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  521. $html = $this->render('frontend/distributors/about.html.twig', [
  522. 'distributor' => $distributor,
  523. ])->getContent();
  524. return new JsonResponse($html);
  525. }
  526. #[Route('/distributors/get/operating-hours', name: 'get_distributor_operating_hours')]
  527. public function getDistributorOperatingHours(Request $request): Response
  528. {
  529. $distributorId = $this->getUser()->getDistributor()->getId();
  530. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  531. $html = $this->render('frontend/distributors/operating_hours.html.twig', [
  532. 'distributor' => $distributor,
  533. ])->getContent();
  534. return new JsonResponse($html);
  535. }
  536. #[Route('/distributors/get/refund-policy', name: 'get_distributor_refund_policy')]
  537. public function getDistributorRefundPolicy(Request $request): Response
  538. {
  539. $distributorId = $this->getUser()->getDistributor()->getId();
  540. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  541. $html = $this->render('frontend/distributors/refund_policy.html.twig', [
  542. 'distributor' => $distributor,
  543. ])->getContent();
  544. return new JsonResponse($html);
  545. }
  546. #[Route('/distributors/get/sales-tax-policy', name: 'get_distributor_sales_tax_policy')]
  547. public function getDistributorSalesTaxPolicy(Request $request): Response
  548. {
  549. $distributorId = $this->getUser()->getDistributor()->getId();
  550. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  551. $html = $this->render('frontend/distributors/sales_tax_policy.html.twig', [
  552. 'distributor' => $distributor,
  553. ])->getContent();
  554. return new JsonResponse($html);
  555. }
  556. #[Route('/distributors/get/shipping-policy', name: 'get_distributor_shipping_policy')]
  557. public function getDistributorShippingPolicy(Request $request): Response
  558. {
  559. $distributorId = $this->getUser()->getDistributor()->getId();
  560. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  561. $html = $this->render('frontend/distributors/shipping_policy.htm.twig', [
  562. 'distributor' => $distributor,
  563. ])->getContent();
  564. return new JsonResponse($html);
  565. }
  566. #[Route('/distributors/inventory-search', name: 'distributor_inventory_search')]
  567. public function distributorInventorySearchAction(Request $request): Response
  568. {
  569. $products = $this->em->getRepository(Products::class)->findBySearch($request->get('keyword'));
  570. $select = '<ul id="product_list">';
  571. foreach($products as $product){
  572. $id = $product->getId();
  573. $name = $product->getName();
  574. $dosage = '';
  575. $size = '';
  576. if(!empty($product->getDosage())) {
  577. $unit = '';
  578. if(!empty($product->getUnit())) {
  579. $unit = $product->getUnit();
  580. }
  581. $dosage = ' | '. $product->getDosage() . $unit;
  582. }
  583. if(!empty($product->getSize())) {
  584. $size = ' | '. $product->getSize();
  585. }
  586. $select .= "
  587. <li
  588. class=\"search-item\"
  589. data-product-id=\"$id\"
  590. data-product-name=\"$name\"
  591. data-action='click->products--distributor-products#onclickEditIcon'
  592. >$name$dosage$size</li>
  593. ";
  594. }
  595. $select .= '</ul>';
  596. return new Response($select);
  597. }
  598. #[Route('/distributors/inventory-get', name: 'distributor_inventory_get')]
  599. public function distributorGetInventoryAction(Request $request,TokenStorageInterface $tokenStorage): Response
  600. {
  601. $productId = (int) $request->request->get('product-id');
  602. $products = $this->em->getRepository(Products::class)->find($productId);
  603. if($products != null)
  604. {
  605. $distributorId = $this->getUser()->getDistributor()->getId();
  606. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  607. $response = [];
  608. $response['html'] = json_decode($this->forward('App\Controller\DistributorProductsController::getDistributorProductAction')
  609. ->getContent());
  610. $distributorProduct = $this->em->getRepository(Distributors::class)
  611. ->getDistributorProduct($distributor->getId(), $productId);
  612. if($distributorProduct != null)
  613. {
  614. $response['distributor_id'] = $distributor->getId();
  615. $response['itemId'] = $distributorProduct[0]['distributorProducts'][0]['itemId'];
  616. $response['sku'] = $distributorProduct[0]['distributorProducts'][0]['sku'];
  617. $response['unit_price'] = $distributorProduct[0]['distributorProducts'][0]['unitPrice'];
  618. $response['stock_count'] = $distributorProduct[0]['distributorProducts'][0]['stockCount'];
  619. $response['expiry_date'] = '';
  620. $response['tax_exempt'] = $distributorProduct[0]['distributorProducts'][0]['taxExempt'];
  621. $response['product'] = $distributorProduct[0]['distributorProducts'][0]['product'];
  622. if($distributorProduct[0]['distributorProducts'][0]['expiryDate'] != null)
  623. {
  624. $response['expiry_date'] = $distributorProduct[0]['distributorProducts'][0]['expiryDate']->format('Y-m-d');
  625. }
  626. }
  627. else
  628. {
  629. $product = $this->em->getRepository(Products::class)->find($productId);
  630. $response['distributor_id'] = $distributor->getId();
  631. $response['sku'] = '';
  632. $response['distributor_no'] = '';
  633. $response['unit_price'] = '';
  634. $response['stock_count'] = '';
  635. $response['expiry_date'] = '';
  636. $response['tax_exempt'] = 0;
  637. $response['product'] = [
  638. 'dosage' => $product->getDosage(),
  639. 'size' => $product->getSize(),
  640. 'unit' => $product->getUnit(),
  641. 'activeIngredient' => $product->getActiveIngredient(),
  642. ];
  643. }
  644. }
  645. else
  646. {
  647. $response['message'] = 'Inventory item not found';
  648. }
  649. return new JsonResponse($response);
  650. }
  651. #[Route('/distributors/inventory-update', name: 'distributor_inventory_update')]
  652. public function distributorUpdateInventoryAction(Request $request, MailerInterface $mailer): Response
  653. {
  654. $data = $request->request->all('distributor_products_form');
  655. $product = $this->em->getRepository(Products::class)->find($data['product']);
  656. $distributor = $this->em->getRepository(Distributors::class)->find($data['distributor']);
  657. $distributorProducts = $this->em->getRepository(DistributorProducts::class)->findOneBy(
  658. [
  659. 'product' => $data['product'],
  660. 'distributor' => $data['distributor']
  661. ]
  662. );
  663. $tracking = false;
  664. $response['unitPrice'] = 0.00;
  665. $response['stockLevel'] = 0;
  666. if($distributorProducts == null){
  667. $distributorProducts = new DistributorProducts();
  668. } else {
  669. if($distributorProducts->getStockCount() == 0){
  670. $tracking = true;
  671. }
  672. }
  673. if(!empty($data['product']) && !empty($data['distributor'])){
  674. $trackingId = $distributor->getTracking()->getId();
  675. $distributorProducts->setDistributor($distributor);
  676. $distributorProducts->setProduct($product);
  677. $distributorProducts->setSku($data['sku']);
  678. $distributorProducts->setItemId($data['itemId']);
  679. $distributorProducts->setTaxExempt($data['taxExempt']);
  680. $distributorProducts->setIsActive(1);
  681. $taxExempt = 0;
  682. if(!empty($data['taxExempt'])){
  683. $taxExempt = $data['taxExempt'];
  684. }
  685. $distributorProducts->setTaxExempt($taxExempt);
  686. if($trackingId == 3)
  687. {
  688. $distributorProducts->setUnitPrice($data['unitPrice']);
  689. $distributorProducts->setStockCount((int)$data['stockCount']);
  690. }
  691. // Get stock and price from API
  692. if($trackingId == 1){
  693. // Retrieve price & stock from api
  694. $distributorId = $distributor->getId();
  695. $priceStockLevels = json_decode($this->forward('App\Controller\ProductsController::zohoRetrieveItem',[
  696. 'distributorId' => $distributorId,
  697. 'itemId' => $data['itemId'],
  698. ])->getContent(), true);
  699. $response['unitPrice'] = $priceStockLevels['unitPrice'] ?? 0.00;
  700. $response['stockLevel'] = $priceStockLevels['stockLevel'] ?? 0;
  701. $distributorProducts->setUnitPrice($response['unitPrice']);
  702. $distributorProducts->setStockCount($response['stockLevel']);
  703. }
  704. $this->em->persist($distributorProducts);
  705. $this->em->flush();
  706. // Update parent stock level
  707. $stockCount = $this->em->getRepository(DistributorProducts::class)->getProductStockCount($product->getId());
  708. $product->setStockCount($stockCount[0][1]);
  709. // Get the lowest price
  710. $lowestPrice = $this->em->getRepository(DistributorProducts::class)->getLowestPrice($product->getId());
  711. $product->setUnitPrice($lowestPrice[0]['unitPrice'] ?? 0.00);
  712. $this->em->persist($product);
  713. $this->em->flush();
  714. // Availability Tracker
  715. $availabilityTracker = '';
  716. if($tracking){
  717. $availabilityTracker = $this->em->getRepository(AvailabilityTracker::class)->findBy([
  718. 'product' => $product->getId(),
  719. 'distributor' => $data['distributor'],
  720. 'isSent' => 0,
  721. ]);
  722. foreach($availabilityTracker as $tracker){
  723. $methodId = $tracker->getCommunication()->getCommunicationMethod()->getId();
  724. $sendTo = $tracker->getCommunication()->getSendTo();
  725. $product = $tracker->getProduct();
  726. // In app notifications
  727. if($methodId == 1){
  728. $notifications = new Notifications();
  729. $notifications->setClinic($tracker->getClinic());
  730. $notifications->setIsRead(0);
  731. $notifications->setIsReadDistributor(0);
  732. $notifications->setIsActive(1);
  733. $notifications->setAvailabilityTracker($tracker);
  734. $this->em->persist($notifications);
  735. $this->em->flush();
  736. // Get the newly created notification
  737. $notification = '
  738. <table class="w-100">
  739. <tr>
  740. <td><span class="badge bg-success me-3">New Stock</span></td>
  741. <td>'. $product->getName() .' '. $product->getDosage() . $product->getUnit() .'</td>
  742. <td>
  743. <a href="#" class="delete-notification" data-notification-id="'. $notifications->getId() .'">
  744. <i class="fa-solid fa-xmark text-black-25 ms-3 float-end"></i>
  745. </a>
  746. </td>
  747. </tr>
  748. </table>';
  749. $notifications = $this->em->getRepository(Notifications::class)->find($notifications->getId());
  750. $notifications->setNotification($notification);
  751. $this->em->persist($notifications);
  752. $this->em->flush();
  753. // Email notifications
  754. } elseif($methodId == 2){
  755. $body = '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  756. $body .= '<tr><td colspan="2">'. $product->getName() .' '. $product->getDosage() . $product->getUnit() .' is back in stock</td></tr>';
  757. $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  758. $body .= '<tr>';
  759. $body .= ' <td><b>Distributor: </b></td>';
  760. $body .= ' <td>'. $tracker->getDistributor()->getDistributorName() .'</td>';
  761. $body .= '</tr>';
  762. $body .= '<tr>';
  763. $body .= ' <td><b>Stock Level: </b></td>';
  764. $body .= ' <td>'. $tracker->getProduct()->getDistributorProducts()[0]->getStockCount() .'</td>';
  765. $body .= '</tr>';
  766. $body .= '</table>';
  767. $subject = 'Fluid Stock Level Update';
  768. $to = $sendTo;
  769. exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($body) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');
  770. // Text notifications
  771. } elseif($methodId == 3){
  772. }
  773. $availabilityTracker = $this->em->getRepository(AvailabilityTracker::class)->find($tracker->getId());
  774. $availabilityTracker->setIsSent(1);
  775. $this->em->persist($availabilityTracker);
  776. $this->em->flush();
  777. }
  778. }
  779. $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>';
  780. } else {
  781. $response['flash'] = 'An error occurred';
  782. }
  783. return new JsonResponse($response);
  784. }
  785. #[Route('/distributors/get/refresh-token', name: 'distributor_get_access_token')]
  786. public function distributorGetRefreshTokenAction(Request $request): Response
  787. {
  788. $id = $this->getUser()->getDistributor()->getId();
  789. $button = false;
  790. $token = false;
  791. $error = false;
  792. if($id == null){
  793. return $this->render('security/login.html.twig', [
  794. 'last_username' => '',
  795. 'error' => '',
  796. 'csrf_token_intention' => 'authenticate',
  797. 'user_type' => 'distributors',
  798. ]);
  799. }
  800. $api = $this->em->getRepository(ApiDetails::class)->findOneBy([
  801. 'distributor' => $id,
  802. ]);
  803. // Check client id & secret exist
  804. if($api == null){
  805. $error = true;
  806. } else {
  807. $refreshTokens = $api->getRefreshTokens();
  808. if(count($refreshTokens) == 0){
  809. $button = true;
  810. } else {
  811. $token = true;
  812. }
  813. }
  814. return new JsonResponse([
  815. 'token' => $token,
  816. 'button' => $button,
  817. 'error' => $error
  818. ]);
  819. }
  820. #[Route('/distributors/zoho/set/refresh-token', name: 'zoho_set_refresh_token')]
  821. public function setZohoRefreshTokenAction(Request $request): Response
  822. {
  823. $distributorId = $this->getUser()->getDistributor()->getId();
  824. $apiDetails = $this->em->getRepository(ApiDetails::class)->findOneBy([
  825. 'distributor' => $distributorId,
  826. ]);
  827. $code = $request->query->get('code');
  828. $error = $request->query->get('error');
  829. if($code != null) {
  830. $curl = curl_init();
  831. $clientId = $this->encryptor->decrypt($apiDetails->getClientId());
  832. $clientSecret = $this->encryptor->decrypt($apiDetails->getClientSecret());
  833. $endpoint = 'https://accounts.zoho.com/oauth/v2/token?code=' . $code . '&client_id=' . $clientId . '&';
  834. $endpoint .= 'client_secret=' . $clientSecret . '&redirect_uri='. $this->getParameter('app.base_url') .'/distributors/zoho/set/refresh-token&';
  835. $endpoint .= 'grant_type=authorization_code';
  836. curl_setopt_array($curl, [
  837. CURLOPT_URL => $endpoint,
  838. CURLOPT_RETURNTRANSFER => true,
  839. CURLOPT_ENCODING => '',
  840. CURLOPT_MAXREDIRS => 10,
  841. CURLOPT_TIMEOUT => 0,
  842. CURLOPT_FOLLOWLOCATION => true,
  843. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  844. CURLOPT_CUSTOMREQUEST => 'POST'
  845. ]);
  846. $json = curl_exec($curl);
  847. curl_close($curl);
  848. $response = json_decode($json, true);
  849. if(array_key_exists('refresh_token', $response)){
  850. $session = $this->requestStack->getSession();
  851. $session->set('accessToken', $response['access_token']);
  852. $session->set('refreshToken', $response['refresh_token']);
  853. $refreshToken = new RefreshTokens();
  854. $api = $this->getUser()->getDistributor()->getApiDetails();
  855. $refreshToken->setToken($response['refresh_token']);
  856. $refreshToken->setApiDetails($api);
  857. $this->em->persist($refreshToken);
  858. $this->em->flush();
  859. return $this->redirectToRoute('distributor_manage_inventory');
  860. } elseif(array_key_exists('error', $response)){
  861. echo $response['error'];
  862. }
  863. } elseif($error != null){
  864. echo $error;
  865. file_put_contents(__DIR__ . '/../../public/zoho.log', date('Y-m-d H:i:s') .': '. $error . "\n", FILE_APPEND);
  866. }
  867. return new JsonResponse('');
  868. }
  869. #[Route('/admin/get/distributors/list', name: 'admin_get_distributors_list')]
  870. public function adminGetDistributorsList(Request $request): Response
  871. {
  872. $status = (int) $request->request->get('status');
  873. $distributors = $this->em->getRepository(Distributors::class)->adminFindAll($status);
  874. $results = $this->pageManager->paginate($distributors[0], $request, self::ITEMS_PER_PAGE);
  875. $dataAction = 'data-action="click->admin--distributors#onClickGetList"';
  876. $pagination = $this->getPagination($request->get('page_id'), $results, $dataAction, self::ITEMS_PER_PAGE);
  877. $response = $this->render('Admin/distributors/distributors_list.html.twig', [
  878. 'distributors' => $results,
  879. 'pagination' => $pagination,
  880. ])->getContent();
  881. return new JsonResponse($response);
  882. }
  883. #[Route('/admin/get/distributor/form', name: 'admin_get_distributor_form')]
  884. public function adminGetDistributorForm(Request $request): Response
  885. {
  886. $distributorId = $request->request->get('distributor-id') ?? 0;
  887. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  888. $distributorUsers = $this->em->getRepository(DistributorUsers::class)->findBy([
  889. 'distributor' => $distributorId
  890. ]);
  891. $userPermissions = $this->em->getRepository(UserPermissions::class)->findBy([
  892. 'isDistributor' => 1
  893. ]);
  894. $api = $this->em->getRepository(Api::class)->findAll();
  895. $countries = $this->em->getRepository(Countries::class)->findBy([
  896. 'isActive' => true,
  897. ]);
  898. $distributorProducts = $this->getDistributorInventory(1, $distributorId, 0, 0, $request);
  899. $response = $this->render('Admin/distributors/distributors.html.twig', [
  900. 'distributor' => $distributor,
  901. 'distributorUsers' => $distributorUsers,
  902. 'userPermissions' => $userPermissions,
  903. 'api' => $api,
  904. 'countries' => $countries,
  905. 'distributorProducts' => $distributorProducts,
  906. ])->getContent();
  907. return new JsonResponse($response);
  908. }
  909. #[Route('/admin/approve/distributor', name: 'admin_approve_distributor')]
  910. public function adminApproveDistributor(Request $request): Response
  911. {
  912. $distributorId = $request->request->get('distributor-id');
  913. $isApproved = $request->request->get('is-approved');
  914. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  915. if($distributor != null)
  916. {
  917. if($isApproved == 1 || $isApproved == 0)
  918. {
  919. $isApproved = 2;
  920. }
  921. else if($isApproved == 2)
  922. {
  923. $isApproved = 1;
  924. }
  925. $distributor->setIsApproved($isApproved);
  926. $this->em->persist($distributor);
  927. $this->em->flush();
  928. }
  929. return new JsonResponse('');
  930. }
  931. #[Route('/admin/get-distributor-products', name: 'admin_get_distributor_products')]
  932. public function distributorInventory(Request $request): Response
  933. {
  934. $pageId = $request->request->get('page-id');
  935. $distributorId = $request->request->get('distributor-id');
  936. $manufacturerId = $request->request->get('manufacturer-id');
  937. $speciesId = $request->request->get('species-id');
  938. $response = $this->getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request);
  939. return new JsonResponse($response);
  940. }
  941. #[Route('/admin/save-scraper-frequency', name: 'admin_save_scraper_frequency')]
  942. public function saveScraperFrequency(Request $request): Response
  943. {
  944. $name = $request->request->get('name');
  945. $cron = $request->request->get('cron');
  946. $status = (int) $request->request->get('status');
  947. $scraperUrlId = $request->request->get('scraper-url-id');
  948. $frequency = $request->request->get('frequency');
  949. $scraperUrl = $this->em->getRepository(ScraperUrls::class)->find($scraperUrlId);
  950. if($scraperUrl == null)
  951. {
  952. $response = [
  953. 'flash' => 'Please first save the scraper url.',
  954. 'type' => 'danger'
  955. ];
  956. return new JsonResponse($response);
  957. }
  958. $cronJob = $this->em->getRepository(CronJob::class)->findOneBy([
  959. 'scraperUrl' => $scraperUrl->getId(),
  960. ]);
  961. if($cronJob == null)
  962. {
  963. $cronJob = new CronJob();
  964. }
  965. $cronJob->setName($name);
  966. $cronJob->setExpression($cron);
  967. $cronJob->setCommand($scraperUrl->getDistributor()->getScraperAunthentication()->getCommand());
  968. $cronJob->setActive($status);
  969. $cronJob->setScraperUrl($scraperUrl);
  970. $cronJob->setFrequency($frequency);
  971. $cronJob->setDescription($this->getCronDescription($cron, $frequency));
  972. $this->em->persist($cronJob);
  973. $this->em->flush();
  974. $response = [
  975. 'flash' => 'Schedule saved successfully.',
  976. 'type' => 'success'
  977. ];
  978. return new JsonResponse($response);
  979. }
  980. #[Route('/admin/run-scraper', name: 'admin_run_scraper')]
  981. public function runScraper(Request $request): Response
  982. {
  983. $command = $request->request->get('command');
  984. $argument = $request->request->get('argument');
  985. $email = $this->encryptor->decrypt($this->getUser()->getEmail());
  986. exec(__DIR__ . "/../../bin/console $command $argument $email > /dev/null 2>&1 &");
  987. $response = [
  988. 'flash' => 'Scraper successfully started.',
  989. 'type' => 'success'
  990. ];
  991. return new JsonResponse($response);
  992. }
  993. public function getCronDescription($cron, $frequency): string
  994. {
  995. $description = '';
  996. // Daily
  997. if(strtolower($frequency) == 'daily')
  998. {
  999. $pieces = explode(' ', $cron);
  1000. $hour = $pieces[1];
  1001. $timeOfDay = 'pm';
  1002. if($hour >= 0 and $hour < 12)
  1003. {
  1004. $timeOfDay = 'am';
  1005. }
  1006. $description = 'Every day at '. $hour . $timeOfDay;
  1007. }
  1008. // Weekly
  1009. if(strtolower($frequency) == 'weekly')
  1010. {
  1011. $pieces = explode(' ', $cron);
  1012. $hour = $pieces[1];
  1013. $day = (int) $pieces[4];
  1014. $timeOfDay = 'pm';
  1015. if($hour >= 0 and $hour < 12)
  1016. {
  1017. $timeOfDay = 'am';
  1018. }
  1019. $date = new \DateTime();
  1020. $date->setISODate(date('Y'), 1, $day);
  1021. $day = $date->format('l');
  1022. $description = 'Every '. $day .' at '. $hour . $timeOfDay;
  1023. }
  1024. // Monthly
  1025. if(strtolower($frequency) == 'monthly')
  1026. {
  1027. $pieces = explode(' ', $cron);
  1028. $hour = $pieces[1];
  1029. $day = $pieces[2];
  1030. $timeOfDay = 'pm';
  1031. if($hour >= 0 and $hour < 12)
  1032. {
  1033. $timeOfDay = 'am';
  1034. }
  1035. $description = 'At '. $hour . $timeOfDay .' on day '. $day .' of the month';
  1036. }
  1037. return $description;
  1038. }
  1039. public function getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request)
  1040. {
  1041. $dataAction = 'data-action="click->admin--distributors#onClickPagination"';
  1042. $distributorProductsRepo = $this->em->getRepository(AiProducts::class)->findByManufacturer($distributorId,$manufacturerId,$speciesId);
  1043. $distributorProducts = $this->pageManager->paginate($distributorProductsRepo[0], $request, self::ITEMS_PER_PAGE);
  1044. $distributorProductsPagination = $this->getAjaxPagination($pageId, $distributorProducts, $distributorId, $dataAction);
  1045. $species = $this->em->getRepository(AiProductsSpecies::class)->adminFindByDistributorProducts($distributorId);
  1046. return $this->render('Admin/distributors/distributor_products.html.twig', [
  1047. 'species' => $species,
  1048. 'speciesId' => $speciesId,
  1049. 'distributorProducts' => $distributorProducts,
  1050. 'pagination' => $distributorProductsPagination,
  1051. ])->getContent();
  1052. }
  1053. public function getPagination($currentPage, $results, $dataAction = '', $itemsPerPage = 10): string
  1054. {
  1055. return $this->render('pagination.html.twig', [
  1056. 'currentPage' => $currentPage,
  1057. 'results' => $results,
  1058. 'dataAction' => $dataAction,
  1059. 'itemsPerPage' => $itemsPerPage,
  1060. 'lastPage' => $this->pageManager->lastPage($results),
  1061. 'totalPages' => ceil(count($results) / $itemsPerPage),
  1062. 'i' => max(1, $currentPage - 5),
  1063. 'forLimit' => min($currentPage + 5, ceil(count($results) / $itemsPerPage)),
  1064. ])->getContent();
  1065. }
  1066. public function getAjaxPagination($pageId, $results, $url, $dataAction = '', $itemsPerPage = 10): string
  1067. {
  1068. $currentPage = $pageId;
  1069. $totalPages = ceil(count($results) / $itemsPerPage);
  1070. $limit = 5;
  1071. $lastPage = $this->pageManager->lastPage($results);
  1072. $pagination = '';
  1073. if(count($results) > 0)
  1074. {
  1075. $pagination .= '
  1076. <!-- Pagination -->
  1077. <div class="row mt-3">
  1078. <div class="col-12">';
  1079. if ($lastPage > 1)
  1080. {
  1081. $previousPageNo = $currentPage - 1;
  1082. $previousPage = $url . $previousPageNo;
  1083. $pagination .= '
  1084. <nav class="custom-pagination">
  1085. <ul class="pagination justify-content-center">
  1086. ';
  1087. $disabled = 'disabled';
  1088. $dataDisabled = 'true';
  1089. // Previous Link
  1090. if ($currentPage > 1)
  1091. {
  1092. $disabled = '';
  1093. $dataDisabled = 'false';
  1094. }
  1095. if ($totalPages >= 1 && $pageId <= $totalPages && $currentPage != 1)
  1096. {
  1097. $pagination .= '
  1098. <li class="page-item ' . $disabled . '">
  1099. <a
  1100. class="address-pagination"
  1101. aria-disabled="' . $dataDisabled . '"
  1102. data-page-id="' . $currentPage - 1 . '"
  1103. href="#"
  1104. ' . $dataAction . '
  1105. >
  1106. <span aria-hidden="true">&laquo;</span> <span class="d-none d-sm-inline">Previous</span>
  1107. </a>
  1108. </li>
  1109. <li class="page-item ">
  1110. <a
  1111. class="address-pagination"
  1112. data-page-id="1"
  1113. href="#"
  1114. '. $dataAction .'
  1115. >
  1116. First
  1117. </a>
  1118. </li>';
  1119. }
  1120. $i = max(1, $currentPage - $limit);
  1121. $forLimit = min($currentPage + $limit, $totalPages);
  1122. $isActive = false;
  1123. for (; $i <= $forLimit; $i++)
  1124. {
  1125. $active = '';
  1126. if ($i == (int)$currentPage) {
  1127. $active = 'active';
  1128. $isActive = true;
  1129. }
  1130. // Go to previous page if all records for a page have been deleted
  1131. if (!$isActive && $i == count($results)) {
  1132. $active = 'active';
  1133. }
  1134. $pagination .= '
  1135. <li class="page-item ' . $active . '">
  1136. <a
  1137. class="address-pagination"
  1138. data-page-id="' . $i . '"
  1139. href="#"
  1140. ' . $dataAction . '
  1141. >' . $i . '</a>
  1142. </li>';
  1143. }
  1144. $disabled = 'disabled';
  1145. $dataDisabled = 'true';
  1146. if ($currentPage < $lastPage) {
  1147. $disabled = '';
  1148. $dataDisabled = 'false';
  1149. }
  1150. if ($currentPage < $lastPage)
  1151. {
  1152. $pagination .= '
  1153. <li class="page-item ">
  1154. <a
  1155. class="address-pagination"
  1156. data-page-id="'. $lastPage .'"
  1157. href="#"
  1158. '. $dataAction .'
  1159. >
  1160. Last
  1161. </a>
  1162. </li>
  1163. <li class="page-item ' . $disabled . '">
  1164. <a
  1165. class="address-pagination"
  1166. aria-disabled="' . $dataDisabled . '"
  1167. data-page-id="' . $currentPage + 1 . '"
  1168. href="#"
  1169. '. $dataAction .'
  1170. >
  1171. <span class="d-none d-sm-inline">Next</span> <span aria-hidden="true">&raquo;</span>
  1172. </a>
  1173. </li>';
  1174. }
  1175. $pagination .= '
  1176. </ul>
  1177. </nav>
  1178. <input type="hidden" id="page_no" value="' . $currentPage . '">
  1179. </div>';
  1180. }
  1181. }
  1182. return $pagination;
  1183. }
  1184. }