gestione gare pubbliche
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

710 righe
29 KiB

<?php
require_once __DIR__ . "/npa.class.php";
class NPA_Import
{
public static function isConcessione(stdClass $schedaPrincipale)
{
$metadata = NuovaPiattaformaAppalti::getCardsMetadata();
$titoloSchedaPrincipale = strtolower($metadata[$schedaPrincipale->codice->codice]["titolo"]);
return str_contains($titoloSchedaPrincipale, "concession");
}
/**
* Ottiene il settore compatibile con la scheda principale
*
* @param stdClass $schedaPrincipale La scheda principale della procedura
* @return array|string Settori compatibili
*/
public static function getSettoreRiferimento(stdClass $schedaPrincipale)
{
$metadata = NuovaPiattaformaAppalti::getCardsMetadata();
$settori = $metadata[$schedaPrincipale->codice->codice ?? ""]["settori"] ?? [];
if (count($settori) == 1)
return $settori[0];
return $settori;
}
/**
* Ottiene la procedura compatibile con la scheda principale
*
* @param stdClass $schedaPrincipale La scheda principale della procedura
* @param array $match_moduli_compatibili Risultati compatibili da match-moduli.json
* @return array|string Tipi di procedura compatibili
*/
public static function getProcedura(stdClass $schedaPrincipale, array $match_moduli_compatibili = [])
{
// Estrazione di tipoProcedura dal body
$body = object_to_array($schedaPrincipale->body->anacForm ?? new stdClass());
$tipo_procedura = recursive_array_key_search_first("tipoProcedura", $body);
if (!empty($tipo_procedura["codice"])) {
$procedure = json_decode(file_get_contents(substr(__DIR__, 0, strpos(__DIR__, "/public_html")) . "/json/gare-procedure.json"));
foreach ($procedure as $key => $procedura) {
$bdncp = $procedura->bdncp ?? null;
if (!empty($bdncp)) {
if (in_array($tipo_procedura["codice"], $bdncp)) {
return $key;
}
}
}
}
// Estrazione da match-moduli.json
if (!empty($match_moduli_compatibili)) {
$risultati_compatibili = array_map(function ($item) {
return $item[2];
}, $match_moduli_compatibili);
$risultati_compatibili = array_filter($risultati_compatibili, function ($item) {
return $item != "*";
});
if (count($risultati_compatibili) == 1) {
return $risultati_compatibili[0];
}
return $risultati_compatibili;
}
return [];
}
/**
* Ottiene la somma del quadroEconomicoStandard di una scheda anac
*
* @param stdClass $scheda
* @return float
*/
public static function getPrezzoRiferimento(stdClass $scheda): float
{
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$results = recursive_array_key_search_all("quadroEconomicoStandard", $scheda);
$sum = 0;
foreach ($results as $result) {
foreach ($result as $v) {
$sum += $v;
}
}
vdump("PrezzoRiferimento: ", $sum);
return $sum;
}
/**
* Ottiene il quadroEconomicoStandard di una scheda anac
*
* @param stdClass $scheda
* @return array
*/
public static function getImporti(stdClass $scheda): array
{
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$results = recursive_array_key_search_all("quadroEconomicoStandard", $scheda);
if(empty($results)) return [];
$nomi = [
"impLavori" => "lavori",
"impServizi" => "servizi",
"impForniture" => "forniture",
"sommeOpzioniRinnovi" => "rinnovi",
"sommeADisposizione" => "sommeAmministrazione"
];
$res = null;
foreach ($results as $r) {
if (empty($res)) {
$res = $r;
} else {
foreach ($r as $key => $value) {
$res[$key] += $value;
}
}
}
foreach ($res as $key => $value) {
foreach ($nomi as $nome) {
if (in_array($key, array_keys($nomi))) {
$res[$nomi[$key]] = $value;
}
}
unset($res[$key]);
}
vdump("Importi: ", $res);
return $res;
}
/**
* Ottiene la tipologia principale a partire dal quadroEconomicoStandard di una scheda,
* viene calcolato prendendo il maggiore tra impServizi, impLavori e impForniture
*
* @param stdClass $scheda
* @return string
*/
public static function getTipologia(stdClass $scheda): string
{
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$oggettoContratto = recursive_array_key_search_first("oggettoContratto", $scheda);
if(!empty($oggettoContratto["codice"])) {
switch($oggettoContratto["codice"]) {
case "works":
return "L";
case "supplies":
return "F";
case "services":
default:
return "S";
}
}
$result = recursive_array_key_search_all("quadroEconomicoStandard", $scheda);
$f_key = $f_value = 0;
foreach ($result as $r) {
foreach ($r as $key => $value) {
if (($value > $f_value || $f_key == null) && in_array($key, ["impServizi", "impLavori", "impForniture"])) {
$f_value = $value;
$f_key = $key;
}
}
}
switch ($f_key) {
case "impLavori":
return "L";
case "impForniture":
return "F";
case "impServizi":
default:
return "S";
}
}
/**
* Cerca nelle schede se è definito un accordo Quadro
*
* @param array $schede
* @return bool
*/
public static function getAccordoQuadro(array $schede): string
{
foreach ($schede as $scheda) {
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$result = recursive_array_key_search_first("accordoQuadro", $scheda);
if (!empty($result["codice"]) && $result["codice"] != "none")
return true;
}
return false;
}
/**
* Cerca un codice NUTS nelle schede
*
* @param array $schede
* @return string|null
*/
public static function getNuts(array $schede): ?string
{
$array_schede = object_to_array((object) $schede);
$result = recursive_array_key_search_first("datiBaseContratto", $array_schede);
vdump("NUTS: ", $result);
return $result["codNUTS"]["codice"] ?? null;
}
/**
* Cerca la norma di riferimento all'interno delle schede
* TODO Da implementare
*
* @param array $schede
* @return string|null
*/
public static function getNormaRiferimento(array $schede): ?string
{
return null;
}
/**
* Metodo helper per cercare all'interno di una scheda una chiave relativa ad un lotto
*
* @param string $key Chiave da cercare
* @param stdClass $identifier Lotto in questione
* @param array $schede Schede in cui cercare
* @return array
*/
private static function searchByLotto(string $key, stdClass $lot, array $schede)
{
$result = [];
foreach ($schede as $scheda) {
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$recursive_search_results = recursive_array_key_search_all($key, $scheda);
foreach ($recursive_search_results as $entries) {
foreach($entries as $entry) {
$lotIdentifier = recursive_array_key_search_first("lotIdentifier", $entry);
if ($lotIdentifier != $lot->lotIdentifier) {
$cig = recursive_array_key_search_first("cig", $entry);
if ($cig != $lot->cig) {
$idContratto = recursive_array_search_all("idContratto", $entry);
if(empty($lot->idContratto) || !in_array($idContratto, $lot->idContratto))
continue;
}
}
$result[] = $entry;
}
}
}
return $result;
}
public static function isDeserta(array $schede, stdClass $lot) {
foreach ($schede as $scheda) {
$codice_scheda = $scheda->codice->codice;
// Se lo è
if ($codice_scheda === "NAG") {
$anacForm = object_to_array($scheda->body->anacForm ?? []);
// Se non abbiamo un lotto assegnato, non la vogliamo
if ($lot === null) {
continue;
}
$cig = recursive_array_key_search_first("cig", $anacForm);
if ($cig != $lot->cig) {
// Poi per lotIdentifier
$lotIdentifier = recursive_array_key_search_first("lotIdentifier", $anacForm);
if ($lotIdentifier != $lot->lotIdentifier) {
continue;
}
}
return true;
}
}
return false;
}
/**
* Ottiene l'ente beneficiario prendendo la prima stazione appaltante censita nella scheda principale
*
* @param stdClass $scheda
* @return array
*/
public static function getEnteBeneficiario(stdClass $scheda) : array {
$scheda = object_to_array($scheda->body->anacForm ?? new stdClass());
$result = recursive_array_key_search_first("stazioniAppaltanti", $scheda);
return $result;
}
/**
* Ottiene le info su un lotto dalle schede ANAC
*
* @param array $schede Schede da considerare
* @param stdClass $lot Lotto da considerare
* @return null|array
*/
public static function getInfoLotto(array $schede, stdClass $lot)
{
// Ci basta lotti o aggiudicazioni
$lotti = array_values(self::searchByLotto("lotti", $lot, $schede)) ?? [];
$aggiudicazioni = array_values(self::searchByLotto("aggiudicazioni", $lot, $schede)) ?? [];
if (empty($lotti)) {
$lotti = $aggiudicazioni;
}
$quadroEconomicoStandard = recursive_array_key_search_all("quadroEconomicoStandard", $lotti)[0] ?? [];
vdump($quadroEconomicoStandard);
$datiBase = recursive_array_key_search_all("datiBase", $lotti)[0] ?? null;
$importoBase = 0;
foreach (["impLavori", "impServizi", "impForniture"] as $importo) {
if (isset($quadroEconomicoStandard[$importo]) && $quadroEconomicoStandard[$importo] > $importoBase) {
$importoBase = $quadroEconomicoStandard[$importo];
}
}
$importoTotale = $datiBase["importo"] ?? null;
$importoOneri = $quadroEconomicoStandard["impTotaleSicurezza"] ?? 0;
$importoOpzioni = $quadroEconomicoStandard["sommeOpzioniRinnovi"] ?? 0;
if (empty($importoTotale)) {
$importoTotale = $importoBase;
} else {
$importoManodopera = $importoTotale - $importoBase - $importoOneri - $importoOpzioni;
}
$infoLotto = [
"importoTotale" => $importoTotale,
"importoBase" => $importoBase,
"importoOneri" => $importoOneri,
"importoOpzioni" => $importoOpzioni,
"importoManodopera" => $importoManodopera ?? 0
];
if (!empty($aggiudicazioni)) {
$quadroEconomicoStandard = recursive_array_key_search_first("quadroEconomicoStandard", $lotti);
$infoLotto["importoAggiudicazione"] = $quadroEconomicoStandard["sommeADisposizione"] ?? 0;
}
$infoLotto["importoPartecipanti"] = 0;
$partecipantiAggiudicazione = recursive_array_key_search_all("partecipanti", $aggiudicazioni)[0] ?? [];
foreach($partecipantiAggiudicazione as $partecipante) {
if($partecipante["aggiudicatario"] ?? true) {
$infoLotto["importoPartecipanti"] += $partecipante["importo"] ?? 0;
}
}
$cpvPrevalente = recursive_array_key_search_first("cpvPrevalente", $lotti);
if (!empty($cpvPrevalente)) {
$infoLotto["cpvPrevalente"] = rtrim($cpvPrevalente["codice"] ?? "", "0");
}
$cupLotto = recursive_array_key_search_first("cupLotto", $lotti);
if(!empty($cupLotto)) {
$infoLotto["cupLotto"] = $cupLotto;
}
$criteriAggiudicazione = recursive_array_key_search_first("criteriAggiudicazione", $lotti);
if (!empty($criteriAggiudicazione)) {
$infoLotto["criteriAggiudicazione"] = $criteriAggiudicazione["codice"] ?? null;
}
vdump($infoLotto);
return $infoLotto;
}
/**
* Importa le schede ANAC, se lot e specificato, solo se relative a quel lotto
*
* @param array $schede
* @param NuovaPiattaformaAppalti $npa
* @param stdClass|null $lot
* @return void
*/
public static function importaSchede(array $schede, NuovaPiattaformaAppalti $npa, ?stdClass &$lot = null)
{
// schede.json
$metadata = NuovaPiattaformaAppalti::getCardsMetadata();
// Per ogni scheda
foreach ($schede as $scheda) {
// Verifichiamo sia di lotto
$codice_scheda = $scheda->codice->codice;
$anacForm = object_to_array($scheda->body->anacForm ?? []);
$is_lotto = $metadata[$codice_scheda]["lotto"];
// Se lo è
if ($is_lotto) {
// Se non abbiamo un lotto assegnato, non la vogliamo
if ($lot === null) {
continue;
}
$cig = recursive_array_key_search_first("cig", $anacForm);
vdump($cig);
if ($cig != $lot->cig) {
// Poi per lotIdentifier
$lotIdentifier = recursive_array_key_search_first("lotIdentifier", $anacForm);
vdump($lotIdentifier);
if ($lotIdentifier != $lot->lotIdentifier) {
// Poi per lotIdentifier
$idContratto = recursive_array_key_search_first("idContratto", $anacForm);
vdump($idContratto);
if (!isset($lot->idContratto) || !in_array($idContratto, $lot->idContratto)) {
continue;
}
}
}
} else if ($lot != null) {
continue;
}
//recupera l'avviso e assegna lo stato
$stato = 50; // Tutte le schede sono almeno confermate se sono presenti
$pubblicazione = $scheda->pubblicazione ?? null;
$info = null;
if (!empty($pubblicazione)) {
if ($pubblicazione->stato->codice == "PUBB") {
$stato = 100;
}
$info = serialize($pubblicazione);
$hasEUPublication = !empty($metadata[$codice_scheda]["guue"]);
$isFullyPublished = isset($pubblicazione->datiPubblicazioneIT) && isset($pubblicazione->datiPubblicazioneIT->stato->codice) && $pubblicazione->datiPubblicazioneIT->stato->codice === "PUBB";
if ($hasEUPublication && $isFullyPublished) {
$isFullyPublished = isset($pubblicazione->datiPubblicazioneEU) && isset($pubblicazione->datiPubblicazioneEU->stato->codice) && $pubblicazione->datiPubblicazioneEU->stato->codice === "PUBB";
}
if ($isFullyPublished) {
$stato = 110;
}
}
$salva = new salva();
$salva->debug = defined('__VERBOSE');
$salva->nome_tabella = "b_npa_schede";
$salva->operazione = "INSERT";
$salva->oggetto = [
"codice_npa" => $npa->fascicolo["codice"],
"uuid" => $scheda->_idScheda,
"id_scheda" => $codice_scheda,
"type" => $metadata[$codice_scheda]["tipologia"],
"stato" => $stato,
"errore" => "NO",
"info" => $info,
"pubblicazione" => serialize($pubblicazione),
"dati" => json_encode($scheda->body),
"codice_lotto" => $lot->codice_lotto_npa ?? null,
"utente_modifica" => $_SESSION["utente"]->codice,
"timestamp_trasmissione" => date('d/m/Y H:i:s', strtotime($scheda->dataCreazione)),
"timestamp_creazione" => date('d/m/Y H:i:s', strtotime($scheda->dataCreazione)),
"versione_scheda" => null,
];
vdump("Scheda {$codice_scheda}", $salva->oggetto);
$salva->save();
}
}
/**
* Inserisce i partecipanti nella procedura
*
* @param array $partecipanti I partecipanti da inserire, in array formato anacForm
* @param mixed $oggetto L'oggetto in cui inserire
* @param integer $codice_lotto Codice lotto in cui inserire
* @param boolean $aggiudicatari Definisce se i partecipanti sono anche aggiudicatari
* @return array Partecipanti raggruppati
*/
public static function insertPartecipanti(array $partecipanti, $oggetto, int $codice_lotto, bool $aggiudicatari = false): array
{
// Creiamo i raggruppamenti
$gruppi = [];
foreach ($partecipanti as $p) {
$gruppi[$p["idPartecipante"]][] = $p;
}
// Per ogni raggruppamento
foreach ($gruppi as $g) {
$codice_capogruppo = null;
foreach ($g as $index => $p) {
$paese = strtolower($p["paeseOperatoreEconomico"] ?? "italia") == "italia" ? "IT" : "";
if ($index === 0) { //si tratta del capogruppo o partecipante singolo
$round = $oggetto->getRounds()[0];
$data = [
"codice_operatore" => 0,
"codice_round" => $round["codice"],
"codice_lotto" => $codice_lotto,
"stato" => $paese,
"codice_fiscale" => $p["codiceFiscale"] ?? "",
"ragione_sociale" => $p["denominazione"] ?? "",
"escluso" => "N",
"esclusione_automatica" => "N",
"conferma" => "S",
"motivazione" => null,
"anomalia" => "N",
"a_facoltativa" => "N",
"motivazione_anomalia" => null,
"a_verificata" => "N",
"note_verifica_anomalia" => null,
"campione" => "N",
"totaleTecnico" => null,
"totaleEconomico" => null,
"totale" => null,
"totaleTmp" => null,
"aggiudicatario" => $aggiudicatari ? "S" : "N",
"posizione" => 0,
"utente_modifica" => 0,
"timestamp" => date('Y-m-d H:i:s'),
"uuid" => $p["idPartecipante"]
];
$salva = new salva();
$salva->debug = defined('__VERBOSE');
$salva->nome_tabella = "r_partecipanti_gare";
$salva->operazione = "INSERT";
$salva->oggetto = $data;
$codice_capogruppo = $salva->save();
} else { //si tratta di un partecipante al gruppo
if($p["avvalimento"] ?? false) {
$data = [
"codice_padre" => $codice_capogruppo,
"ragione_sociale" => $p["denominazione"] ?? "",
"stato" => $paese,
"codice_fiscale_impresa" => $p["codiceFiscale"],
"ruolo" => $p["tipologiaAvvalimento"]["codice"] ?? 1,
"utente_modifica" => $_SESSION["utente"]->codice
];
$salva = new salva();
$salva->debug = defined('__VERBOSE');
$salva->nome_tabella = "r_avvalimenti_gare";
$salva->operazione = "INSERT";
$salva->oggetto = $data;
$salva->save();
} else {
$ruolo = $p["ruoloOE"] ?? 2;
$ruoloDB = "";
switch($ruolo) {
case 6:
case 7:
case 8:
case 9:
case 11:
$ruoloDB = "05-CONSORZIATA";
break;
case 2:
case 10:
case 12:
default:
$ruoloDB = "01-MANDANTE";
break;
}
$data = [
"codice_padre" => $codice_capogruppo,
"ragione_sociale" => $p["denominazione"] ?? "",
"stato" => $paese,
"codice_fiscale_impresa" => $p["codiceFiscale"],
"ruolo" => $ruoloDB,
"utente_modifica" => $_SESSION["utente"]->codice
];
$salva = new salva();
$salva->debug = defined('__VERBOSE');
$salva->nome_tabella = "r_raggruppamenti_gare";
$salva->operazione = "INSERT";
$salva->oggetto = $data;
$salva->save();
}
}
$partecipanti[$p["idPartecipante"]][] = $p;
}
}
return $gruppi;
}
/**
* Importa i partecipanti dalle schede
*
* @param array $schede Schede da considerare
* @param mixed $oggetto Oggetto (gara/concorso)
* @param stdClass $lot Lotto da considerare
* @return array
*/
public static function importaPartecipanti(array $schede, $oggetto, stdClass $lot): array
{
$partecipanti = [];
$metadata = NuovaPiattaformaAppalti::getCardsMetadata();
foreach ($schede as $scheda) {
$codice_scheda = $scheda->codice->codice;
$anacForm = object_to_array($scheda->body->anacForm);
$is_lotto = $metadata[$codice_scheda]["lotto"];
if ($is_lotto) {
// Proviamo prima per CIG
$cig = recursive_array_key_search_first("cig", $anacForm);
if ($cig != $lot->cig) {
// Poi per lotIdentifier
$lotIdentifier = recursive_array_key_search_first("lotIdentifier", $anacForm);
if ($lotIdentifier != $lot->lotIdentifier) {
continue;
}
}
$partecipanti = recursive_array_key_search_all("partecipanti", $anacForm)[0] ?? [];
$partecipanti = self::insertPartecipanti($partecipanti, $oggetto, $lot->codice_lotto_oggetto);
} else {
// Nessuna scheda generale definisce i partecipanti senza definire anche gli aggiudicatari
}
}
vdump("Partecipanti", $partecipanti);
return $partecipanti;
}
public static function importaAggiudicatari(array $schede, $oggetto, stdClass $lot, array $partecipanti = []): bool
{
global $pdo;
$metadata = NuovaPiattaformaAppalti::getCardsMetadata();
foreach ($schede as $scheda) {
$codice_scheda = $scheda->codice->codice;
$anacForm = object_to_array($scheda->body->anacForm ?? new stdClass());
$is_lotto = $metadata[$codice_scheda]["lotto"];
if ($is_lotto) { // Troveremo gli aggiudicatari nelle schede di lotto nelle procedure aperte
// Proviamo prima per CIG
$cig = recursive_array_key_search_first("cig", $anacForm);
if ($cig != $lot->cig) {
// Poi per lotIdentifier
$lotIdentifier = recursive_array_key_search_first("lotIdentifier", $anacForm);
if ($lotIdentifier != $lot->lotIdentifier) {
continue;
}
}
// Cerchiamo le aggiudicazioni
$aggiudicazioni = recursive_array_key_search_all("aggiudicazioni", $anacForm) ?? [];
// E al loro interno le offerte Presentate
$offerte_presentate = recursive_array_key_search_all("offertePresentate", $aggiudicazioni)[0] ?? [];
$last_importo = 0;
if(!empty($offerte_presentate)) {
// Per ogni offerta
foreach ($offerte_presentate as $op) {
if ($op["aggiudicatario"] ?? true) {
$partecipante = $partecipanti[$op["idPartecipante"]][0] ?? null;
if (!empty($partecipante)) {
if (!empty($op["importo"]) && $op["importo"] > $last_importo) {
$last_importo = $op["importo"];
}
// TODO QUesto va cambiato per tipo di oggetto
// Settiamo come aggiudicatario il partecipante
$pdo->go(
"UPDATE r_partecipanti_gare SET aggiudicatario = 'S' WHERE uuid = :uuid AND codice_lotto = :codice_lotto",
[":uuid" => $op["idPartecipante"], ":codice_lotto" => $lot->codice_lotto_oggetto]
);
}
}
}
vdump("Aggiudicatari (offertePresentate):", $offerte_presentate);
return true;
}
// Se abbiamo anche un importo lo impostiamo sul lotto
if (!empty($last_importo)) {
$pdo->go(
"UPDATE b_gare_lotti SET importoAggiudicazione = :importo WHERE codice = :codice",
[":importo" => $last_importo, ":codice" => $lot->codice_lotto_oggetto]
);
}
} else { // Nelle aggiudicazioni dirette lo troveremo invece nella scheda principale
$aggiudicazioni = recursive_array_key_search_all("aggiudicazioni", $anacForm)[0] ?? [];
foreach ($aggiudicazioni as $aggiudicazione) {
$lot_identifier = recursive_array_key_search_first("lotIdentifier", $aggiudicazione);
if ($lot_identifier != $lot->lotIdentifier) {
$cig = recursive_array_key_search_first("cig", $aggiudicazione);
if ($cig != $lot->cig) {
continue;
}
}
vdump("Aggiudicazioni", $aggiudicazione);
$partecipantiAggiudicazioni = recursive_array_key_search_all("partecipanti", $aggiudicazione)[0] ?? "";
if(!empty($partecipantiAggiudicazioni)) {
$last_importo = 0;
foreach ($partecipantiAggiudicazioni as $partecipante) {
if (!empty($partecipante["importo"]) && $partecipante["importo"] > $last_importo) {
$last_importo = $partecipante["importo"];
}
}
if (!empty($last_importo)) {
$pdo->go(
"UPDATE b_gare_lotti SET importo = :importo WHERE codice = :codice",
[":importo" => $last_importo, ":codice" => $lot->codice_lotto_oggetto]
);
}
vdump("Aggiudicatari (diretti):", $partecipantiAggiudicazioni);
self::insertPartecipanti($partecipantiAggiudicazioni, $oggetto, $lot->codice_lotto_oggetto, true);
return true;
}
}
//$_cig = recursive_array_key_search_all("cig", $body)[0] ?? null;
//if ($_cig != $lotto->cig) {
// continue;
//}
}
}
return false;
}
}