src/Controller/DistributorsController.php line 75
<?php
namespace 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 change
if(
!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 Email
if(!$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 .= "
<li
class=\"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 API
if($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 notifications
if($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 exist
if($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');
$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 = '';
// Daily
if(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;
}
// Weekly
if(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;
}
// Monthly
if(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 Link
if ($currentPage > 1)
{
$disabled = '';
$dataDisabled = 'false';
}
if ($totalPages >= 1 && $pageId <= $totalPages && $currentPage != 1)
{
$pagination .= '
<li class="page-item ' . $disabled . '">
<a
class="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 ">
<a
class="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 deleted
if (!$isActive && $i == count($results)) {
$active = 'active';
}
$pagination .= '
<li class="page-item ' . $active . '">
<a
class="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 ">
<a
class="address-pagination"
data-page-id="'. $lastPage .'"
href="#"
'. $dataAction .'
>
Last
</a>
</li>
<li class="page-item ' . $disabled . '">
<a
class="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;
}
}