<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use App\Entity\PriceList;
use App\Entity\Price;
use App\Entity\Product;
use App\Entity\ProductArca;
use App\Entity\ProductPS;
use Psr\Log\LoggerInterface;
use App\AppUtils\PrezziDaAggiornare;
#[Route('/pricelist')]
class PriceListController extends AbstractController
{
private $request;
private $session;
private $em;
private $logger;
public function __construct(RequestStack $rS, ManagerRegistry $doctrine, LoggerInterface $logger){
$this->request=$rS->getCurrentRequest();
$this->session=$rS->getSession();
$this->em=$doctrine->getManager();
$this->logger=$logger;
}
#[Route('/', name: 'price_list_index')]
public function index($optParams=null): Response
{
//nel caso i parametri opzionali non siano già stati passati nella chiamata del metodo, provo a ricavarli dalla request POST
if ($optParams == null){
$optParams=[]; //arrayvuoto
$optParams['tipoUscita'] = $this->request->get('tipoUscita');
$this->logger->info("tipoUscita: {$optParams['tipoUscita']} letto dal POST");
} else {}
$output=[]; //contenitore per uscite della response
if ( isset($optParams) && is_array($optParams) ){
$possibiliTipiUscita=['json','array','template'];
//controllo se il tipoUscita è definito ed è appartenente ai tipi permessi
if ( isset($optParams['tipoUscita']) && is_string($optParams['tipoUscita']) && in_array($optParams['tipoUscita'],$possibiliTipiUscita) ){
$tipoUscita = $optParams['tipoUscita'];
} else {
$output['warning']="tipoUscita definito {$optParams['tipoUscita']} , ma non valido";
$tipoUscita = 'json';
}
}
else {
$tipoUscita = 'json';
}
$esplosoListino=[]; //contenitore per l'esplosione del listino
//prelevo tutti i prodotti
$prodotti=$this->em->getRepository(Product::class)->findAll();
$numeroProdotti = count($prodotti);
//ciclo sui prodotti
for ($j=0;$j<$numeroProdotti;$j++){
$productArca = $prodotti[$j]->getProductArca();
//prelevo i prezzi corrispondenti ancora validi, se ce n'è più di uno arriva giù un array e quindi devo gestire l'eccezione
$prezziProdotto = $prodotti[$j]->getLastPrice();
//se siamo nel caso in cui c'è più di un prezzo valido per il singolo prodotto
if ($prezziProdotto != null && is_array($prezziProdotto)){
$esplosoListino[$productArca->getCdAr()]=[
'product' => $prodotti[$j],
'productArca' => $productArca,
'price' => $prezziProdotto,
'price_multiple' => true,
];
} else if ($prezziProdotto != null){ //caso in cui il prezzo è uno solo
$esplosoListino[$productArca->getCdAr()]=[
'product' => $prodotti[$j],
'productArca' => $productArca,
'price' => $prezziProdotto,
'price_multiple' => false,
];
}
else {
//caso in cui manca il prezzo
$esplosoListino[$productArca->getCdAr()]=[
'product' => $prodotti[$j],
'productArca' => $productArca,
'price' => null,
'price_multiple' => false,
];
}
}
ksort($esplosoListino); //ordina alfabeticamente per chiavi (cdar)
$output['message']="listini prezzi correnti per prodotto";
//$output['priceList']=$priceList;
$output['priceListExpanded']=$esplosoListino;
switch($tipoUscita){
case 'template' :
return $this->render('price_list/expanded.html.twig',$output);
break;
case 'queryPS' :
return $this->render('price_list/queryPS.html.twig',$output);
break;
default : //lo uso per tipo uscita json, dato che lo uso come fallback
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_OK);
return $jresponse;
break;
}
if ($tipoUscita == 'json'){
} else {}
}
#[Route('/materassi', name: 'price_list_materassi')]
public function price_list_materassi(): Response
{
return $this->render('price_list/index.html.twig', [
'controller_name' => 'PriceListController',
]);
}
#[Route('/expand', name: 'price_list_expand')]
public function expand($optParams=null): Response
{
//legge dalla request l'id del price list da espandere e controlla sia un valore valido
$idPriceList = $this->request->query->get('id');
//nel caso i parametri opzionali non siano già stati passati nella chiamata del metodo, provo a ricavarli dalla request POST
if ($optParams == null){
$optParams=[]; //arrayvuoto
$optParams['tipoUscita'] = $this->request->get('tipoUscita');
$this->logger->info("tipoUscita: {$optParams['tipoUscita']} letto dal POST");
} else {}
$output=[]; //contenitore per uscite della response
if ( isset($optParams) && is_array($optParams) ){
$possibiliTipiUscita=['json','array','template','queryPS'];
//controllo se il tipoUscita è definito ed è appartenente ai tipi permessi
if ( isset($optParams['tipoUscita']) && is_string($optParams['tipoUscita']) && in_array($optParams['tipoUscita'],$possibiliTipiUscita) ){
$tipoUscita = $optParams['tipoUscita'];
} else {
$output['warning']="tipoUscita definito {$optParams['tipoUscita']} , ma non valido";
$tipoUscita = 'json';
}
}
else {
$tipoUscita = 'json';
}
$esplosoListino=[]; //contenitore per l'esplosione del listino
if ( $idPriceList != null && ((int) $idPriceList > 0) ){}
else{
$output['error']='missing or wrong id in request';
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_BAD_REQUEST);
return $jresponse;
}
//legge dal database il record price list e controlla che esista
$priceList = $this->em->getRepository(PriceList::class)->find($idPriceList);
if ($priceList != null){}
else {
$output['error']='missing id in price list database';
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_NOT_FOUND);
return $jresponse;
}
//parto con l'espansione
$prezzi = $priceList->getPrice(); //ottiene gli oggetti price correlati
$numeroPrezzi = count($prezzi);
//ciclo sui prezzi
for ($i=0;$i<$numeroPrezzi;$i++){
$prodotti = $prezzi[$i]->getProducts(); //ottiene gli oggetti product correlati
$numeroProdotti = count($prodotti);
//ciclo sui prodotti abbinati ai prezzi
for ($j=0;$j<$numeroProdotti;$j++){
$prodArca = $prodotti[$j]->getProductArca(); //contiene il prodotto arca corrispondente
$prodPS = $prodotti[$j]->getProductPS(); //contiene il prodotto prestashop corrispondente
if ($prodPS != null){
if ($prodPS->getIdProductAttribute() != null ){
$parentProdPS = $this->em->getRepository(ProductPS::class)->findParent();
} else {
$parentProdPS = null;
}
}
$esplosoListino[$prodArca->getCdar()]=[
'product' => $prodotti[$j],
'productArca' => $prodArca,
'productPS' => $productPS,
'price' => $prezzi[$i],
];
}
}
//
ksort($esplosoListino); //ordina alfabeticamente per chiavi (cdar)
$output['message']="expand results price_list id:{$idPriceList}";
$output['priceList']=$priceList;
$output['priceListExpanded']=$esplosoListino;
switch($tipoUscita){
case 'template' :
return $this->render('price_list/expanded.html.twig',$output);
break;
case 'queryPS':
return $this->render('price_list/queryPS.html.twig',$output);
break;
default : //lo uso per tipo uscita json, dato che lo uso come fallback
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_OK);
return $jresponse;
break;
}
if ($tipoUscita == 'json'){
} else {}
}
/**
* Per stampare le query di update necessarie
*/
#[Route('/queryPS', name: 'price_list_queryPS')]
public function queryPS($optParams=null): Response
{
//legge dalla request l'id del price list da espandere e controlla sia un valore valido
$idPriceList = $this->request->query->get('id');
//nel caso i parametri opzionali non siano già stati passati nella chiamata del metodo, provo a ricavarli dalla request POST
/*if ($optParams == null){
$optParams=[]; //arrayvuoto
$optParams['tipoUscita'] = $this->request->get('tipoUscita');
$this->logger->info("tipoUscita: {$optParams['tipoUscita']} letto dal POST");
} else {}
$output=[]; //contenitore per uscite della response
if ( isset($optParams) && is_array($optParams) ){
$possibiliTipiUscita=['json','array','template','queryPS'];
//controllo se il tipoUscita è definito ed è appartenente ai tipi permessi
if ( isset($optParams['tipoUscita']) && is_string($optParams['tipoUscita']) && in_array($optParams['tipoUscita'],$possibiliTipiUscita) ){
$tipoUscita = $optParams['tipoUscita'];
} else {
$output['warning']="tipoUscita definito {$optParams['tipoUscita']} , ma non valido";
$tipoUscita = 'json';
}
}
else {
$tipoUscita = 'json';
}*/
$esplosoListino=[]; //contenitore per l'esplosione del listino
if ( $idPriceList != null && ((int) $idPriceList > 0) ){}
else{
$output['error']='missing or wrong id in request';
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_BAD_REQUEST);
return $jresponse;
}
//legge dal database il record price list e controlla che esista
$priceList = $this->em->getRepository(PriceList::class)->find($idPriceList);
if ($priceList != null){}
else {
$output['error']='missing id in price list database';
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_NOT_FOUND);
return $jresponse;
}
//parto con l'espansione
$prezzi = $priceList->getPrice(); //ottiene gli oggetti price correlati
$numeroPrezzi = count($prezzi);
//PRIMO ciclo sui prezzi, per preparare una lista dei prodotti prestashop BASE (senza variazioni) che hanno subito aggiornamento prezzo
$parentsAggiornati = []; // contenitore per i parents (prodotti prestashop base) soggetti ad aggiornamento
$childrenAggiornati = []; // contenitore per i parents (prodotti prestashop base) soggetti ad aggiornamento
for ($i=0;$i<$numeroPrezzi;$i++){
$prodotti = $prezzi[$i]->getProducts(); //ottiene gli oggetti product correlati
$numeroProdotti = count($prodotti);
//ciclo sui prodotti abbinati ai prezzi
for ($j=0;$j<$numeroProdotti;$j++){
$prodArca = $prodotti[$j]->getProductArca(); //contiene il prodotto arca corrispondente
$prodottiPS = $prodotti[$j]->getProductPS(); //contiene i prodotti prestashop corrispondente
$numPPS = count ($prodottiPS);
//ciclo sui prodotti prestashop abbianti al prodotto in questione (potrebbero essere più cloni, per svariati motivi)
for ($h=0; $h<$numPPS; $h++){
if ($prodottiPS[$h] != null){ //nel caso sia stato rintracciato
//nel caso in cui siamo in presenza di un prodotto variation che ha un parent
if ($prodottiPS[$h]->getIdProductAttribute() != null ){ //prelevo il parent
//in questo primo ciclo non faccio nulla
} else { //caso in cui il prodotto non ha parent e quindi è un prodotto base, lo inserisco nell'apposito contenitore
$prezzoPerUpdate=$prezzi[$i]->getAmount();
$parentsAggiornati[$prodottiPS[$h]]=[
'product' => $prodotti[$j],
'productArca' => $prodArca,
'productPS' => $prodottiPS[$h],
'price' => $prezzi[$i],
'prezzoPerUpdate' => $prezzoPerUpdate,
];
}
} else {
continue;
}
}
}
}
//FINE PRIMO Ciclo sui prezzi e inizio del secondo
for ($i=0;$i<$numeroPrezzi;$i++){
$prodotti = $prezzi[$i]->getProducts(); //ottiene gli oggetti product correlati
$numeroProdotti = count($prodotti);
//ciclo sui prodotti abbinati ai prezzi
for ($j=0;$j<$numeroProdotti;$j++){
$prodArca = $prodotti[$j]->getProductArca(); //contiene il prodotto arca corrispondente
$prodottiPS = $prodotti[$j]->getProductPS(); //contiene i prodotti prestashop corrispondenti
$numPPS = count ($prodottiPS);
//ciclo sui prodotti prestashop abbianti al prodotto in questione (potrebbero essere più cloni, per svariati motivi)
for ($h=0; $h<$numPPS; $h++){
if ($prodottiPS[$h] != null){ //nel caso sia stato rintracciato
//nel caso in cui siamo in presenza di un prodotto variation che ha un parent
$idpa=$prodottiPS[$h]->getIdProductAttribute();
if ( $idpa != null ){
//tento di prelevare il parent prima dall'array $parentsAggiornati perché se è stato aggiornato il suo prezzo a database può averne ancora uno vecchio
//inoltre è più celere
$idParentPerRicerca=$prodottiPS[$h]->getIdProduct();
//se c'è il parent aggiornato, uso il prezzo per la differenza
if ( isset($parentsAggiornati[$idParentPerRicerca]) ){
$prezzoParent = $parentsAggiornati[$idParentPerRicerca]['prezzoPerUpdate'];
} else { //se non c'è lo prelevo dal database
$parentProdPS = $this->em->getRepository(ProductPS::class)->findParent($idParentPerRicerca);
$prezzoParent = $parentProdPS->getLastPrice();
}
//calcolo la differenza tra il child ed il proprio parent
$prezzoPerUpdate = $prezzi[$i]->getAmount() - $prezzoParent;
$childrenAggiornati[]=[
'product' => $prodotti[$j],
'productArca' => $prodArca,
'productPS' => $prodottiPS[$h],
'price' => $prezzi[$i],
'prezzoPerUpdate' => $prezzoPerUpdate,
];
} else { //caso in cui il prodotto non ha parent, non faccio nulla perché è stato sicuramente già inserito in update nel primo ciclo
//$prezzoPerUpdate = $prezzi[$i]->getAmount();
}
} else {
continue;
}
}
/*
$esplosoListino[$prodArca->getCdar()]=[
'product' => $prodotti[$j],
'productArca' => $prodArca,
'productPS' => $productPS,
'price' => $prezzi[$i],
'prezzoPerUpdate' => $prezzoPerUpdate,
];*/
}
}
$output = [
'parentsAggiornati' => $parentsAggiornati,
'childrenAggiornati' => $childrenAggiornati,
];
return $this->render('price_list/queryPS.html.twig',$output);
//
/*ksort($esplosoListino); //ordina alfabeticamente per chiavi (cdar)
$output['message']="expand results price_list id:{$idPriceList}";
$output['priceList']=$priceList;
$output['priceListExpanded']=$esplosoListino;
switch($tipoUscita){
case 'template' :
return $this->render('price_list/expanded.html.twig',$output);
break;
case 'queryPS':
return $this->render('price_list/queryPS.html.twig',$output);
break;
default : //lo uso per tipo uscita json, dato che lo uso come fallback
$jresponse = new JsonResponse ($output);
$jresponse->setStatusCode(Response::HTTP_OK);
return $jresponse;
break;
}
if ($tipoUscita == 'json'){
} else {}*/
}
#[Route('/update', name: 'price_list_update')]
public function aggiornaPrezzi(){
//legge dalla request l'id del price list da espandere e controlla sia un valore valido
/*$idPriceList = $this->request->query->get('id');
if ( is_int($idPriceList) && $idPriceList>0 ){
$priceList = $this->em->getRepository(PriceList::class)->find($idPriceList);
if ($priceList != null){}
else {
$output = "listino corrispondente a {$idPriceList} non impostato";
$jresponse = new JsonResponse($output);
$jresponse->setStatusCode(Response::HTTP_NOT_FOUND);
return $jresponse;
}
} else {
$output = "id listino : {$idPriceList} non corretto";
$jresponse = new JsonResponse($output);
$jresponse->setStatusCode(Response::HTTP_BAD_REQUEST);
return $jresponse;
}*/
$dtnow = new \DateTime();
$newPriceList = new PriceList();
$newPriceList->setCreated($dtnow);
$newPriceList->setUpdated($dtnow);
$newPriceList->setStart($dtnow);
$this->em->persist($newPriceList);
//importo i dati da aggiornare
$PDA_raw = new PrezziDaAggiornare();
$PDA = $PDA_raw->prodotti; //array di prodotti [ ['Cd_AR' => 'WMSFTCNF-BSN-10','price' => '1988',], ... ]
$iMax=count($PDA);
$esito_iterazioni=[]; //contenitore per uscite
for ($i=0;$i<$iMax;$i++){
//per comodità assegno il valori
$Cd_AR = $PDA[$i]['Cd_AR'];
$price = $PDA[$i]['price'];
//rintraccio il ProductArca mediante cd_ar, controllo se non esiste segno l'errore e tralascio l'iterazione
$prodArca = $this->em->getRepository(ProductArca::class)->findByCdar($Cd_AR);
$this->logger->info('prodArca '.json_encode(get_object_vars($prodArca)));
if ($prodArca != null ){
}
else {
$esito_iterazioni[$i]="prodotto arca corrispondente a Cd_AR: {$Cd_AR} non rintracciato";
continue;
}
//estrapolo il prodotto corrispondente, controllo se non esiste segno l'errore e tralascio l'iterazione
$prod = $prodArca->getProduct();
if ($prod != null){}
else {
$esito_iterazioni[$i]="prodotto corrispondente a Cd_AR: {$Cd_AR} e idProductArca: {$prodArca->getId()} non rintracciato";
continue;
}
//estrapolo il prezzo attuale
$prezzoPrecedente = $prod->getLastPrice();
if ($prezzoPrecedente != null){
if (is_array($prezzoPrecedente)){
$esito_iterazioni[$i]="PROBLEMA: Trovato più di un prezzo precedente ancora valido per il prodotto corrispondente Cd_AR: {$Cd_AR} e idProductArca: {$prodArca->getId()}";
continue;
} else{}
}
else {
$esito_iterazioni[$i]="Prezzo precedente prodotto corrispondente Cd_AR: {$Cd_AR} e idProductArca: {$prodArca->getId()} non rintracciato";
continue;
}
//verifico che l'id price list precedente fosse abbinato
/*$abbinamentiPriceList = $prezzoPrecedente->getPriceLists();
$abbinamentoPresente = false;
foreach($abbinamentiPriceList as $apl){
//se trovo l'abbinamento, ritorno la variabile a true e stoppo il ciclo
if ($apl->getId() == $idPriceList){
$abbinamentoPresente = true;
break;
} else {}
}
//se il prezzo non è abbinato al listino che devo aggiornare, torno un errore e passo all'iterazione successiva
if ($abbinamentoPresente){} else {
$esito_iterazioni[$i]="A database non risultano corrispondenze tra price di Cd_AR: {$Cd_AR} e listino id: {$idPriceList}... verificare";
continue;
}*/
//effettuo la variazione vera e propria
$esito_iterazioni[$i]="Cd_AR: {$Cd_AR} Prezzo precedente: {$prezzoPrecedente->getAmount()} Nuovo Prezzo: {$price}";
//chiudo il prezzo precedente
$prezzoPrecedente->setEnd($dtnow);
//creo un nuovo prezzo
$prezzoAttuale = new Price();
$prezzoAttuale->setAmount($price);
$prezzoAttuale->addProduct($prod);
$prezzoAttuale->setCreated($dtnow);
$prezzoAttuale->setUpdated($dtnow);
$prezzoAttuale->setStart($dtnow);
$prezzoAttuale->addPriceList($newPriceList);
$this->em->persist($prezzoAttuale);
}
//SALVO LE MODIFICHE A DATABASE
$this->em->flush();//DISATTIVATA PER DEBUG
$jresponse = new JsonResponse ($esito_iterazioni);
$jresponse->setStatusCode(Response::HTTP_OK);
return $jresponse;
}
#[Route('/new', name: 'price_list_new')]
public function creaListinoPrezzi(){
$jsonResponse = new JsonResponse();
$output=[];
//
$dtnow = new \DateTime(); //tempo attuale
$newPriceList = new PriceList();
$newPriceList->setCreated($dtnow);
$newPriceList->setUpdated($dtnow);
//legge dalla request gli input json decodificandoli in array associativo
$requestJson_dec = json_decode($this->request->getContent(),true);
if ( isset($requestJson_dec['prices']) && is_array($requestJson_dec['prices']) && count($requestJson_dec['prices'])>0 ){
$arrPrezzi = $requestJson_dec['prices'];
$numPrezzi = count($arrPrezzi);
//controllo data di inizio applicazione listino
if ( isset($requestJson_dec['start']) && is_string($requestJson_dec['start']) ){
//controllo se la stringa passata è davvero una data
$dataInizio = date_create_from_format('Y-m-d H:i:s',$requestJson_dec['start']);
if ( $dataInizio instanceOf \DateTime ){
$newPriceList->setStart($dataInizio);
} else {
$jsonResponse->setStatusCode(400);
$jsonResponse->setContent("start: data di inizio non valida");
return $jsonResponse;
}
if ( isset($requestJson_dec['end']) && is_string($requestJson_dec['end']) ){
//controllo se la stringa passata è davvero una data
$dataFine = date_create_from_format('Y-m-d H:i:s',$requestJson_dec['end']);
if ( $dataFine instanceOf \DateTime ){
$newPriceList->setEnd($dataFine);
} else {
$dataFine = null;
$jsonResponse->setStatusCode(400);
$jsonResponse->setContent("end: data di fine non valida");
return $jsonResponse;
}
} else {
$newPriceList->setEnd(null);
}
} else {
$jsonResponse->setStatusCode(400);
$jsonResponse->setContent("start: data di inizio uso listino prezzi mancante");
return $jsonResponse;
}
//validazione dei parametri in ingresso effettuata, posso proseguire e intanto persisto il listino nuovo
$this->em->persist($newPriceList);
} else {
$jsonResponse->setStatusCode(400);
$jsonResponse->setContent("prices: array dei prezzi mancante o vuoto");
return $jsonResponse;
}
//ciclo effettivo sui prezzi
for ($i=0;$i<$numPrezzi;$i++){
if ( isset($arrPrezzi[$i]['Cd_AR']) && is_string($arrPrezzi[$i]['Cd_AR']) && isset($arrPrezzi[$i]['price']) && is_int($arrPrezzi[$i]['price']) ){
$productArca = $this->em->getRepository(ProductArca::class)->findOneBy([
'cdar' => $arrPrezzi[$i]['Cd_AR'],
]);
if ($productArca != null){
$product = $productArca->getProduct();
}
else {
$output["scarto {$i}"] = $arrPrezzi[$i];
continue; //interrompo l'iterazione corrente e passo alla successiva
}
}
else {
$output["scarto {$i}"] = $arrPrezzi[$i];
continue; //interrompo l'iterazione corrente e passo alla successiva
}
$newPrice = new Price();
$newPrice->setAmount($arrPrezzi[$i]['price']);
$newPrice->setCreated($dtnow);
$newPrice->setUpdated($dtnow);
$newPrice->setStart($dataInizio);
if (isset($dataFine) && $dataFine != null){
$newPrice->setEnd($dataFine);
} else {
$newPrice->setEnd(null);
}
$newPrice->addProduct($product);
$newPrice->addPriceList($newPriceList);
$this->em->persist($newPrice);
$output["Aggiungo {$i}"]="Aggiunto {$arrPrezzi[$i]['Cd_AR']}, prezzo: {$arrPrezzi[$i]['price']}";
}
//salvo in database
$this->em->flush();
$jsonResponse->setStatusCode(200);
$jsonResponse->setContent(json_encode($output));
return $jsonResponse;
}
} //FINE CONTROLLER