<?php
namespace DcSiteBundle\Services;
use Application\Sonata\MediaBundle\Entity\GalleryItem;
use CoreBundle\Entity\Dealer;
use CoreBundle\Entity\Vehicles\ConfiguratorColor;
use CoreBundle\Entity\Vehicles\Equipment;
use CoreBundle\Entity\Vehicles\EquipmentOptions;
use CoreBundle\Entity\Vehicles\Faq;
use CoreBundle\Entity\Vehicles\RecommendGroup;
use CoreBundle\Entity\Vehicles\VariationCharacteristic;
use CoreBundle\Entity\Vehicles\Vehicle;
use CoreBundle\Entity\Vehicles\VehicleItem;
use CoreBundle\Factory\Vehicle as VehicleFactory;
use CoreBundle\Model\Vehicles\EquipmentOptions as EquipmentOptionsCoreModel;
use CoreBundle\Model\Vehicles\VehicleType;
use CoreBundle\Services\MediaExtensionVidi;
use DcSiteBundle\Entity\ServiceVariation;
use DcSiteBundle\Model\CreditModel;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class VehicleService
{
private EntityManagerInterface $em;
private MediaExtensionVidi $mediaExtension;
private RequestStack $requestStack;
private VehicleFactory $vehicleFactory;
private TranslatorInterface $translator;
private RouterInterface $router;
private CreditModel $creditModel;
public function __construct(EntityManagerInterface $em, MediaExtensionVidi $mediaExtension, RequestStack $requestStack,
VehicleFactory $vehicleFactory, TranslatorInterface $translator, RouterInterface $router,
CreditModel $creditModel)
{
$this->em = $em;
$this->mediaExtension = $mediaExtension;
$this->requestStack = $requestStack;
$this->vehicleFactory = $vehicleFactory;
$this->translator = $translator;
$this->router = $router;
$this->creditModel = $creditModel;
}
public function getVehicleModelLineup(Vehicle $vehicle)
{
return $this->em->getRepository(Faq::class)->getByVehicle($vehicle);
}
public function getVehiclePrice(Vehicle $vehicle): array
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$equipments = [];
$hasYears = [];
foreach ($vehicle->getEquipments() as $equipment) {
/** @var Equipment $equipment */
if (!$equipment->getState()) {
continue;
}
$sortPrice = $equipment->minPrice();
if ($sortPrice == 0) {
$sortPrice = Equipment::SORT_PRICE;
}
$equipments[] = [
'id' => $equipment->getId(),
'title' => $equipment->getTitle(),
'sortPrice' => $sortPrice,
'price' => $equipment->minPrice(),
'hasSpecifications' => [],
'isSpecifyPrice' => $equipment
];
}
usort($equipments, fn($a, $b) => $a['sortPrice'] <=> $b['sortPrice']);
$variations = [];
$specifications = [];
$hasPreOrder = false;
/** @var VehicleItem $vehicleItem */
foreach ($vehicle->getVehicleItems() as $vehicleItem) {
if (!$vehicleItem->getState()) {
continue;
}
if (!$vehicleItem->getEquipment()->getState()) {
continue;
}
$model = $this->vehicleFactory->createByVehicleItem($vehicleItem);
$specification = $vehicleItem->getSpecification();
$specId = $specification ? $specification->getId() : 'none';
$specTitle = $specification ? $specification->getTitle($locale) : $model->getModelName();
$specifications[$specId] = $specTitle;
$Variation = $vehicleItem->getVariation();
$Equipment = $vehicleItem->getEquipment();
if (!isset($variations[$Variation->getId()])) {
$capacity = (int)str_replace(' ', '', $model->getEngineVolume($locale));
$capacityUpd = $capacity > 50 ? round(($capacity / 1000), 1) : $capacity;
$capacityUpd = number_format($capacityUpd, 1, '.', ' ');
$variations[$Variation->getId()] = [
'id' => $Variation->getId(),
'capacity' => $capacityUpd,
'minPrice' => false,
'fuelType' => $model->getFuelTypeName($locale),
'fuelRateMixed' => $model->getFuelRateMixed(),
'power' => $model->getEnginePower($locale),
'generalMaxPower' => $model->getGeneralMaxPower($locale),
'drive' => $model->getDriveUnitTypeName($locale),
'transmission' => $model->getTransmissionTypeName($locale),
'hasPreorderYears' => [],
'hasSpecifications' => [],
'hasYears' => [],
'items' => [],
'turbo' => $model->hasTurbo(),
'title' => $model->getEquipment()->getTitle(),
'publicTitle' => $model->getVariationPublicTitle(),
];
}
$variations[$Variation->getId()]['hasSpecifications'][$specId] = $specId;
foreach ($equipments as &$eq) {
if ($eq['id'] == $Equipment->getId()) {
$eq['hasSpecifications'][$specId] = $specId;
}
}
if ($model->getPreorderPrice()) {
$hasPreOrder = true;
$variations[$Variation->getId()]['hasPreOrder'] = true;
$variations[$Variation->getId()]['hasPreorderYears'][] = $vehicleItem->getYear();
}
if (
!$variations[$Variation->getId()]['minPrice'] ||
$variations[$Variation->getId()]['minPrice'] > $model->fullPrice()
) {
$fullPrice = $model->fullPrice();
if ($fullPrice == 0) {
//TODO remove magic numbers
$fullPrice = 9999999999999;
}
$variations[$Variation->getId()]['minPrice'] = $fullPrice;
}
if (!in_array($vehicleItem->getYear(), $hasYears)) {
$hasYears[] = $vehicleItem->getYear();
}
if (!in_array($vehicleItem->getYear(), $variations[$Variation->getId()]['hasYears'])) {
$variations[$Variation->getId()]['hasYears'][] = $vehicleItem->getYear();
}
$variations[$Variation->getId()]['items'][$Equipment->getId()][$specId][$vehicleItem->getId()] = [
'price' => $model->price(),
'year' => $vehicleItem->getYear(),
'fullPrice' => $model->fullPrice(),
'preOrderPrice' => $model->getPreorderPrice(),
'specification' => $specId,
'isSpecifyPrice' => $vehicleItem->getSpecifyPrice(),
];
}
usort($variations, fn($a, $b) => $a['minPrice'] <=> $b['minPrice']);
$sortedSpecification = [];
foreach ($specifications as $id => $title) {
$sortedSpecification[] = [
'id' => $id,
'title' => $title,
];
}
sort($hasYears);
$price = [
'specifications' => $sortedSpecification,
'equipments' => $equipments,
'variations' => $variations,
'hasPreOrder' => $hasPreOrder,
'hasYears' => $hasYears,
];
return $price;
}
public function getVehicleEquipment(Vehicle $vehicle): array
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$equipments = [];
$equipmentOptions = [];
/** @var Equipment $equipment */
foreach ($vehicle->getEquipments() as $equipment) {
if (!$equipment->getState()) {
continue;
}
$sortPrice = $equipment->minPrice();
if ($sortPrice == 0) {
$sortPrice = Equipment::SORT_PRICE;
}
$equipments[] = [
'id' => $equipment->getId(),
'title' => $equipment->getTitle(),
'sortPrice' => $sortPrice,
'price' => $equipment->minPrice(),
'fullPrice' => $equipment->minFullPrice(),
'preOrderPrice' => $equipment->minPreOrderPrice(),
];
$equipmentOptions = $this->getVehicleEquipmentOption($equipment, $locale, $equipmentOptions);
}
usort($equipments, fn($a, $b) => $a['sortPrice'] <=> $b['sortPrice']);
return ['equipments' => $equipments, 'equipmentOptions' => $equipmentOptions];
}
public function getVehicleEquipmentOption(Equipment $equipment, $locale, $equipmentOptions = [])
{
/** @var EquipmentOptions $option */
foreach ($equipment->getOptions() as $option) {
$oneOption = $option->getOption();
$oType = $option->getOption()->getOptionType();
if (!isset($equipmentOptions[$oType])) {
$equipmentOptions[$oType] = [
'id' => $oType,
'title' => EquipmentOptionsCoreModel::getTypeName($oType, $locale),
'options' => []
];
}
if (!isset($equipmentOptions[$oType]['options'][$oneOption->getId()])) {
$equipmentOptions[$oType]['options'][$oneOption->getId()] = [
'id' => $oneOption->getId(),
'title' => $oneOption->getTitle($locale),
'values' => []
];
}
$currentOptionValue = '';
if (isset($equipmentOptions[$oType]['options'][$oneOption->getId()]['values'][$equipment->getId()])) {
$currentOptionValue = $equipmentOptions[$oType]['options'][$oneOption->getId()]['values'][$equipment->getId()]['value'];
}
if ($currentOptionValue) {
$currentOptionValue .= ', ' . $option->getValue($locale);
} else {
$currentOptionValue = $option->getValue($locale);
}
$hasOption = $option->getOption();
$hasValue = $hasOption->getHasValue();
$equipmentOptions[$oType]['options'][$oneOption->getId()]['values'][$equipment->getId()] = [
'price' => $option->price(),
'value' => $currentOptionValue,
'optional' => $option->getIsOptional() > 0,
'hasValue' => $hasValue
];
}
return $equipmentOptions;
}
public function getVehicleEquipmentVariation(Equipment $equipment, $locale)
{
$rateInDelivery = $equipment->getVehicle()->getDealer()->getRateInDelivery();
$equipmentVariation = [];
/** @var VehicleItem $vehicleItem */
foreach ($equipment->getVehicleItems() as $vehicleItem)
{
if(!$vehicleItem->getState()){
continue;
}
$vehicleModel = $this->vehicleFactory->createByVehicleItem($vehicleItem);
$capacity = (int)str_replace(' ', '', $vehicleModel ->getEngineVolume($locale));
$capacityUpd = $capacity > 50 ? round(($capacity / 1000), 1) : $capacity;
$capacityUpd = number_format($capacityUpd, 1, '.', ' ');
$equipmentVariation[$vehicleItem->getId()] = [
'id' => $vehicleItem->getId(),
'title' => $vehicleModel->getEquipment()->getTitle(),
'capacity' => $capacityUpd,
'price' => number_format($vehicleItem->getPrice(), '0','',' '),
'minPrice' => $vehicleItem->calcPrice(),
'preorderPrice' => number_format($vehicleItem->getPreorderPrice() * $rateInDelivery,'0','',' '),
'year' => $vehicleItem->getYear(),
'fuelType' => $vehicleModel ->getFuelTypeName($locale),
'fuelRateMixed' => $vehicleModel ->getFuelRateMixed(),
'enginePower' => $vehicleModel ->getEnginePower($locale),
'driveType' => $vehicleModel ->getDriveUnitTypeName($locale),
'transmissionType' => $vehicleModel ->getTransmissionTypeName($locale),
'specificationTitle' => ($vehicleItem->getSpecification()) ? $vehicleItem->getSpecification()->getTitle($locale) : null,
];
}
usort($equipmentVariation, fn($a, $b) => $a['price'] <=> $b['price']);
return $equipmentVariation;
}
public function getCompareVehicleEquipment(Vehicle $vehicle, $urlParams = null)
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$vehicleComparison = $this->getVehicleComparison();
$compare = [];
/** @var VehicleItem $vehicleItem */
foreach ($vehicle->getVehicleItems() as $vehicleItem) {
if(!$vehicleItem->getState()){
continue;
}
$model = $this->vehicleFactory->createByVehicleItem($vehicleItem);
$options = [];
$optionsByEquipment = $model->getOptionsByEquipment($vehicleItem->getEquipment(), $locale, true);
foreach ($optionsByEquipment as $group) {
foreach ($group['options'] as $option){
$options[] = $option;
}
}
$link = $this->router->generate($urlParams['routeName'], array_merge($urlParams['params'], ['variation' => $vehicleItem->getId()]));
$linkCatalogInStock = $this->router->generate('portal_in_stock_catalog', ['brand' => [$model->getBrand()->getUrl()], 'model' => [$model->getModel()->getUrl()]]);
$compare[] =
[
'equipment' => [
'id' => $model->getEquipment()->getId(),
'title' => $model->getEquipmentTitle(),
],
'fuelType' => [
'id' => $model->getFuelType()->getId(),
'title' => $model->getFuelTypeName($locale),
],
'driveUnit' => [
'id' => $model->getDriveUnitType()->getId(),
'title' => $model->getDriveUnitTypeName($locale),
],
'transmissionType' => [
'id' => $model->getTransmissionType()->getId(),
'title' => $model->getTransmissionTypeName($locale),
],
'enginPower' => [
'id' => (int)$model->getEnginePower($locale),
'title' => $model->getEnginePower($locale),
],
'enginVolume' => round((int)$model->getEngineVolume($locale) / 1000, 2),
'state' => $vehicleItem->getState(),
'hasInStock' => $model->hasInStock(),
'creditPayment' => $this->creditModel->getMinPayment($model),
'altPrice' => $vehicleItem->getAltPrice(),
'price' => $model->price(),
'fullPrice' => $model->fullPrice(),
'hasActionPrice' => $model->hasActionPrice(),
'options' => $options,
'link' => $link,
'linkCatalogInStock' => $linkCatalogInStock,
'vehicleItemId' => $vehicleItem->getId(),
'isComparison' => in_array($vehicleItem->getId(), $vehicleComparison),
];
}
return $compare;
}
public function getVehicleComparison()
{
$request = $this->requestStack->getCurrentRequest();
$compareCookie = $request->cookies->get('compare');
$vehicleItemIds = explode(',', $compareCookie);
return $vehicleItemIds;
}
public function getVehicleColor(Vehicle $vehicle)
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$colors = [];
/** @var ConfiguratorColor $color */
$vehicleType = VehicleType::getTypeDataById($vehicle->getVehicleType());
$vehicleType['title'] = $this->translator->trans('modules.colors.vehicle_type_your_color_' . $vehicleType['url'], [], 'dc_base');
foreach ($vehicle->getColors() as $color) {
if (!$color->getState()) {
continue;
}
$gallery = $color->getGallery();
if (!$gallery) {
continue;
}
$galleryItems = $gallery->getGalleryItems();
if (!$galleryItems->count()) {
continue;
}
$colors[] = [
'title' => $color->getName($locale),
'price' => $color->calcPrice(),
'preview' => $this->mediaExtension->getPath($color->getImage(), 'reference'),
'image' => $this->mediaExtension->getPath($galleryItems->first()->getMedia(), 'reference')
];
}
return ['vehicleType' => $vehicleType, 'colors' => $colors];
}
public function getVehicleTechnicalCharacteristic(Vehicle $vehicle)
{
$request = $this->requestStack->getCurrentRequest();
$tech = [];
$engines = [];
/** @var VehicleItem $vehicleItem */
foreach ($vehicle->getVehicleItems() as $vehicleItem) {
$model = $this->vehicleFactory->createByVehicleItem($vehicleItem);
$variation = $vehicleItem->getVariation();
if(!$variation->getState()) {
continue;
}
$engines[$variation->getId()] = [
'id' => $variation->getId(),
'vehicleItemId' => $vehicleItem->getId(),
'title' => $model->getEngineName($request->getLocale()),
'transmissionType' => $model->getTransmissionTypeName($request->getLocale()),
'fuelVolume' => $model->getFuelVolume($request->getLocale()),
'fuelType' => $model->getFuelTypeName($request->getLocale()),
'driveUnitType' => $model->getDriveUnitTypeName($request->getLocale())
];
/** @var VariationCharacteristic $vCharacteristic */
foreach ($variation->getCharacteristics() as $vCharacteristic) {
$Characteristic = $vCharacteristic->getCharacteristic();
if (!isset($tech[$Characteristic->getId()])) {
$tech[$Characteristic->getId()] = [
'id' => $Characteristic->getId(),
'title' => $Characteristic->getTitle($request->getLocale()),
'groupId' => $Characteristic->getGroup() ? $Characteristic->getGroup()->getId() : 9999,
'items' => [],
];
}
$tech[$Characteristic->getId()]['items'][$variation->getId()] = $vCharacteristic->getValue($request->getLocale());
}
}
$withGroups = $request->get('withGroups');
$sortedTech = [];
if ($withGroups) {
foreach ($tech as $row) {
foreach ($row['items'] as $k => $item) {
if (!$item) {
unset($row['items'][$k]);
}
}
if (!$row['items']) {
continue;
}
$sortedTech[$row['groupId']][] = $row;
}
ksort($sortedTech);
} else {
foreach ($tech as $row) {
$sortedTech[] = $row;
}
foreach ($sortedTech as $key => $t) {
$hasValue = false;
foreach ($t['items'] as $i) {
if ($i) {
$hasValue = true;
}
}
if (!$hasValue) {
unset($sortedTech[$key]);
}
}
usort($sortedTech, fn($prev, $next) => $prev['id'] <=> $next['id']);
}
$sortedEngines = [];
foreach ($engines as $row) {
$sortedEngines[] = $row;
}
$groups = [];
if ($withGroups) {
$groupModels = $this->em->getRepository(\CoreBundle\Entity\Vehicles\CharacteristicGroup::class)->findAll();
foreach ($groupModels as $group) {
$groups[$group->getId()] = $group->getTitle($request->getLocale());
}
$groups[9999] = 'Загальні';
if ($request->getLocale() == 'ru') {
$groups[9999] = 'Общие';
}
}
return [
'success' => true,
'engines' => $sortedEngines,
'tech' => $sortedTech,
'groups' => $groups
];
}
public function getVehicleCharacteristic(Vehicle $vehicle)
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$tech = [];
$engines = [];
/** @var VehicleItem $vehicleItem */
foreach ($vehicle->getVehicleItems() as $vehicleItem) {
$model = $this->vehicleFactory->createByVehicleItem($vehicleItem);
$variation = $vehicleItem->getVariation();
if (!$variation->getState()) {
continue;
}
// TODO remove this Костыль для Королы в ТТХ
$transmission = '';
if ($model->getModel()->getTitle() === 'COROLLA') {
switch ($model->getTransmissionType()->getId()) {
case 17:
$transmission = 'CVT';
break;
case 5:
$transmission = 'M/T';
break;
}
}
$engines[$variation->getId()] = [
'id' => $variation->getId(),
'title' => $model->getEngineName($locale) . ' ' . $transmission,
];
/** @var VariationCharacteristic $vCharacteristic */
foreach ($variation->getCharacteristics() as $vCharacteristic) {
$Characteristic = $vCharacteristic->getCharacteristic();
if (!isset($tech[$Characteristic->getId()])) {
$tech[$Characteristic->getId()] = [
'title' => $Characteristic->getTitle($locale),
//TODO remove magic numbers
'groupId' => $Characteristic->getGroup() ? $Characteristic->getGroup()->getId() : 9999,
'items' => [],
];
}
$tech[$Characteristic->getId()]['items'][$variation->getId()] =
$vCharacteristic->getValue($locale);
}
}
$sortedTech = [];
foreach ($tech as $row) {
foreach ($row['items'] as $k => $item) {
if (!$item) {
unset($row['items'][$k]);
}
}
if (!$row['items']) {
continue;
}
$sortedTech[$row['groupId']][] = $row;
}
$sortedEngines = [];
foreach ($engines as $row) {
$sortedEngines[] = $row;
}
ksort($sortedTech);
$groupModels = $this->em->getRepository(\CoreBundle\Entity\Vehicles\CharacteristicGroup::class)->findAll();
$groups = [];
foreach ($groupModels as $group) {
$groups[$group->getId()] = $group->getTitle($locale);
}
return
[
'engines' => $sortedEngines,
'tech' => $sortedTech,
'groups' => $groups
];
}
public function getVehicleFaqs(Vehicle $vehicle)
{
return $this->em->getRepository(Faq::class)->getByVehicle($vehicle);
}
public function getModelsForRegulationsTo(Dealer $dealer, $brandId = null)
{
$brandId ??= $dealer->getBrand()->getId();
$variations = $this->em->getRepository(ServiceVariation::class)->getRegulationVariations($dealer, $brandId);
$models = [];
/** @var ServiceVariation $variation */
foreach ($variations as $variation) {
$Model = $variation->getModel();
if (!isset($models[$Model->getId()])) {
$modelImage = $Model->getImage();
if ($modelImage) {
$img = $this->mediaExtension->getPath($modelImage, 'small');
$imgWebp = $this->mediaExtension->pathWebp($modelImage, 'small');
} else {
$vehicle = $this->em->getRepository(Vehicle::class)->findOneBy(['dealer' => $dealer, 'model' => $Model, 'state' => 1, 'is_used' => 0]);
$img = ($vehicle) ? $this->mediaExtension->getPath($vehicle->getPreview(), 'small') : $this->mediaExtension->getPath($Model->getBrand()->getLogo(), 'reference');
$imgWebp = ($vehicle) ? $this->mediaExtension->pathWebp($vehicle->getPreview(), 'small') : $this->mediaExtension->pathWebp($Model->getBrand()->getLogo(), 'reference');
}
$models[$Model->getId()] = [
'id' => $Model->getId(),
'title' => $Model->getTitle(),
'img' => $img,
'img_webp' => $imgWebp,
'url' => $Model->getUrl(),
];
}
}
usort($models, fn($item1, $item2) => $item1['title'] <=> $item2['title']);
return $models;
}
public function getRecommendGroup($state = false, $state_slider = false, $sort = false)
{
$recommendGroup = $this->em->getRepository(RecommendGroup::class)->findRecommendGroup($state, $state_slider);
if ($sort) {
foreach ($recommendGroup as $key => $item) {
$position[$key] = $item->getPosition() ?: 999999;
}
array_multisort($position, SORT_ASC, $recommendGroup);
}
return $recommendGroup;
}
public function getVehicleFile(Vehicle $vehicle)
{
$files = [];
foreach ($vehicle->getFiles() as $row) {
$files[] = [
'files' => $row,
'position' => $row->getPosition(),
];
}
usort($files, fn($a, $b) => $a['position'] <=> $b['position']);
return $files;
}
public function addViews(Vehicle $vehicle)
{
$vehicle->setViews((int)$vehicle->getViews() + 1);
$this->em->persist($vehicle);
$this->em->flush();
}
public function getVehiclePriceEquipment(Vehicle $vehicle)
{
$request = $this->requestStack->getCurrentRequest();
$locale = $request->getLocale();
$rateInDelivery = $vehicle->getDealer()->getRateInDelivery();
$priceEquipment = [];
/** @var GalleryItem $galleryItem */
$galleryItem = $vehicle->getGallery()->getGalleryItems()->first();
$image = $this->mediaExtension->getPath($galleryItem->getMedia(), 'small');
/** @var Equipment $equipment */
foreach ($vehicle->getEquipments() as $equipment) {
$variations = $this->getVehicleEquipmentVariation($equipment, $locale);
$options = $this->getVehicleEquipmentOption($equipment, $locale);
if(!$variations){
continue;
}
$priceEquipment[$equipment->getId()] = [
'id' => $equipment->getId(),
'image' => $image,
'title' => $equipment->getTitle(),
'minPrice' => number_format($equipment->minPrice(),'0','',' '),
'minPreOrderPrice' => number_format($equipment->minPreOrderPrice() * $rateInDelivery,'0','',' '),
'variations' => $variations,
'options' => $options,
'position' => $equipment->getPosition(),
];
}
return $priceEquipment;
}
private function checkPricesCars($data, $id)
{
return array_key_exists($id, $data) ? true : false;
}
}