<?php
namespace App\Controller;
use App\Entity\Category;
use App\Entity\Product;
use App\Entity\ProductAvailability;
use App\Entity\ProductConnection;
use App\Entity\Provider;
use App\Integration\InSalesIntegration;
use App\Service\PriceCalculatorService;
use App\Service\ProductService;
use Doctrine\Persistence\ManagerRegistry;
use Knp\Component\Pager\PaginatorInterface;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xls;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Annotation\Route;
class ProductController extends AbstractController
{
/**
* @Route("/product", name="product_list")
* @param Request $request
* @return Response
*/
public function index(Request $request, ManagerRegistry $managerRegistry, PaginatorInterface $paginator, ProductService $productService) {
$chosenCategoryId = $request->get('c');
$filterProviderId = $request->get('provider');
$filterName = $request->get('name', '');
$filterProviderArticle = $request->get('provider_sku', '');
$filterSiteArticle = $request->get('site_sku', '');
$filterProviderAvailability = $request->get('availability', '');
$filterSiteConnection = $request->get('connected', '');
$filterBrand = $request->get('brand', '');
$selectedProvider = $managerRegistry->getRepository(Provider::class)->findOneBy(['id' => $filterProviderId]);
$qb = $managerRegistry->getRepository(Product::class)->createQueryBuilder('p')
->join(ProductAvailability::class, 'av', 'WITH', 'av.product = p')
->leftJoin(ProductConnection::class, 'cn', 'WITH', 'cn.product = p')
->orderBy('p.id', 'DESC');
if (!empty(trim($filterBrand))) {
$qb->andWhere('av.brand = :brand')
->setParameter('brand', trim($filterBrand));
}
if ($selectedProvider instanceof Provider) {
$qb->andWhere('av.provider = :provider')
->setParameter('provider', $selectedProvider);
}
if (($filterName = trim($filterName)) != '') {
$qb->andWhere('av.providerName LIKE :filterName OR av.providerPartNumber LIKE :filterName')
->setParameter('filterName', "%$filterName%");
}
if (($filterProviderArticle = trim($filterProviderArticle)) != '') {
$qb->andWhere('av.providerArticle LIKE :providerArticle')
->setParameter('providerArticle', "%$filterProviderArticle%");
}
if (($filterSiteArticle = trim($filterSiteArticle)) != '') {
$qb->andWhere('cn.insalesSku LIKE :siteArticle')
->setParameter('siteArticle', "%$filterSiteArticle%");
}
if ($filterProviderAvailability == '1') {
$qb->andWhere('av.stock > 0');
} elseif ($filterProviderAvailability == '0') {
$qb->andWhere('av.stock <= 0');
}
if ($filterSiteConnection == '1') {
$qb->andWhere('cn IS NOT NULL');
} elseif ($filterSiteConnection == '0') {
$qb->andWhere('cn IS NULL');
}
$brands = $productService->getAllBrands();
$providers = $managerRegistry->getRepository(Provider::class)->findAll();
$categories = [];
$chosenCategory = $managerRegistry->getRepository(Category::class)->findOneBy(['id' => $chosenCategoryId]);
if ($selectedProvider instanceof Provider) {
if (!empty($chosenCategoryId)) {
$categories = $managerRegistry->getRepository(Category::class)->findBy(['provider' => $selectedProvider, 'parent' => $chosenCategoryId], ['name' => 'ASC']);
} else {
$categories = $managerRegistry->getRepository(Category::class)->findBy(['provider' => $selectedProvider, 'parent' => null], ['name' => 'ASC']);
}
}
if ($chosenCategory instanceof Category) {
$children = $managerRegistry->getRepository(Category::class)->getAllChildrenId($chosenCategory->getId());
$qb->andWhere('av.category = :category OR av.category IN (:children)')
->setParameter('category', $chosenCategory)
->setParameter('children', $children);
}
$pagination = $paginator->paginate(
$qb->getQuery(),
$request->query->getInt('page', 1),
100
);
$pagination->setTemplate('@KnpPaginator/Pagination/bootstrap_v5_pagination.html.twig');
return $this->render('product/list.html.twig', [
'pagination' => $pagination,
'brands' => $brands,
'providers' => $providers,
'selectedProvider' => $selectedProvider,
'children' => $categories,
'chosenCategory' => $chosenCategory
]);
}
/**
* @Route("/product/exportSelected", name="product_export_selected")
* @param Request $request
* @param SessionInterface $session
* @param ManagerRegistry $managerRegistry
* @param PriceCalculatorService $priceCalculatorService
* @return Response
*/
public function exportSelectedToExcel(Request $request, SessionInterface $session, ManagerRegistry $managerRegistry, PriceCalculatorService $priceCalculatorService) {
$selected = $session->get('selected', []);
$providerId = $request->get('provider_id');
$provider = $managerRegistry->getRepository(Provider::class)->findOneBy(['id' => $providerId]);
$data = [];
foreach ($selected as $productId) {
$product = $managerRegistry->getRepository(Product::class)->findOneBy(['id' => $productId]);
if ($provider instanceof Provider) {
$availability = $managerRegistry->getRepository(ProductAvailability::class)->findOneBy(['product' => $product, 'provider' => $provider]);
} else {
$availability = $priceCalculatorService->getOptimalAvailability($product);
}
$temp = [
'id' => $product->getId(),
'name' => $product->getName(),
'provider' => ($availability instanceof ProductAvailability ? $availability->getProvider()->getName() : ''),
'provider_article' => ($availability instanceof ProductAvailability ? $availability->getProviderArticle() : ''),
'provider_part_number' => ($availability instanceof ProductAvailability ? $availability->getProviderPartNumber() : ''),
'provider_name' => ($availability instanceof ProductAvailability ? $availability->getProviderName() : ''),
'provider_qty' => ($availability instanceof ProductAvailability ? $availability->getStock() : ''),
'input_price' => ($availability instanceof ProductAvailability ? $availability->getPriceRub() : ''),
'sale_price' => ($availability instanceof ProductAvailability ? $availability->getPriceSale() : ''),
'final_price' => ''
];
if ($availability instanceof ProductAvailability) {
$temp['final_price'] = $priceCalculatorService->calculatePriceForAvailability($availability);
}
$data[] = $temp;
}
$spreadsheet = new Spreadsheet();
$activeSheet = $spreadsheet->getActiveSheet();
$headers = [
'id' => 'ID',
'name' => 'Наименование (в Provider)',
'provider' => 'Поставщик',
'provider_article' => 'Артикул у поставщика',
'provider_part_number' => 'Партномер',
'provider_name' => 'Наименование (у поставщика)',
'provider_qty' => 'Количество',
'input_price' => 'Цена вход',
'sale_price' => 'Цена продажи',
'final_price' => 'Финальная цена',
];
foreach ($headers as $slug => $name) {
$col = array_search($slug, array_keys($headers)) + 1;
$activeSheet->setCellValueByColumnAndRow($col, 1, $name);
$activeSheet->getStyleByColumnAndRow($col, 1)->getFont()->setBold(true);
$activeSheet->getColumnDimensionByColumn($col)->setAutoSize(true);
}
$row = 2;
foreach ($data as $item) {
foreach ($headers as $slug => $header) {
$col = array_search($slug, array_keys($headers)) + 1;
$activeSheet->setCellValueByColumnAndRow($col, $row, $item[$slug] ?? '');
}
$row ++;
}
$writer = new Xls($spreadsheet);
$response = new StreamedResponse(
function () use ($writer) {
$writer->save('php://output');
}
);
$response->headers->set('Content-Type', 'application/vnd.ms-excel');
$response->headers->set('Content-Disposition', 'attachment;filename="SelectedProducts.xls"');
$response->headers->set('Cache-Control','max-age=0');
return $response;
}
/**
* @Route("/product/removeAvailability/{id}", name="product_remove_availability")
* @param Request $request
* @param ProductAvailability $availability
* @param ManagerRegistry $managerRegistry
* @return void
*/
public function removeAvailability(Request $request, ProductAvailability $availability, ManagerRegistry $managerRegistry) {
$product = $availability->getProduct();
$managerRegistry->getManager()->remove($availability);
$managerRegistry->getManager()->flush();
return $this->redirectToRoute('product_view', ['id' => $product->getId()]);
}
/**
* @Route("/product/moveAvailability/{id}", name="product_move_availability")
* @param Request $request
* @param ProductAvailability $availability
* @param ManagerRegistry $managerRegistry
* @param FlashBagInterface $flashBag
* @return void
*/
public function moveAvailability(Request $request, ProductAvailability $availability, ManagerRegistry $managerRegistry, FlashBagInterface $flashBag) {
$to = $request->get('to');
$product = $managerRegistry->getRepository(Product::class)->findOneBy(['id' => $to]);
if ($product instanceof Product) {
$availability->setProduct($product);
$managerRegistry->getManager()->flush();
return $this->redirectToRoute('product_view', ['id' => $product->getId()]);
}
$flashBag->add('error', "Товар с ID $to не найден");
return $this->redirectToRoute('product_view', ['id' => $availability->getProduct()->getId()]);
}
/**
* @Route("/product/connect/{id}", name="product_connect")
*/
public function connect(Request $request, Product $product, InSalesIntegration $inSalesIntegration, ManagerRegistry $managerRegistry, FlashBagInterface $flashBag) {
$insalesProductId = $request->get('insales_product_id', '');
$insalesProductId = trim($insalesProductId);
if (!empty($insalesProductId)) {
$variants = $inSalesIntegration->getVariantsOfProduct($insalesProductId);
if (isset($variants[0])) {
$variant = $variants[0];
$connection = $product->getConnection();
if (!$connection instanceof ProductConnection) {
$connection = new ProductConnection();
$connection->setProduct($product);
$managerRegistry->getManager()->persist($connection);
}
$connection->setDateConnected(time());
$connection->setInsalesProductId($insalesProductId);
$connection->setInsalesVariantId($variant['id']);
$connection->setInsalesSku($variant['sku'] ?? 0);
$managerRegistry->getManager()->flush();
$flashBag->add('info', "Привязка к сайту добавлена");
} else {
$flashBag->add('error', "Не найдены варианты для товара с ID $insalesProductId");
}
} else {
$connection = $product->getConnection();
if ($connection instanceof ProductConnection) {
$managerRegistry->getManager()->remove($connection);
$managerRegistry->getManager()->flush();
$flashBag->add('warning', "Привязка к сайту удалена");
}
}
return $this->redirectToRoute('product_view', [
'id' => $product->getId()
]);
}
/**
* @Route("/product/view/{id}", name="product_view")
* @param Request $request
* @return Response
*/
public function view(Request $request, Product $product) {
return $this->render('product/view.html.twig', [
'product' => $product
]);
}
}