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