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; } }