src/Controller/DistributorsController.php line 75
<?phpnamespace App\Controller;use App\Entity\Addresses;use App\Entity\AiProducts;use App\Entity\AiProductsSpecies;use App\Entity\Api;use App\Entity\ApiDetails;use App\Entity\AvailabilityTracker;use App\Entity\Clinics;use App\Entity\ClinicUsers;use App\Entity\Countries;use App\Entity\CronJob;use App\Entity\DistributorProducts;use App\Entity\Distributors;use App\Entity\DistributorUserPermissions;use App\Entity\DistributorUsers;use App\Entity\Notifications;use App\Entity\Products;use App\Entity\RefreshTokens;use App\Entity\RestrictedDomains;use App\Entity\ScraperUrls;use App\Entity\Tracking;use App\Entity\UserPermissions;use App\Form\AddressesFormType;use App\Form\DistributorFormType;use App\Form\DistributorUsersFormType;use App\Services\PaginationManager;use Doctrine\ORM\EntityManagerInterface;use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\BinaryFileResponse;use Symfony\Component\HttpFoundation\JsonResponse;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\RequestStack;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpFoundation\ResponseHeaderBag;use Symfony\Component\Mailer\MailerInterface;use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;use Symfony\Component\Routing\Annotation\Route;use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;class DistributorsController extends AbstractController{private $em;const ITEMS_PER_PAGE = 10;private $pageManager;private $requestStack;private $plainPassword;private $encryptor;private $mailer;public function __construct(EntityManagerInterface $em, PaginationManager $pagination, RequestStack $requestStack, Encryptor $encryptor, MailerInterface $mailer){$this->em = $em;$this->pageManager = $pagination;$this->requestStack = $requestStack;$this->encryptor = $encryptor;$this->mailer = $mailer;}#[Route('/distributors/dashboard', name: 'distributor_dashboard')]#[Route('/distributors/account', name: 'distributor_account')]#[Route('/distributors/about', name: 'distributor_about')]#[Route('/distributors/operating-hours', name: 'distributor_operating_hours')]#[Route('/distributors/refund-policy', name: 'distributor_refund_policy')]#[Route('/distributors/sales-tax-policy', name: 'distributor_sales_tax_policy')]#[Route('/distributors/shipping-policy', name: 'distributor_shipping_policy')]#[Route('/distributors/manage-inventory', name: 'distributor_manage_inventory')]#[Route('/distributors/users', name: 'distributor_get_users')]#[Route('/distributors/order/{order_id}', name: 'distributor_order')]#[Route('/distributors/orders/{distributor_id}', name: 'distributor_order_list')]#[Route('/distributors/customers/1', name: 'distributor_customer_list')]#[Route('/distributors/inventory/list', name: 'distributor_inventory_list')]public function distributorDashboardAction(Request $request): Response{if($this->getUser()->getUserIdentifier() == null){$this->addFlash('danger', 'Your session expired due to inactivity, please login.');return $this->redirectToRoute('distributor_login');}$distributor = $this->getUser()->getDistributor();$user = $this->getUser();$username = $distributor->getDistributorName();$permissions = [];foreach($user->getDistributorUserPermissions() as $permission){$permissions[] = $permission->getPermission()->getId();}return $this->render('frontend/distributors/index.html.twig',['distributor' => $distributor,'permissions' => json_encode($permissions),'username' => $username,]);}#[Route('/distributors/register', name: 'distributor_reg')]public function distributorReg(Request $request): Response{$countries = $this->em->getRepository(Countries::class)->findBy(['isActive' => 1,]);$form = $this->createRegisterForm();return $this->render('frontend/distributors/register.html.twig', ['form' => $form->createView(),'countries' => $countries]);}#[Route('/sellers', name: 'sellers_page')]public function sellersAction(Request $request): Response{$sellers = $this->em->getRepository(Distributors::class)->findBy(['isApproved' => true,]);return $this->render('frontend/sellers.html.twig', ['sellers' => $sellers,]);}protected function createRegisterForm(){$distributors = new Distributors();return $this->createForm(DistributorFormType::class, $distributors);}#[Route('/distributors/register/check-email', name: 'distributor_check_email')]public function distributorsCheckEmailAction(Request $request): Response{$email = $request->request->get('email');$domainName = explode('@', $email);$response['response'] = true;$firstName = '';$restrictedDomains = $this->em->getRepository(RestrictedDomains::class)->arrayFindAll();foreach($restrictedDomains as $restrictedDomain){if(md5($domainName[1]) == md5($restrictedDomain->getName())){$response['response'] = false;$response['restricted'] = true;return new JsonResponse($response);}}$distributor = $this->em->getRepository(Distributors::class)->findOneBy(['hashedEmail' => md5($email),]);$distributorDomain = $this->em->getRepository(Distributors::class)->findOneBy(['domainName' => md5($domainName[1]),]);$distributorUsers = $this->em->getRepository(DistributorUsers::class)->findOneBy(['hashedEmail' => md5($email),]);$clinic = $this->em->getRepository(Clinics::class)->findOneBy(['hashedEmail' => md5($email),]);$clinicDomain = $this->em->getRepository(Clinics::class)->findOneBy(['domainName' => md5($domainName[1]),]);$clinicUsers = $this->em->getRepository(ClinicUsers::class)->findOneBy(['hashedEmail' => md5($email),]);if($clinicDomain != null){$user = $this->em->getRepository(ClinicUsers::class)->findOneBy(['clinic' => $clinicDomain->getId(),'isPrimary' => 1]);$firstName = $this->encryptor->decrypt($user->getFirstName());}if($distributorDomain != null){$user = $this->em->getRepository(DistributorUsers::class)->findOneBy(['distributor' => $distributorDomain->getId(),'isPrimary' => 1]);$firstName = $this->encryptor->decrypt($user->getFirstName());}$response['firstName'] = $firstName;if($distributor != null || $distributorUsers != null || $clinic != null || $clinicUsers != null || $clinicDomain != null || $distributorDomain != null){$response['response'] = false;$response['restricted'] = false;}return new JsonResponse($response);}#[Route('/distributor/addresses', name: 'distributor_addresses')]public function createDistributorAddressesForm(){$addresses = new Addresses();return $this->createForm(AddressesFormType::class, $addresses);}#[Route('/distributor/register/create', name: 'distributor_create')]public function distributorCreateAction(Request $request, UserPasswordHasherInterface $passwordHasher, MailerInterface $mailer): Response{$data = $request->request;$distributor = $this->em->getRepository(Distributors::class)->findOneBy(['email' => $data->get('email')]);$countries = $this->em->getRepository(Countries::class)->find($data->get('country'));$tracking = $this->em->getRepository(Tracking::class)->find(3);if($distributor == null) {$distributors = new Distributors();$plainTextPwd = $this->generatePassword();if (!empty($plainTextPwd)) {$domainName = explode('@', $data->get('email'));$distributors->setDistributorName($this->encryptor->encrypt($data->get('distributor-name')));$distributors->setEmail($this->encryptor->encrypt($data->get('email')));$distributors->setHashedEmail(md5($data->get('email')));$distributors->setDomainName(md5($domainName[1]));$distributors->setTelephone($this->encryptor->encrypt($data->get('telephone')));$distributors->setIntlCode($this->encryptor->encrypt($data->get('intl-code')));$distributors->setIsoCode($this->encryptor->encrypt($data->get('iso-code')));$distributors->setAddressCountry($countries);$distributors->setTracking($tracking);$distributors->setIsApproved(0);$this->em->persist($distributors);$this->em->flush();// Create user$distributor = $this->em->getRepository(Distributors::class)->findOneBy(['hashedEmail' => md5($data->get('email')),]);$distributorUsers = new DistributorUsers();$hashed_pwd = $passwordHasher->hashPassword($distributorUsers, $plainTextPwd);$distributorUsers->setDistributor($distributor);$distributorUsers->setFirstName($this->encryptor->encrypt($data->get('first-name')));$distributorUsers->setLastName($this->encryptor->encrypt($data->get('last-name')));$distributorUsers->setPosition($this->encryptor->encrypt($data->get('position')));$distributorUsers->setEmail($this->encryptor->encrypt($data->get('email')));$distributorUsers->setHashedEmail(md5($data->get('email')));$distributorUsers->setTelephone($this->encryptor->encrypt($data->get('telephone')));$distributorUsers->setRoles(['ROLE_DISTRIBUTOR']);$distributorUsers->setPassword($hashed_pwd);$distributorUsers->setIsPrimary(1);$this->em->persist($distributorUsers);$this->em->flush();// Assign User Permissions$userPermissions = $this->em->getRepository(UserPermissions::class)->findBy(['isDistributor' => 1,]);foreach($userPermissions as $userPermission){$distributorUserPermissions = new DistributorUserPermissions();$distributorUserPermissions->setUser($distributorUsers);$distributorUserPermissions->setDistributor($distributors);$distributorUserPermissions->setPermission($userPermission);$this->em->persist($distributorUserPermissions);}$this->em->flush();// Send Email$body = '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';$body .= '<tr><td colspan="2">Hi '. $data->get('first_name') .',</td></tr>';$body .= '<tr><td colspan="2"> </td></tr>';$body .= '<tr><td colspan="2">Please use the credentials below login to the Fluid Backend.</td></tr>';$body .= '<tr><td colspan="2"> </td></tr>';$body .= '<tr>';$body .= ' <td><b>URL: </b></td>';$body .= ' <td><a href="https://'. $_SERVER['HTTP_HOST'] .'/distributors/login">https://'. $_SERVER['HTTP_HOST'] .'/distributor/login</a></td>';$body .= '</tr>';$body .= '<tr>';$body .= ' <td><b>Username: </b></td>';$body .= ' <td>'. $data->get('email') .'</td>';$body .= '</tr>';$body .= '<tr>';$body .= ' <td><b>Password: </b></td>';$body .= ' <td>'. $plainTextPwd .'</td>';$body .= '</tr>';$body .= '</table>';$subject = 'Fluid Login Credentials';$to = $data->get('email');exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($body) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');}$response = '<div class="row pt-3"><div class="col-12 text-center mt-1 pt-3 pb-3" id="order_header"><h4 class="text-primary">Let\'s Create Your Account.</h4><span class="text-primary">Your Fluid account was successfully created, an email with your login credentials has been sent to your inbox.</span></div>';} else {$response = false;}return new JsonResponse($response);}#[Route('/distributors/get/company-information', name: 'get_company_information')]public function getCompanyInformation(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$countries = $this->em->getRepository(Countries::class)->findAll();$html = $this->render('frontend/distributors/company_information.html.twig', ['distributor' => $distributor,'countries' => $countries,])->getContent();return new JsonResponse($html);}private function generatePassword(): string{$curl = curl_init();curl_setopt_array($curl, array(CURLOPT_URL => 'https://www.dinopass.com/password/simple',CURLOPT_RETURNTRANSFER => true,CURLOPT_ENCODING => '',CURLOPT_MAXREDIRS => 10,CURLOPT_TIMEOUT => 0,CURLOPT_FOLLOWLOCATION => true,CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,CURLOPT_CUSTOMREQUEST => 'GET',));$response = curl_exec($curl);curl_close($curl);$this->plainPassword = $response;return $this->plainPassword;}public function createDistributorUserForm(){$distributorUsers = new DistributorUsers();return $this->createForm(DistributorUsersFormType::class, $distributorUsers);}#[Route('/distributors/update/company-information', name: 'distributor_update_company_information')]public function distributorUpdateCompanyInformationAction(Request $request): Response{$data = $request->request->all('distributor_form');$distributor = $this->getUser()->getDistributor();$countryId = (int) $data['addressCountry'];$logo = '';$country = $this->em->getRepository(Countries::class)->find($countryId);$isApproved = (bool) $distributor->getIsApproved() ?? false;$tradeLicense = $_FILES['distributor_form']['name']['trade-license-file'];$tradeLicenseNo = $data['trade-license-no'];$tradeLicenseExpDate = $data['trade-license-exp-date'];// Account approval required if reg docs changeif(!empty($tradeLicense) || $tradeLicenseNo != $this->encryptor->decrypt($distributor->getTradeLicenseNo()) ||$tradeLicenseExpDate != $distributor->getTradeLicenseExpDate()->format('Y-m-d')){$distributor->setIsApproved(0);$isApproved = false;}if($distributor != null){$domainName = explode('@', $data['email']);$distributor->setDistributorName($this->encryptor->encrypt($data['distributor-name']));$distributor->setTelephone($this->encryptor->encrypt($data['telephone']));$distributor->setEmail($this->encryptor->encrypt($data['email']));$distributor->setWebsite($this->encryptor->encrypt($data['website']));$distributor->setDomainName(md5($domainName[1]));$distributor->setAddressCountry($country);$distributor->setAddressStreet($this->encryptor->encrypt($data['address-street']));$distributor->setAddressCity($this->encryptor->encrypt($data['address-city']));$distributor->setAddressPostalCode($this->encryptor->encrypt($data['address-postal-code']));$distributor->setAddressState($this->encryptor->encrypt($data['address-state']));$distributor->setIsoCode($this->encryptor->encrypt($data['iso-code']));$distributor->setIntlCode($this->encryptor->encrypt($data['intl-code']));$distributor->setManagerFirstName($this->encryptor->encrypt($data['manager-first-name']));$distributor->setManagerLastName($this->encryptor->encrypt($data['manager-last-name']));$distributor->setManagerIdNo($this->encryptor->encrypt($data['manager-id-no']));$distributor->setManagerIdExpDate(new \DateTime($data['manager-id-exp-date']));$distributor->setTradeLicenseNo($this->encryptor->encrypt($data['trade-license-no']));$distributor->setTradeLicenseExpDate(new \DateTime($data['trade-license-exp-date']));if(!empty($_FILES['distributor_form']['name']['trade-license-file'])){$extension = pathinfo($_FILES['distributor_form']['name']['trade-license-file'], PATHINFO_EXTENSION);$file = $distributor->getId() . '-' . uniqid() . '.' . $extension;$targetFile = __DIR__ . '/../../public/documents/' . $file;if(move_uploaded_file($_FILES['distributor_form']['tmp_name']['trade-license-file'], $targetFile)){$distributor->setTradeLicense($file);}}if(!empty($_FILES['distributor_form']['name']['logo'])){$extension = pathinfo($_FILES['distributor_form']['name']['logo'], PATHINFO_EXTENSION);$file = $distributor->getId() . '-' . uniqid() . '.' . $extension;$targetFile = __DIR__ . '/../../public/images/logos/' . $file;if (move_uploaded_file($_FILES['distributor_form']['tmp_name']['logo'], $targetFile)){$distributor->setLogo($file);$logo = $file;}}$this->em->persist($distributor);$this->em->flush();// Send Approval Emailif(!$isApproved){$orderUrl = $this->getParameter('app.base_url') . '/admin/distributor/'. $distributor->getId();$html = '<p>Please <a href="'. $orderUrl .'">click here</a> to view the distributors details.</p><br>';$html = $this->forward('App\Controller\ResetPasswordController::emailFooter', ['html' => $html,]);$subject = 'Fluid - Account Approval Request';$to = $this->getParameter('app.email_admin');exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($html) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');}$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>';}else{$message = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';}$response = ['message' => $message,'logo' => $logo,];return new JsonResponse($response);}#[Route('/distributors/download/trade-license/{tradeLicense}', name: 'distributors_download_trade_license')]public function distributorDownloadTradeLicenseAction(Request $request){$path = __DIR__ . '/../../public/documents/';$tradeLicense = $path . $request->get('tradeLicense');$response = new BinaryFileResponse($tradeLicense);$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT,basename($tradeLicense));return $response;}#[Route('/distributors/update/about_us', name: 'distributor_update_about_us')]public function distributorUpdateAboutUsAction(Request $request): Response{$data = $request->request;$distributor = $this->getUser()->getDistributor();if($distributor != null){$about = $data->get('about-us');if(!empty($about)){$distributor->setAbout($about);$this->em->persist($distributor);$this->em->flush();}$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>';}else{$response = '<b><i class="fas fa-check-circle"></i> An error occurred.';}return new JsonResponse($response);}#[Route('/distributors/update/operating_hours', name: 'distributor_update_operating_hours')]public function distributorUpdateOperatingHoursAction(Request $request): Response{$data = $request->request;$distributor = $this->getUser()->getDistributor();if($distributor != null){if(!empty($data->get('operating-hours'))){$distributor->setOperatingHours($data->get('operating-hours'));}$this->em->persist($distributor);$this->em->flush();$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>';}else{$response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';}return new JsonResponse($response);}#[Route('/distributors/update/refund_policy', name: 'distributor_update_refund_policy')]public function distributorUpdateRefundPolicyAction(Request $request): Response{$data = $request->request;$distributor = $this->getUser()->getDistributor();if($distributor != null){if(!empty($data->get('refund-policy'))){$distributor->setRefundPolicy($data->get('refund-policy'));}$this->em->persist($distributor);$this->em->flush();$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>';}else{$response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';}return new JsonResponse($response);}#[Route('/distributors/update/sales_tax_policy', name: 'distributor_update_sales_tax_policy')]public function distributorUpdateSalesTaxPolicyAction(Request $request): Response{$data = $request->request;$distributor = $this->getUser()->getDistributor();if($distributor != null){if(!empty($data->get('sales-tax-policy'))){$distributor->setSalesTaxPolicy($data->get('sales-tax-policy'));}$this->em->persist($distributor);$this->em->flush();$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>';}else{$response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';}return new JsonResponse($response);}#[Route('/distributors/update/shipping_policy', name: 'distributor_update_shipping_policy')]public function distributorUpdateShippingPolicyAction(Request $request): Response{$data = $request->request;$distributor = $this->getUser()->getDistributor();if($distributor != null){if(!empty($data->get('shipping-policy'))){$distributor->setShippingPolicy($data->get('shipping-policy'));}$this->em->persist($distributor);$this->em->flush();$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>';}else{$response = '<b><i class="fas fa-check-circle"></i> Personal details successfully updated.';}return new JsonResponse($response);}#[Route('/distributors/get/about', name: 'get_about')]public function getAbout(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$html = $this->render('frontend/distributors/about.html.twig', ['distributor' => $distributor,])->getContent();return new JsonResponse($html);}#[Route('/distributors/get/operating-hours', name: 'get_distributor_operating_hours')]public function getDistributorOperatingHours(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$html = $this->render('frontend/distributors/operating_hours.html.twig', ['distributor' => $distributor,])->getContent();return new JsonResponse($html);}#[Route('/distributors/get/refund-policy', name: 'get_distributor_refund_policy')]public function getDistributorRefundPolicy(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$html = $this->render('frontend/distributors/refund_policy.html.twig', ['distributor' => $distributor,])->getContent();return new JsonResponse($html);}#[Route('/distributors/get/sales-tax-policy', name: 'get_distributor_sales_tax_policy')]public function getDistributorSalesTaxPolicy(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$html = $this->render('frontend/distributors/sales_tax_policy.html.twig', ['distributor' => $distributor,])->getContent();return new JsonResponse($html);}#[Route('/distributors/get/shipping-policy', name: 'get_distributor_shipping_policy')]public function getDistributorShippingPolicy(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$html = $this->render('frontend/distributors/shipping_policy.htm.twig', ['distributor' => $distributor,])->getContent();return new JsonResponse($html);}#[Route('/distributors/inventory-search', name: 'distributor_inventory_search')]public function distributorInventorySearchAction(Request $request): Response{$products = $this->em->getRepository(Products::class)->findBySearch($request->get('keyword'));$select = '<ul id="product_list">';foreach($products as $product){$id = $product->getId();$name = $product->getName();$dosage = '';$size = '';if(!empty($product->getDosage())) {$unit = '';if(!empty($product->getUnit())) {$unit = $product->getUnit();}$dosage = ' | '. $product->getDosage() . $unit;}if(!empty($product->getSize())) {$size = ' | '. $product->getSize();}$select .= "<liclass=\"search-item\"data-product-id=\"$id\"data-product-name=\"$name\"data-action='click->products--distributor-products#onclickEditIcon'>$name$dosage$size</li>";}$select .= '</ul>';return new Response($select);}#[Route('/distributors/inventory-get', name: 'distributor_inventory_get')]public function distributorGetInventoryAction(Request $request,TokenStorageInterface $tokenStorage): Response{$productId = (int) $request->request->get('product-id');$products = $this->em->getRepository(Products::class)->find($productId);if($products != null){$distributorId = $this->getUser()->getDistributor()->getId();$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$response = [];$response['html'] = json_decode($this->forward('App\Controller\DistributorProductsController::getDistributorProductAction')->getContent());$distributorProduct = $this->em->getRepository(Distributors::class)->getDistributorProduct($distributor->getId(), $productId);if($distributorProduct != null){$response['distributor_id'] = $distributor->getId();$response['itemId'] = $distributorProduct[0]['distributorProducts'][0]['itemId'];$response['sku'] = $distributorProduct[0]['distributorProducts'][0]['sku'];$response['unit_price'] = $distributorProduct[0]['distributorProducts'][0]['unitPrice'];$response['stock_count'] = $distributorProduct[0]['distributorProducts'][0]['stockCount'];$response['expiry_date'] = '';$response['tax_exempt'] = $distributorProduct[0]['distributorProducts'][0]['taxExempt'];$response['product'] = $distributorProduct[0]['distributorProducts'][0]['product'];if($distributorProduct[0]['distributorProducts'][0]['expiryDate'] != null){$response['expiry_date'] = $distributorProduct[0]['distributorProducts'][0]['expiryDate']->format('Y-m-d');}}else{$product = $this->em->getRepository(Products::class)->find($productId);$response['distributor_id'] = $distributor->getId();$response['sku'] = '';$response['distributor_no'] = '';$response['unit_price'] = '';$response['stock_count'] = '';$response['expiry_date'] = '';$response['tax_exempt'] = 0;$response['product'] = ['dosage' => $product->getDosage(),'size' => $product->getSize(),'unit' => $product->getUnit(),'activeIngredient' => $product->getActiveIngredient(),];}}else{$response['message'] = 'Inventory item not found';}return new JsonResponse($response);}#[Route('/distributors/inventory-update', name: 'distributor_inventory_update')]public function distributorUpdateInventoryAction(Request $request, MailerInterface $mailer): Response{$data = $request->request->all('distributor_products_form');$product = $this->em->getRepository(Products::class)->find($data['product']);$distributor = $this->em->getRepository(Distributors::class)->find($data['distributor']);$distributorProducts = $this->em->getRepository(DistributorProducts::class)->findOneBy(['product' => $data['product'],'distributor' => $data['distributor']]);$tracking = false;$response['unitPrice'] = 0.00;$response['stockLevel'] = 0;if($distributorProducts == null){$distributorProducts = new DistributorProducts();} else {if($distributorProducts->getStockCount() == 0){$tracking = true;}}if(!empty($data['product']) && !empty($data['distributor'])){$trackingId = $distributor->getTracking()->getId();$distributorProducts->setDistributor($distributor);$distributorProducts->setProduct($product);$distributorProducts->setSku($data['sku']);$distributorProducts->setItemId($data['itemId']);$distributorProducts->setTaxExempt($data['taxExempt']);$distributorProducts->setIsActive(1);$taxExempt = 0;if(!empty($data['taxExempt'])){$taxExempt = $data['taxExempt'];}$distributorProducts->setTaxExempt($taxExempt);if($trackingId == 3){$distributorProducts->setUnitPrice($data['unitPrice']);$distributorProducts->setStockCount((int)$data['stockCount']);}// Get stock and price from APIif($trackingId == 1){// Retrieve price & stock from api$distributorId = $distributor->getId();$priceStockLevels = json_decode($this->forward('App\Controller\ProductsController::zohoRetrieveItem',['distributorId' => $distributorId,'itemId' => $data['itemId'],])->getContent(), true);$response['unitPrice'] = $priceStockLevels['unitPrice'] ?? 0.00;$response['stockLevel'] = $priceStockLevels['stockLevel'] ?? 0;$distributorProducts->setUnitPrice($response['unitPrice']);$distributorProducts->setStockCount($response['stockLevel']);}$this->em->persist($distributorProducts);$this->em->flush();// Update parent stock level$stockCount = $this->em->getRepository(DistributorProducts::class)->getProductStockCount($product->getId());$product->setStockCount($stockCount[0][1]);// Get the lowest price$lowestPrice = $this->em->getRepository(DistributorProducts::class)->getLowestPrice($product->getId());$product->setUnitPrice($lowestPrice[0]['unitPrice'] ?? 0.00);$this->em->persist($product);$this->em->flush();// Availability Tracker$availabilityTracker = '';if($tracking){$availabilityTracker = $this->em->getRepository(AvailabilityTracker::class)->findBy(['product' => $product->getId(),'distributor' => $data['distributor'],'isSent' => 0,]);foreach($availabilityTracker as $tracker){$methodId = $tracker->getCommunication()->getCommunicationMethod()->getId();$sendTo = $tracker->getCommunication()->getSendTo();$product = $tracker->getProduct();// In app notificationsif($methodId == 1){$notifications = new Notifications();$notifications->setClinic($tracker->getClinic());$notifications->setIsRead(0);$notifications->setIsReadDistributor(0);$notifications->setIsActive(1);$notifications->setAvailabilityTracker($tracker);$this->em->persist($notifications);$this->em->flush();// Get the newly created notification$notification = '<table class="w-100"><tr><td><span class="badge bg-success me-3">New Stock</span></td><td>'. $product->getName() .' '. $product->getDosage() . $product->getUnit() .'</td><td><a href="#" class="delete-notification" data-notification-id="'. $notifications->getId() .'"><i class="fa-solid fa-xmark text-black-25 ms-3 float-end"></i></a></td></tr></table>';$notifications = $this->em->getRepository(Notifications::class)->find($notifications->getId());$notifications->setNotification($notification);$this->em->persist($notifications);$this->em->flush();// Email notifications} elseif($methodId == 2){$body = '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';$body .= '<tr><td colspan="2">'. $product->getName() .' '. $product->getDosage() . $product->getUnit() .' is back in stock</td></tr>';$body .= '<tr><td colspan="2"> </td></tr>';$body .= '<tr>';$body .= ' <td><b>Distributor: </b></td>';$body .= ' <td>'. $tracker->getDistributor()->getDistributorName() .'</td>';$body .= '</tr>';$body .= '<tr>';$body .= ' <td><b>Stock Level: </b></td>';$body .= ' <td>'. $tracker->getProduct()->getDistributorProducts()[0]->getStockCount() .'</td>';$body .= '</tr>';$body .= '</table>';$subject = 'Fluid Stock Level Update';$to = $sendTo;exec(__DIR__ . '/../../bin/console app:send-email "'. $subject .'" "'. addslashes($body) .'" "'. $to .'" "" "" "'. true .'" > /dev/null 2>&1 &');// Text notifications} elseif($methodId == 3){}$availabilityTracker = $this->em->getRepository(AvailabilityTracker::class)->find($tracker->getId());$availabilityTracker->setIsSent(1);$this->em->persist($availabilityTracker);$this->em->flush();}}$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>';} else {$response['flash'] = 'An error occurred';}return new JsonResponse($response);}#[Route('/distributors/get/refresh-token', name: 'distributor_get_access_token')]public function distributorGetRefreshTokenAction(Request $request): Response{$id = $this->getUser()->getDistributor()->getId();$button = false;$token = false;$error = false;if($id == null){return $this->render('security/login.html.twig', ['last_username' => '','error' => '','csrf_token_intention' => 'authenticate','user_type' => 'distributors',]);}$api = $this->em->getRepository(ApiDetails::class)->findOneBy(['distributor' => $id,]);// Check client id & secret existif($api == null){$error = true;} else {$refreshTokens = $api->getRefreshTokens();if(count($refreshTokens) == 0){$button = true;} else {$token = true;}}return new JsonResponse(['token' => $token,'button' => $button,'error' => $error]);}#[Route('/distributors/zoho/set/refresh-token', name: 'zoho_set_refresh_token')]public function setZohoRefreshTokenAction(Request $request): Response{$distributorId = $this->getUser()->getDistributor()->getId();$apiDetails = $this->em->getRepository(ApiDetails::class)->findOneBy(['distributor' => $distributorId,]);$code = $request->query->get('code');$error = $request->query->get('error');if($code != null) {$curl = curl_init();$clientId = $this->encryptor->decrypt($apiDetails->getClientId());$clientSecret = $this->encryptor->decrypt($apiDetails->getClientSecret());$endpoint = 'https://accounts.zoho.com/oauth/v2/token?code=' . $code . '&client_id=' . $clientId . '&';$endpoint .= 'client_secret=' . $clientSecret . '&redirect_uri='. $this->getParameter('app.base_url') .'/distributors/zoho/set/refresh-token&';$endpoint .= 'grant_type=authorization_code';curl_setopt_array($curl, [CURLOPT_URL => $endpoint,CURLOPT_RETURNTRANSFER => true,CURLOPT_ENCODING => '',CURLOPT_MAXREDIRS => 10,CURLOPT_TIMEOUT => 0,CURLOPT_FOLLOWLOCATION => true,CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,CURLOPT_CUSTOMREQUEST => 'POST']);$json = curl_exec($curl);curl_close($curl);$response = json_decode($json, true);if(array_key_exists('refresh_token', $response)){$session = $this->requestStack->getSession();$session->set('accessToken', $response['access_token']);$session->set('refreshToken', $response['refresh_token']);$refreshToken = new RefreshTokens();$api = $this->getUser()->getDistributor()->getApiDetails();$refreshToken->setToken($response['refresh_token']);$refreshToken->setApiDetails($api);$this->em->persist($refreshToken);$this->em->flush();return $this->redirectToRoute('distributor_manage_inventory');} elseif(array_key_exists('error', $response)){echo $response['error'];}} elseif($error != null){echo $error;file_put_contents(__DIR__ . '/../../public/zoho.log', date('Y-m-d H:i:s') .': '. $error . "\n", FILE_APPEND);}return new JsonResponse('');}#[Route('/admin/get/distributors/list', name: 'admin_get_distributors_list')]public function adminGetDistributorsList(Request $request): Response{$status = (int) $request->request->get('status');$distributors = $this->em->getRepository(Distributors::class)->adminFindAll($status);$results = $this->pageManager->paginate($distributors[0], $request, self::ITEMS_PER_PAGE);$dataAction = 'data-action="click->admin--distributors#onClickGetList"';$pagination = $this->getPagination($request->get('page_id'), $results, $dataAction, self::ITEMS_PER_PAGE);$response = $this->render('Admin/distributors/distributors_list.html.twig', ['distributors' => $results,'pagination' => $pagination,])->getContent();return new JsonResponse($response);}#[Route('/admin/get/distributor/form', name: 'admin_get_distributor_form')]public function adminGetDistributorForm(Request $request): Response{$distributorId = $request->request->get('distributor-id') ?? 0;$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);$distributorUsers = $this->em->getRepository(DistributorUsers::class)->findBy(['distributor' => $distributorId]);$userPermissions = $this->em->getRepository(UserPermissions::class)->findBy(['isDistributor' => 1]);$api = $this->em->getRepository(Api::class)->findAll();$countries = $this->em->getRepository(Countries::class)->findBy(['isActive' => true,]);$distributorProducts = $this->getDistributorInventory(1, $distributorId, 0, 0, $request);$response = $this->render('Admin/distributors/distributors.html.twig', ['distributor' => $distributor,'distributorUsers' => $distributorUsers,'userPermissions' => $userPermissions,'api' => $api,'countries' => $countries,'distributorProducts' => $distributorProducts,])->getContent();return new JsonResponse($response);}#[Route('/admin/approve/distributor', name: 'admin_approve_distributor')]public function adminApproveDistributor(Request $request): Response{$distributorId = $request->request->get('distributor-id');$isApproved = $request->request->get('is-approved');$distributor = $this->em->getRepository(Distributors::class)->find($distributorId);if($distributor != null){if($isApproved == 1 || $isApproved == 0){$isApproved = 2;}else if($isApproved == 2){$isApproved = 1;}$distributor->setIsApproved($isApproved);$this->em->persist($distributor);$this->em->flush();}return new JsonResponse('');}#[Route('/admin/get-distributor-products', name: 'admin_get_distributor_products')]public function distributorInventory(Request $request): Response{$pageId = $request->request->get('page-id');$distributorId = $request->request->get('distributor-id');$manufacturerId = $request->request->get('manufacturer-id');$speciesId = $request->request->get('species-id');$response = $this->getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request);return new JsonResponse($response);}#[Route('/admin/save-scraper-frequency', name: 'admin_save_scraper_frequency')]public function saveScraperFrequency(Request $request): Response{$name = $request->request->get('name');$cron = $request->request->get('cron');$status = (int) $request->request->get('status');$scraperUrlId = $request->request->get('scraper-url-id');$frequency = $request->request->get('frequency');$scraperUrl = $this->em->getRepository(ScraperUrls::class)->find($scraperUrlId);if($scraperUrl == null){$response = ['flash' => 'Please first save the scraper url.','type' => 'danger'];return new JsonResponse($response);}$cronJob = $this->em->getRepository(CronJob::class)->findOneBy(['scraperUrl' => $scraperUrl->getId(),]);if($cronJob == null){$cronJob = new CronJob();}$cronJob->setName($name);$cronJob->setExpression($cron);$cronJob->setCommand($scraperUrl->getDistributor()->getScraperAunthentication()->getCommand());$cronJob->setActive($status);$cronJob->setScraperUrl($scraperUrl);$cronJob->setFrequency($frequency);$cronJob->setDescription($this->getCronDescription($cron, $frequency));$this->em->persist($cronJob);$this->em->flush();$response = ['flash' => 'Schedule saved successfully.','type' => 'success'];return new JsonResponse($response);}public function getCronDescription($cron, $frequency): string{$description = '';// Dailyif(strtolower($frequency) == 'daily'){$pieces = explode(' ', $cron);$hour = $pieces[1];$timeOfDay = 'pm';if($hour >= 0 and $hour < 12){$timeOfDay = 'am';}$description = 'Every day at '. $hour . $timeOfDay;}// Weeklyif(strtolower($frequency) == 'weekly'){$pieces = explode(' ', $cron);$hour = $pieces[1];$day = (int) $pieces[4];$timeOfDay = 'pm';if($hour >= 0 and $hour < 12){$timeOfDay = 'am';}$date = new \DateTime();$date->setISODate(date('Y'), 1, $day);$day = $date->format('l');$description = 'Every '. $day .' at '. $hour . $timeOfDay;}// Monthlyif(strtolower($frequency) == 'monthly'){$pieces = explode(' ', $cron);$hour = $pieces[1];$day = $pieces[2];$timeOfDay = 'pm';if($hour >= 0 and $hour < 12){$timeOfDay = 'am';}$description = 'At '. $hour . $timeOfDay .' on day '. $day .' of the month';}return $description;}public function getDistributorInventory($pageId, $distributorId, $manufacturerId, $speciesId, $request){$dataAction = 'data-action="click->admin--distributors#onClickPagination"';$distributorProductsRepo = $this->em->getRepository(AiProducts::class)->findByManufacturer($distributorId,$manufacturerId,$speciesId);$distributorProducts = $this->pageManager->paginate($distributorProductsRepo[0], $request, self::ITEMS_PER_PAGE);$distributorProductsPagination = $this->getAjaxPagination($pageId, $distributorProducts, $distributorId, $dataAction);$species = $this->em->getRepository(AiProductsSpecies::class)->adminFindByDistributorProducts($distributorId);return $this->render('Admin/distributors/distributor_products.html.twig', ['species' => $species,'speciesId' => $speciesId,'distributorProducts' => $distributorProducts,'pagination' => $distributorProductsPagination,])->getContent();}public function getPagination($currentPage, $results, $dataAction = '', $itemsPerPage = 10): string{return $this->render('pagination.html.twig', ['currentPage' => $currentPage,'results' => $results,'dataAction' => $dataAction,'itemsPerPage' => $itemsPerPage,'lastPage' => $this->pageManager->lastPage($results),'totalPages' => ceil(count($results) / $itemsPerPage),'i' => max(1, $currentPage - 5),'forLimit' => min($currentPage + 5, ceil(count($results) / $itemsPerPage)),])->getContent();}public function getAjaxPagination($pageId, $results, $url, $dataAction = '', $itemsPerPage = 10): string{$currentPage = $pageId;$totalPages = ceil(count($results) / $itemsPerPage);$limit = 5;$lastPage = $this->pageManager->lastPage($results);$pagination = '';if(count($results) > 0){$pagination .= '<!-- Pagination --><div class="row mt-3"><div class="col-12">';if ($lastPage > 1){$previousPageNo = $currentPage - 1;$previousPage = $url . $previousPageNo;$pagination .= '<nav class="custom-pagination"><ul class="pagination justify-content-center">';$disabled = 'disabled';$dataDisabled = 'true';// Previous Linkif ($currentPage > 1){$disabled = '';$dataDisabled = 'false';}if ($totalPages >= 1 && $pageId <= $totalPages && $currentPage != 1){$pagination .= '<li class="page-item ' . $disabled . '"><aclass="address-pagination"aria-disabled="' . $dataDisabled . '"data-page-id="' . $currentPage - 1 . '"href="#"' . $dataAction . '><span aria-hidden="true">«</span> <span class="d-none d-sm-inline">Previous</span></a></li><li class="page-item "><aclass="address-pagination"data-page-id="1"href="#"'. $dataAction .'>First</a></li>';}$i = max(1, $currentPage - $limit);$forLimit = min($currentPage + $limit, $totalPages);$isActive = false;for (; $i <= $forLimit; $i++){$active = '';if ($i == (int)$currentPage) {$active = 'active';$isActive = true;}// Go to previous page if all records for a page have been deletedif (!$isActive && $i == count($results)) {$active = 'active';}$pagination .= '<li class="page-item ' . $active . '"><aclass="address-pagination"data-page-id="' . $i . '"href="#"' . $dataAction . '>' . $i . '</a></li>';}$disabled = 'disabled';$dataDisabled = 'true';if ($currentPage < $lastPage) {$disabled = '';$dataDisabled = 'false';}if ($currentPage < $lastPage){$pagination .= '<li class="page-item "><aclass="address-pagination"data-page-id="'. $lastPage .'"href="#"'. $dataAction .'>Last</a></li><li class="page-item ' . $disabled . '"><aclass="address-pagination"aria-disabled="' . $dataDisabled . '"data-page-id="' . $currentPage + 1 . '"href="#"'. $dataAction .'><span class="d-none d-sm-inline">Next</span> <span aria-hidden="true">»</span></a></li>';}$pagination .= '</ul></nav><input type="hidden" id="page_no" value="' . $currentPage . '"></div>';}}return $pagination;}}