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. use Symfony\Component\Lock\LockFactory;
  42. use Symfony\Component\Lock\Store\FlockStore;
  43. class DistributorsController extends AbstractController
  44. {
  45. private $em;
  46. const ITEMS_PER_PAGE = 10;
  47. private $pageManager;
  48. private $requestStack;
  49. private $plainPassword;
  50. private $encryptor;
  51. public function __construct(EntityManagerInterface $em, PaginationManager $pagination, RequestStack $requestStack, Encryptor $encryptor)
  52. {
  53. $this->em = $em;
  54. $this->pageManager = $pagination;
  55. $this->requestStack = $requestStack;
  56. $this->encryptor = $encryptor;
  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. $scraperUrls = $this->em->getRepository(ScraperUrls::class)->findBy([
  900. 'scraperAuthentication' => $distributor?->getScraperAunthentication()->getId(),
  901. ],
  902. [
  903. 'pageName' => 'ASC'
  904. ]);
  905. $response = $this->render('Admin/distributors/distributors.html.twig', [
  906. 'distributor' => $distributor,
  907. 'distributorUsers' => $distributorUsers,
  908. 'userPermissions' => $userPermissions,
  909. 'api' => $api,
  910. 'countries' => $countries,
  911. 'distributorProducts' => $distributorProducts,
  912. 'scraperUrls' => $scraperUrls,
  913. ])->getContent();
  914. return new JsonResponse($response);
  915. }
  916. #[Route('/admin/approve/distributor', name: 'admin_approve_distributor')]
  917. public function adminApproveDistributor(Request $request): Response
  918. {
  919. $distributorId = $request->request->get('distributor-id');
  920. $isApproved = $request->request->get('is-approved');
  921. $distributor = $this->em->getRepository(Distributors::class)->find($distributorId);
  922. if($distributor != null)
  923. {
  924. if($isApproved == 1 || $isApproved == 0)
  925. {
  926. $isApproved = 2;
  927. }
  928. else if($isApproved == 2)
  929. {
  930. $isApproved = 1;
  931. }
  932. $distributor->setIsApproved($isApproved);
  933. $this->em->persist($distributor);
  934. $this->em->flush();
  935. }
  936. return new JsonResponse('');
  937. }
  938. #[Route('/admin/get-distributor-products', name: 'admin_get_distributor_products')]
  939. public function distributorInventory(Request $request): Response
  940. {
  941. $pageId = $request->request->get('page-id');
  942. $distributorId = $request->request->get('distributor-id');
  943. $manufacturerId = $request->request->get('manufacturer-id');
  944. $speciesId = $request->request->get('species-id');
  945. $response = $this->getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request);
  946. return new JsonResponse($response);
  947. }
  948. #[Route('/admin/save-scraper-frequency', name: 'admin_save_scraper_frequency')]
  949. public function saveScraperFrequency(Request $request): Response
  950. {
  951. $name = $request->request->get('name');
  952. $cron = $request->request->get('cron');
  953. $status = (int) $request->request->get('status');
  954. $scraperUrlId = $request->request->get('scraper-url-id');
  955. $frequency = $request->request->get('frequency');
  956. $scraperUrl = $this->em->getRepository(ScraperUrls::class)->find($scraperUrlId);
  957. if($scraperUrl == null)
  958. {
  959. $response = [
  960. 'flash' => 'Please first save the scraper url.',
  961. 'type' => 'danger'
  962. ];
  963. return new JsonResponse($response);
  964. }
  965. $cronJob = $this->em->getRepository(CronJob::class)->findOneBy([
  966. 'scraperUrl' => $scraperUrl->getId(),
  967. ]);
  968. if($cronJob == null)
  969. {
  970. $cronJob = new CronJob();
  971. }
  972. $cronJob->setName($name);
  973. $cronJob->setExpression($cron);
  974. $cronJob->setCommand($scraperUrl->getDistributor()->getScraperAunthentication()->getCommand());
  975. $cronJob->setActive($status);
  976. $cronJob->setScraperUrl($scraperUrl);
  977. $cronJob->setFrequency($frequency);
  978. $cronJob->setDescription($this->getCronDescription($cron, $frequency));
  979. $this->em->persist($cronJob);
  980. $this->em->flush();
  981. $response = [
  982. 'flash' => 'Schedule saved successfully.',
  983. 'type' => 'success'
  984. ];
  985. return new JsonResponse($response);
  986. }
  987. #[Route('/admin/run-scraper', name: 'admin_run_scraper')]
  988. public function runScraper(Request $request): Response
  989. {
  990. $lockFactory = new LockFactory(new FlockStore());
  991. $lock = $lockFactory->createLock('app:scrape-eurovets');
  992. $command = $request->request->get('command');
  993. $email = $this->encryptor->decrypt($this->getUser()->getEmail());
  994. if(!$lock->acquire())
  995. {
  996. $response = [
  997. 'flash' => 'Scraper is already running.',
  998. 'type' => 'danger'
  999. ];
  1000. return new JsonResponse($response);
  1001. }
  1002. exec(__DIR__ . "/../../bin/console $command 0 $email > /dev/null 2>&1 &");
  1003. $response = [
  1004. 'flash' => 'Scraper successfully started.',
  1005. 'type' => 'success'
  1006. ];
  1007. return new JsonResponse($response);
  1008. }
  1009. #[Route('/admin/scrape-brand', name: 'admin_scrape_brand')]
  1010. public function scrapeBrand(Request $request): Response
  1011. {
  1012. $lockFactory = new LockFactory(new FlockStore());
  1013. $command = $request->request->get('command');
  1014. $lock = $lockFactory->createLock($command);
  1015. $brandId = $request->request->get('brand-id');
  1016. $email = $this->encryptor->decrypt($this->getUser()->getEmail());
  1017. if(!$lock->acquire())
  1018. {
  1019. $response = [
  1020. 'flash' => 'Scraper is already running.',
  1021. 'type' => 'danger'
  1022. ];
  1023. return new JsonResponse($response);
  1024. }
  1025. // Not running
  1026. $lock->release();
  1027. exec(__DIR__ . "/../../bin/console $command $brandId $email > /dev/null 2>&1 &");
  1028. $response = [
  1029. 'flash' => 'Scraper successfully started.',
  1030. 'type' => 'success'
  1031. ];
  1032. return new JsonResponse($response);
  1033. }
  1034. public function getCronDescription($cron, $frequency): string
  1035. {
  1036. $description = '';
  1037. // Daily
  1038. if(strtolower($frequency) == 'daily')
  1039. {
  1040. $pieces = explode(' ', $cron);
  1041. $hour = $pieces[1];
  1042. $timeOfDay = 'pm';
  1043. if($hour >= 0 and $hour < 12)
  1044. {
  1045. $timeOfDay = 'am';
  1046. }
  1047. $description = 'Every day at '. $hour . $timeOfDay;
  1048. }
  1049. // Weekly
  1050. if(strtolower($frequency) == 'weekly')
  1051. {
  1052. $pieces = explode(' ', $cron);
  1053. $hour = $pieces[1];
  1054. $day = (int) $pieces[4];
  1055. $timeOfDay = 'pm';
  1056. if($hour >= 0 and $hour < 12)
  1057. {
  1058. $timeOfDay = 'am';
  1059. }
  1060. $date = new \DateTime();
  1061. $date->setISODate(date('Y'), 1, $day);
  1062. $day = $date->format('l');
  1063. $description = 'Every '. $day .' at '. $hour . $timeOfDay;
  1064. }
  1065. // Monthly
  1066. if(strtolower($frequency) == 'monthly')
  1067. {
  1068. $pieces = explode(' ', $cron);
  1069. $hour = $pieces[1];
  1070. $day = $pieces[2];
  1071. $timeOfDay = 'pm';
  1072. if($hour >= 0 and $hour < 12)
  1073. {
  1074. $timeOfDay = 'am';
  1075. }
  1076. $description = 'At '. $hour . $timeOfDay .' on day '. $day .' of the month';
  1077. }
  1078. return $description;
  1079. }
  1080. public function getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request)
  1081. {
  1082. $dataAction = 'data-action="click->admin--distributors#onClickPagination"';
  1083. $distributorProductsRepo = $this->em->getRepository(AiProducts::class)->findByManufacturer($distributorId,$manufacturerId,$speciesId);
  1084. $distributorProducts = $this->pageManager->paginate($distributorProductsRepo[0], $request, self::ITEMS_PER_PAGE);
  1085. $distributorProductsPagination = $this->getAjaxPagination($pageId, $distributorProducts, $distributorId, $dataAction);
  1086. $species = $this->em->getRepository(AiProductsSpecies::class)->adminFindByDistributorProducts($distributorId);
  1087. return $this->render('Admin/distributors/distributor_products.html.twig', [
  1088. 'species' => $species,
  1089. 'speciesId' => $speciesId,
  1090. 'distributorProducts' => $distributorProducts,
  1091. 'pagination' => $distributorProductsPagination,
  1092. ])->getContent();
  1093. }
  1094. public function getPagination($currentPage, $results, $dataAction = '', $itemsPerPage = 10): string
  1095. {
  1096. return $this->render('pagination.html.twig', [
  1097. 'currentPage' => $currentPage,
  1098. 'results' => $results,
  1099. 'dataAction' => $dataAction,
  1100. 'itemsPerPage' => $itemsPerPage,
  1101. 'lastPage' => $this->pageManager->lastPage($results),
  1102. 'totalPages' => ceil(count($results) / $itemsPerPage),
  1103. 'i' => max(1, $currentPage - 5),
  1104. 'forLimit' => min($currentPage + 5, ceil(count($results) / $itemsPerPage)),
  1105. ])->getContent();
  1106. }
  1107. public function getAjaxPagination($pageId, $results, $url, $dataAction = '', $itemsPerPage = 10): string
  1108. {
  1109. $currentPage = $pageId;
  1110. $totalPages = ceil(count($results) / $itemsPerPage);
  1111. $limit = 5;
  1112. $lastPage = $this->pageManager->lastPage($results);
  1113. $pagination = '';
  1114. if(count($results) > 0)
  1115. {
  1116. $pagination .= '
  1117. <!-- Pagination -->
  1118. <div class="row mt-3">
  1119. <div class="col-12">';
  1120. if ($lastPage > 1)
  1121. {
  1122. $previousPageNo = $currentPage - 1;
  1123. $previousPage = $url . $previousPageNo;
  1124. $pagination .= '
  1125. <nav class="custom-pagination">
  1126. <ul class="pagination justify-content-center">
  1127. ';
  1128. $disabled = 'disabled';
  1129. $dataDisabled = 'true';
  1130. // Previous Link
  1131. if ($currentPage > 1)
  1132. {
  1133. $disabled = '';
  1134. $dataDisabled = 'false';
  1135. }
  1136. if ($totalPages >= 1 && $pageId <= $totalPages && $currentPage != 1)
  1137. {
  1138. $pagination .= '
  1139. <li class="page-item ' . $disabled . '">
  1140. <a
  1141. class="address-pagination"
  1142. aria-disabled="' . $dataDisabled . '"
  1143. data-page-id="' . $currentPage - 1 . '"
  1144. href="#"
  1145. ' . $dataAction . '
  1146. >
  1147. <span aria-hidden="true">&laquo;</span> <span class="d-none d-sm-inline">Previous</span>
  1148. </a>
  1149. </li>
  1150. <li class="page-item ">
  1151. <a
  1152. class="address-pagination"
  1153. data-page-id="1"
  1154. href="#"
  1155. '. $dataAction .'
  1156. >
  1157. First
  1158. </a>
  1159. </li>';
  1160. }
  1161. $i = max(1, $currentPage - $limit);
  1162. $forLimit = min($currentPage + $limit, $totalPages);
  1163. $isActive = false;
  1164. for (; $i <= $forLimit; $i++)
  1165. {
  1166. $active = '';
  1167. if ($i == (int)$currentPage) {
  1168. $active = 'active';
  1169. $isActive = true;
  1170. }
  1171. // Go to previous page if all records for a page have been deleted
  1172. if (!$isActive && $i == count($results)) {
  1173. $active = 'active';
  1174. }
  1175. $pagination .= '
  1176. <li class="page-item ' . $active . '">
  1177. <a
  1178. class="address-pagination"
  1179. data-page-id="' . $i . '"
  1180. href="#"
  1181. ' . $dataAction . '
  1182. >' . $i . '</a>
  1183. </li>';
  1184. }
  1185. $disabled = 'disabled';
  1186. $dataDisabled = 'true';
  1187. if ($currentPage < $lastPage) {
  1188. $disabled = '';
  1189. $dataDisabled = 'false';
  1190. }
  1191. if ($currentPage < $lastPage)
  1192. {
  1193. $pagination .= '
  1194. <li class="page-item ">
  1195. <a
  1196. class="address-pagination"
  1197. data-page-id="'. $lastPage .'"
  1198. href="#"
  1199. '. $dataAction .'
  1200. >
  1201. Last
  1202. </a>
  1203. </li>
  1204. <li class="page-item ' . $disabled . '">
  1205. <a
  1206. class="address-pagination"
  1207. aria-disabled="' . $dataDisabled . '"
  1208. data-page-id="' . $currentPage + 1 . '"
  1209. href="#"
  1210. '. $dataAction .'
  1211. >
  1212. <span class="d-none d-sm-inline">Next</span> <span aria-hidden="true">&raquo;</span>
  1213. </a>
  1214. </li>';
  1215. }
  1216. $pagination .= '
  1217. </ul>
  1218. </nav>
  1219. <input type="hidden" id="page_no" value="' . $currentPage . '">
  1220. </div>';
  1221. }
  1222. }
  1223. return $pagination;
  1224. }
  1225. }