getExtensionPath() . DIRECTORY_SEPARATOR . "gara.extender.class.php"; $extenderName = "GaraExtender{$_SESSION["ente"]->codice}"; if (file_exists($pathExtender)) { include_once $pathExtender; return $extenderName; } } } private function __construct() { global $pdo; $this->commissario = false; $this->db = $pdo; } public static function riferimentiNormativi() { return [ "2016-50" => [ "label" => "D.lgs 50/2016", "inizio" => null, "fine" => '2023-06-30 23:59:59' ], "2023-36" => [ "label" => "D.lgs 36/2023", "inizio" => '2023-07-01 00:00:00', "fine" => null ], ]; } public static function interpretazioniArt41() : Array { return [ "complessivo" => "Offerta complessiva: L'operatore economico esprimerà un'offerta complessiva inclusiva di eventuali costi della manodopera differenti", "scorporato" => "Valutazione separata: L'operatore economico esprimerà un'offerta sulla componente base a cui si sommeranno i costi della manodopera da lui indicati per il calcolo del ribasso complessivo" ]; } public static function statiTermineProcedura() { return [ "35", // "Aggiudicazione definitiva" "50", // "Inviato esito" "90", // "Annullato" "95", // "Deserto" "99", // "Non aggiudicato" "100" // "Completo" ]; } public function updateStato($stato) { if ($this->info["fase_attiva"] == $this->round["numero"] && $this->info["stato"] < $stato) { $this->db->go("UPDATE b_gare SET stato = :stato WHERE codice = :codice", [":stato" => $stato, ":codice" => $this->info["codice"]]); $this->info["stato"] = $stato; if (in_array($stato,static::statiTermineProcedura()) !== false) { $b = settingsManager::getValue("pubblicazioneSuConclusione"); if ($b >= 0 && !$this->privata) { $this->db->go("UPDATE b_gare_round SET pubblica = :pubblica WHERE codice = :codice", [":pubblica" => $b, ":codice" => $this->round["codice"]]); $this->round["pubblica"] = $b; if (empty($this->round["pubblicazione"])) { $this->db->go("UPDATE b_gare_round SET pubblicazione = NOW() WHERE codice = :codice", [":codice" => $this->round["codice"]]); $this->round["pubblicazione"] = date("Y-m-d H:i:s"); } } } $this->calcolaContributo(); $this->updateBadges(); } $this->triggerUpdates(); // se la gara è collegata a un'rda, aggiorna lo stato dell'rda $this->updateStateRda(); } public function triggerUpdates() { if (isset($_SESSION["ente"])) { $_SESSION["ente"]->manageUpdates("gare", $this->info["codice"], $this); $_SESSION["ente"]->checkConservazione("gare", $this->info["codice"], $this->info["stato"], $this->info["codice_ente"]); try { ProcurePlus\Out::sendGara($this); } catch(\Throwable $t) { /* Niente */ } } } public function updateStatoLotto(int $stato,bool $force = false) { if (!empty($this->lotto) && ($this->info["fase_attiva"] == $this->round["numero"] && ($this->lotto["stato"] < $stato || $force))) { $this->db->go("UPDATE b_gare_lotti SET stato = :stato WHERE codice = :codice", [":stato" => $stato, ":codice" => $this->lotto["codice"]]); $this->valutaStatoGenerale($force); } } public function calcolaContributo() { if ($this->info["codice"] != $_SESSION["ente"]->codice) { $infoContributo = Ente::getContributiSUA($_SESSION["ente"]->codice,$this->info["prezzoRiferimento"]); if (!empty($infoContributo["quote"]) && ($infoContributo["all"] || !empty($this->getModalita()["online"]))) { if (($infoContributo["tipo"] == "2" && $this->info["stato"] == 20) || ($infoContributo["tipo"] == "1" && $this->info["stato"] == 35)) { $riferimento = $this->info["prezzoRiferimento"]; if ($infoContributo["tipo"] != "2") { $lotti = $this->getLotti(); $riferimento = 0; foreach($lotti AS $lotto) { $riferimento += $lotto["importoAggiudicazione"]; } } if (!empty($riferimento)) { $contributo = 0; foreach($infoContributo["quote"] AS $quota) { if($quota["tipo"] == "fisso") { $contributo += $quota["valore"]; } else if ($quota["tipo"] == "percentuale") { $contributo += $riferimento * ($quota["valore"]/100); } } if (!empty($contributo)) { $this->db->go("UPDATE b_gare SET contributoSUA = :contributo WHERE codice = :codice", [":contributo" => $contributo, ":codice" => $this->info["codice"]]); $this->info["contributo"] = $contributo; } } } } } } public function getManagerRegistro() { return new registriManager("gare", $this->info["codice"]); } public function configurazioneBusteConfermata() { if ($this->info["stato"] <= 10) { $extraInfo = $this->getExtraInfo()["round"] ?? []; if (isset($extraInfo["conferma_buste"]) && $extraInfo["conferma_buste"] === true) { return true; } return false; } return true; } public function sedutaAperta() { $extraInfo = $this->getExtraInfo()["round"] ?? []; if (isset($extraInfo["seduta_aperta"]) && $extraInfo["seduta_aperta"] === true) { return true; } return false; } public function showPunteggiTecnici() { $extraInfo = $this->getExtraInfo()["round"] ?? []; if (isset($extraInfo["esponi_tecnici"]) && $extraInfo["esponi_tecnici"] === true) { return true; } return false; } public function showPunteggiEconomici() { $extraInfo = $this->getExtraInfo()["round"] ?? []; if (isset($extraInfo["esponi_economici"]) && $extraInfo["esponi_economici"] === true) { return true; } return false; } public function addToLog($operazione, $oggetto) { return $this->getManagerRegistro()->addToLog($operazione, $oggetto); } public function getLog($start = 0, $length = -1) { return $this->getManagerRegistro()->getLog($start, $length); } public function saveExtraInfo($chiave, $valore, $ambito = "gara") { $extraInfo = $this->getExtraInfo(); $extraInfo[$ambito][$chiave] = $valore; if ($ambito == "gara") { $codice = $this->info["codice"]; $tabella = "b_gare"; $this->info["extraInfo"] = json_encode($extraInfo["gara"]); } else if ($ambito == "round") { $codice = $this->round["codice"]; $tabella = "b_gare_round"; $this->round["extraInfo"] = json_encode($extraInfo["round"]); } else if ($ambito == "lotto") { $codice = $this->lotto["codice"]; $tabella = "b_gare_lotti"; $this->lotto["extraInfo"] = json_encode($extraInfo["lotto"]); } if (!empty($codice) && !empty($tabella)) { $extraInfo = json_encode($extraInfo[$ambito]); $salva = new salva(); $salva->debug = false; $salva->nome_tabella = $tabella; $salva->operazione = "UPDATE"; $salva->oggetto = ["codice" => $codice, "extraInfo" => $extraInfo]; if (!empty($salva->save())) { return true; } } return false; } public static function save($data) { global $pdo; $return = false; $operazione_generale = $operazione = empty($data["codice"]) ? "INSERT" : "UPDATE"; $expect = ["codice", "id", "oggetto", "modalita", "tipologia", "accordo_quadro", "procedura", "prezzoRiferimento", "codice_pec", "email_chiave", "codice_ente", "utente_creazione", "timestamp_creazione"]; $solare = false; $affix = ""; if ($_SESSION["ente"]->getInfo()["numerazione"] == "solare") { $solare = true; $expect[] = "anno"; $affix = $data["anno"] . "/"; } $canClone = false; if ($operazione == "INSERT") { $canClone = true; $data["id"] = 1; $where = ""; $bind = []; if ($solare) { $where = " WHERE anno = :anno "; $bind[":anno"] = $data["anno"]; } $sql = "SELECT id FROM b_gare {$where} ORDER BY codice DESC LIMIT 0,1 "; $ris = $pdo->go($sql,$bind); if ($ris->rowCount() === 1) { $rec = $ris->fetch(PDO::FETCH_ASSOC); if ($solare) { $tmp = explode("/",$rec["id"]); if (!empty($tmp[1])) { $rec["id"] = $tmp[1]; } } $data["id"] = (int)$rec["id"] + 1; } $data["id"] = $affix . $data["id"]; $data["utente_creazione"] = $_SESSION["utente"]->codice; $data["timestamp_creazione"] = date('Y-m-d H:i:s'); } else { $checkRound = $pdo->go("SELECT codice FROM b_gare_round WHERE codice_gara = :codice",[":codice"=>$data["codice"]]); if ($checkRound->rowCount() > 0) { $expect = ["codice", "id", "oggetto", "modalita", "accordo_quadro", "prezzoRiferimento", "codice_pec", "email_chiave", "codice_ente", "utente_creazione", "timestamp_creazione"]; } } if(!empty($data["importata"])) { $expect[] = "importata"; } $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare"; $salva->operazione = $operazione; $salva->oggetto = $data; $salva->expect = $expect; $codice = $salva->save(); if ($codice !== false) { if ($operazione_generale == "INSERT") { if ($_SESSION["utente"]->gerarchia > 15) { $utenti = [$_SESSION["utente"]->codice]; } if (!empty($utenti)) { foreach ($utenti as $utente) { $permesso = []; $permesso["sezione"] = "gare"; $permesso["codice_elemento"] = $codice; $permesso["funzione"] = "0"; $permesso["codice_gestore"] = $_SESSION["ente"]->codice; $permesso["codice_utente"] = $utente; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "r_permessi"; $salva->operazione = "INSERT"; $salva->oggetto = $permesso; $salva->save(); } } } $bind = array(":codice" => $codice); $strsql = "DELETE FROM r_cpv_gare WHERE codice_gara = :codice"; $pdo->go($strsql, $bind); scriviLog("r_cpv_gare", "DELETE", $pdo->getSQL()); if (!empty($data["cpv"])) { $data["cpv"] = array_unique($data["cpv"]); foreach ($data["cpv"] as $codice_categoria) { if ($codice_categoria != "") { $bind = array(":codice" => $codice, ":codice_categoria" => $codice_categoria, ":codice_utente" => $_SESSION["utente"]->codice); $strsql = "INSERT INTO r_cpv_gare (codice_gara,codice,utente_modifica) VALUES (:codice,:codice_categoria,:codice_utente)"; $pdo->go($strsql, $bind); scriviLog("r_cpv_gare", "INSERT", $pdo->getSQL()); } } } $bind = array(); $bind[":codice"] = $codice; $strsql = "SELECT * FROM b_gare WHERE codice = :codice"; $risultato = $pdo->go($strsql, $bind); if ($risultato->rowCount() > 0) { $record = $risultato->fetch(PDO::FETCH_ASSOC); if (empty($record["public_key"]) && getModalita()[$record["modalita"]]["online"]) { $email = $data["email_chiave"] ?? ""; $public = P7Manager::generateKeys("gare-{$record["id"]}", $record["oggetto"], $email); if (!empty($public)) { if (!$pdo->go("UPDATE b_gare SET public_key = :public_key WHERE codice = :codice", [":public_key" => $public, ":codice" => $record["codice"]])) { $error_key = true; } } else { $error_key = true; } } if (!isset($error_key)) { $return = gara::init($record["codice"]); if (!empty($return)) { foreach ($data["extraInfo"] as $chiave => $valore) { $return->saveExtraInfo($chiave, $valore, "gara"); } $return->addToLog($operazione_generale, "Dati preliminari"); if ($canClone) { $return->clone(); } } } else { $return = -1; if ($operazione == "INSERT") { $pdo->go("DELETE FROM b_gare WHERE codice = :codice", [":codice" => $codice]); } } } // salva relazione con rda se esiste if(!empty($return->info['codice']) && !empty($data['codici_rda'])){ foreach ($data['codici_rda'] as $codice_rda) { $bind = array(":codice_gara" => $codice, ":codice_rda" => $codice_rda, ":codice_utente" => $_SESSION["utente"]->codice); $strsql = "INSERT INTO r_gara_rda (codice_gara,codice_rda,utente_modifica) VALUES (:codice_gara,:codice_rda,:codice_utente)"; $ris = $pdo->go($strsql, $bind); scriviLog("r_gara_rda", "INSERT", $pdo->getSQL()); if($ris->rowCount() === 1){ // controlla se esiste lo stato 20 $codice_stato = StatoRda::getStati(null, 20); if(!empty($codice_stato)){ $codice_stato = reset($codice_stato); $bind = array(":codice" => $codice_rda, ":codice_stato" => $codice_stato['codice'], ":utente_modifica" => $_SESSION["utente"]->codice); $strsql = "UPDATE b_rda SET codice_stato = :codice_stato, utente_modifica = :utente_modifica WHERE codice = :codice"; $ris = $pdo->go($strsql, $bind); scriviLog("b_rda", "UPDATE", $pdo->getSQL()); }else{ $rda = rda::init($codice_rda); $return->error_rda[] = __("Errore creazione Gara da RDA #{$rda->info['codice']} - {$rda->info['oggetto']} "); } } } } } return $return; } public function setLotto($codice) { if (!empty($codice)) { $dbLotto = $this->getLotti($codice)[0] ?? false; if (!empty($dbLotto)) { $dbLotto = static::getImportiBaseAsta($dbLotto,$this->normaRiferimento); $this->lotto = $dbLotto; return true; } } return false; } public function pubblicaPartecipanti($codiceLotto = NULL) { if (!empty($this->round)) { if (!empty($codiceLotto)) { $lotto = $this->getLotti($codiceLotto)[0] ?? false; } else if (!empty($this->lotto)) { $lotto = $this->lotto; } if ($lotto["stato"] >= 30) { $extraInfo = json_decode($lotto["extraInfo"],true); return $extraInfo["showPartecipanti-{$this->round["codice"]}"] ?? false; } } return false; } public function pubblicaAtti($codiceLotto = NULL) { if (!empty($this->round)) { if (!empty($codiceLotto)) { $lotto = $this->getLotti($codiceLotto)[0] ?? false; } else if (!empty($this->lotto)) { $lotto = $this->lotto; } if (isset($lotto)) { if ($lotto["stato"] >= 50) { $extraInfo = json_decode($lotto["extraInfo"],true); return $extraInfo["showAtti-{$this->round["codice"]}"] ?? false; } } } return false; } public function forceAccessoAttiAmministrativa() : Bool { $rispostaForce = $this->getRisposteElaborazione()["accessoArt36ForceAmministrativa"] ?? "N"; return ($rispostaForce == "S"); } /** * amministrativaSecretabile * * @param string $dataPubblicazione * @param string $force * @return Bool */ public static function amministrativaSecretabile(?String $dataPubblicazione = "1970-01-01", Bool $force = false) : Bool { return ($force || strtotime($dataPubblicazione) > strtotime(date("2024-04-04"))); } public function getRichiestePubblicabili() { $richieste = $this->getRichieste(); $return = []; if (!empty($richieste)) { foreach($richieste AS $richiesta) { if ($richiesta["busta"] != "amministrativa" || self::amministrativaSecretabile($this->round["pubblicazione"],$this->forceAccessoAttiAmministrativa())) { $return[] = $richiesta; } } } return $return; } public function getBustaAccesso(int $richiesta,int $partecipante,bool $content = false) { $busta = $this->getBusta($partecipante,$richiesta,false,$content); if (!empty($busta)) { $pubblica = $busta["pubblica"]; $origine = "busta"; $oscurata = false; $emendamento = $this->getEmendamento($partecipante,$richiesta,$content); if (!empty($emendamento) && $emendamento["accettata"] == "S") { $busta = $emendamento; $origine = "emendamento"; if ($emendamento["segreta"] == "S") { $tmp = $this->getBustaSecretata($partecipante,$richiesta,"emendamento",$content); if (!empty($tmp) && $tmp["accettata"] == "S") { $oscurata = true; $busta = $tmp; } } else { if (empty($pubblica)) { $this->modificaPubblicazioneBusta("S",$partecipante,$richiesta); $pubblica = "S"; } } } else { if ($busta["segreta"] == "S") { $tmp = $this->getBustaSecretata($partecipante,$richiesta,"busta",$content); if (!empty($tmp) && $tmp["accettata"] == "S") { $oscurata = true; $busta = $tmp; } } else { if (empty($pubblica)) { $this->modificaPubblicazioneBusta("S",$partecipante,$richiesta); $pubblica = "S"; } } } $busta["origine"] = $origine; $busta["oscurata"] = $oscurata; $busta["pubblica"] = $pubblica; } return $busta; } public function modificaPubblicazioneBusta(string $esito,int $partecipante,int $richiesta) { $busta = $this->getBusta($partecipante,$richiesta); if (!empty($busta)) { $richiesta = $this->getRichiesta($richiesta); if ($richiesta["busta"] != "amministrativa" || self::amministrativaSecretabile($this->round["pubblicazione"],$this->forceAccessoAttiAmministrativa())) { $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_buste"; $salva->operazione = "UPDATE"; $salva->oggetto = ["codice"=>$busta["codice"],"pubblica"=>$esito]; $salva->save(); return true; } } } public function getBusteSoggetteAccesso() { $richieste = $this->getRichiestePubblicabili(); $partecipanti = $this->getPartecipanti(); $return = []; if (!empty($richieste) && !empty($partecipanti)) { foreach($partecipanti AS $partecipante) { if ($partecipante["escluso"] == "N") { $return[$partecipante["codice"]] = []; foreach($richieste AS $richiesta) { $return[$partecipante["codice"]][$richiesta["codice"]] = $this->getBustaAccesso($richiesta["codice"],$partecipante["codice"]); } } } } return $return; } public function saveLotto($data) { $operazione = (empty($data["codice"])) ? "INSERT" : "UPDATE"; if ($operazione == "INSERT") { $lotti = $this->getLotti(); if (!empty($lotti)) { $data["numero"] = count($lotti) + 1; } else { $data["numero"] = 1; } } $data["codice_gara"] = $this->info["codice"]; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_lotti"; $salva->operazione = $operazione; $salva->oggetto = $data; $salva->ignore = ["extraInfo","stato"]; $codice = $salva->save(); if (!empty($codice)) { if ($this->setLotto($codice)) { if (!empty($data["extraInfo"])) { foreach($data["extraInfo"] AS $key => $value) { $this->saveExtraInfo($key,$value,"lotto"); } } return $codice; } } return false; } public function soloEconomica() { return (empty($this->getLottiOEPV())) ? true : false; } public function getLottiMP() { $lotti = $this->getLotti(); $return = []; if (!empty($lotti)) { foreach($lotti AS $lotto) { if ($lotto["criterio"] == "prezzo") { $return[] = $lotto; } } } return $return; } public function getLottiOEPV() { $lotti = $this->getLotti(); $return = []; if (!empty($lotti)) { foreach($lotti AS $lotto) { if ($lotto["criterio"] != "prezzo") { $return[] = $lotto; } } } return $return; } public function getIdAppalto() { return $this->info["codice"]; // TODO: Restituire l'id appalto rilasciato da ANAC } public function getExtraInfo() { $return = []; if (!empty($this->info["extraInfo"])) { $return["gara"] = json_decode($this->info["extraInfo"], true); } if (!empty($this->round["extraInfo"])) { $return["round"] = json_decode($this->round["extraInfo"], true); } if (!empty($this->lotto["extraInfo"])) { $return["lotto"] = json_decode($this->lotto["extraInfo"], true); } return $return; } public static function getStati() { return jsonToArray(__DIR__ . "/stati.json"); } /** * Restituisce la configurazione delle buste * * @param String|null $dataPubblicazione - Indicare la data di pubblicazione * @return Array */ public static function tipologieBusta(String $dataPubblicazione = "1970-01-01") : Array { $return = []; $return["amministrativa"] = ["titolo" => "Busta Amministrativa","emendabile"=>false,"secretabile"=>self::amministrativaSecretabile($dataPubblicazione)]; $return["tecnica"] = ["titolo" => "Busta Tecnica","emendabile"=>true,"secretabile"=>true]; $return["economica"] = ["titolo" => "Busta Economica","emendabile"=>true,"secretabile"=>true]; return $return; } public function busteDisponibili() { $return = self::tipologieBusta(); if (empty($this->getLottiOEPV()) || (isset($this->lotto) && $this->lotto["criterio"] == "prezzo")) { unset($return["tecnica"]); } return $return; } public function getRichieste($busta = NULL) { $bind = [":codice_round" => $this->round["codice"]]; $sql = "SELECT b_gare_richieste.* FROM b_gare_richieste "; if (!empty($this->lotto)) { $sql .= " JOIN r_gare_richieste_lotti ON b_gare_richieste.codice = r_gare_richieste_lotti.codice_richiesta "; } $sql .= " WHERE codice_round = :codice_round "; if (!empty($this->lotto)) { $sql .= " AND (r_gare_richieste_lotti.codice_lotto = 0 OR r_gare_richieste_lotti.codice_lotto = :lotto ) "; if ($this->lotto["criterio"] == "prezzo") { $sql .= " AND b_gare_richieste.busta <> 'tecnica' "; } $bind[":lotto"] = $this->lotto["codice"]; } if (!empty($busta)) { $bind[":busta"] = $busta; $sql .= " AND b_gare_richieste.busta = :busta "; } $sql .= " ORDER BY b_gare_richieste.ordinamento, b_gare_richieste.codice "; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } public function getRichiesta($codice) { $richieste = $this->getRichieste(); if (!empty($richieste)) { foreach($richieste AS $richiesta) { if ($richiesta["codice"] == $codice) { return $richiesta; } } } return false; } public function getRounds($codice = null) { $bind = [":codice_gara" => $this->info["codice"]]; $sql = "SELECT * FROM b_gare_round WHERE codice_gara = :codice_gara "; if ($codice !== null) { $bind[":codice"] = $codice; $sql .= " AND codice = :codice "; } return $this->db->go($sql . " ORDER BY numero", $bind)->fetchAll(PDO::FETCH_ASSOC); } public function fasiSuccessive() { $return = []; $procedura = $this->getProcedura(); if (!empty($procedura["fasi"])) { $found = false; foreach($procedura["fasi"] AS $key => $info) { if ($key == $this->round["id"]) { $found = true; if ($info["ripetibile"]) { $return[$key] = $info; } } else { if ($found) { $return[$key] = $info; break; } } } } return $return; } /** * getInmportiBaseAsta * * Aggiunge al lotto passato alla funzione le chiavi importoRibassabile e importoNonRibassabile in base alla configurazione del lotto * * @param Array $lotto * @param ?String $norma * @return Array */ public static function getImportiBaseAsta(Array $lotto, String $norma = null ) : Array { $lotto["importoRibassabile"] = (!empty($lotto["importoBase"])) ? $lotto["importoBase"] : 0; if ($norma != "2016-50") { $lotto["importoRibassabile"] += (!empty($lotto["importoManodopera"])) ? $lotto["importoManodopera"] : 0; } $lotto["importoNonRibassabile"] = (!empty($lotto["oneriNoRibasso"])) ? $lotto["oneriNoRibasso"] : 0; return $lotto; } public static function formatLotto($lotto,$niceNumbers = false) { $decimale = "."; $migliaia = ""; if ($niceNumbers) { $decimale = ","; $migliaia = "."; } if (!isset($lotto["importoRibassabile"])) { $lotto = static::getImportiBaseAsta($lotto); } if (!empty($lotto["importoRibassabile"])) { $lotto["importoRibassabile"] = number_format($lotto["importoRibassabile"],2,$decimale,$migliaia); } if (!empty($lotto["importoNonRibassabile"])) { $lotto["importoNonRibassabile"] = number_format($lotto["importoNonRibassabile"],2,$decimale,$migliaia); } if (!empty($lotto["importoBase"])) { $lotto["importoBase"] = number_format($lotto["importoBase"],2,$decimale,$migliaia); } if (!empty($lotto["importoManodopera"])) { $lotto["importoManodopera"] = number_format($lotto["importoManodopera"],2,$decimale,$migliaia); } if (!empty($lotto["oneriNoRibasso"])) { $lotto["oneriNoRibasso"] = number_format($lotto["oneriNoRibasso"],2,$decimale,$migliaia); } if (!empty($lotto["importoOpzioni"])) { $lotto["importoOpzioni"] = number_format($lotto["importoOpzioni"],2,$decimale,$migliaia); } $lotto["extraInfo"] = json_decode($lotto["extraInfo"],true); return $lotto; } public function getLotti($codice = null) { $bind = [":codice_gara" => $this->info["codice"]]; $sql = "SELECT * FROM b_gare_lotti WHERE codice_gara = :codice_gara "; if ($codice !== null) { $bind[":codice"] = $codice; $sql .= " AND codice = :codice "; } return $this->db->go($sql . " ORDER BY numero", $bind)->fetchAll(PDO::FETCH_ASSOC); } public function getAsta($object = false) { if (!empty($this->lotto)) { $bind = [":codice_lotto"=>$this->lotto["codice"],":codice_round"=>$this->round["codice"]]; $sql = "SELECT * FROM b_gare_aste WHERE codice_lotto = :codice_lotto AND codice_round = :codice_round"; $asta = $this->db->go($sql, $bind)->fetch(PDO::FETCH_ASSOC); if (!empty($asta)) { if ($object) { $asta = new asta($this,$asta); } return $asta; } } } public function getCategorieMerceologiche() { $codici_categoria = []; $sql_categoria = "SELECT codice FROM r_cpv_gare WHERE codice_gara = :codice "; $ris_custom = $this->db->go($sql_categoria, array(":codice" => $this->info["codice"])); if ($ris_custom->rowCount() > 0) { while ($categoria = $ris_custom->fetch(PDO::FETCH_ASSOC)) { if (!empty($categoria)) { $codici_categoria[] = $categoria["codice"]; } } } $codici_categoria = array_unique($codici_categoria); return $codici_categoria; } public static function getFormule() { return tuttogareMath::getFormule(); } public static function initStatic() { $gara = new self(); $gara->info = get_campi("b_gare"); return $gara; } public static function init($codice, $codice_round = NULL, $valutazione = NULL) { if (! empty($codice) && (defined("__CMDS_JOB_EXEC") || (! empty($_SESSION["utente"]) && ! empty($_SESSION["ente"])))) { global $pdo; $bind = [":codice" => $codice]; $sql = "SELECT * FROM b_gare WHERE codice = :codice "; if (! defined("__CMDS_JOB_EXEC") && ! $_SESSION["utente"]->fromHere() && !isset($valutazione)) { $sql .= " AND codice_ente = :codice_ente"; $bind[":codice_ente"] = $_SESSION["utente"]->codice_ente; } $gara = $pdo->go($sql, $bind)->fetch(PDO::FETCH_ASSOC); if (! empty($gara)) { $continua = false; $commissario = false; if ($valutazione !== NULL) { $check = $pdo->go( "SELECT r_commissione.codice, b_commissioni.scadenza FROM r_commissione JOIN b_commissioni ON r_commissione.codice_commissione = b_commissioni.codice WHERE r_commissione.codice_utente = :codice_utente AND b_commissioni.codice_elemento = :codice_round AND b_commissioni.modulo = \"gare\" AND b_commissioni.tipologia = :tipologia ", [":codice_utente" => $_SESSION["utente"]->codice, ":codice_round" => $codice_round, ":tipologia" => "commissione"] ); if ($check->rowCount() == 1) { $check = $check->fetch(PDO::FETCH_ASSOC); if (($valutazione == "commissione" && ($gara["stato"] == "21" || $gara["stato"] == "25") && strtotime($check["scadenza"]) > time())) { $continua = true; $commissario = true; } } } else { if (!defined("__CMDS_JOB_EXEC")) { $continua = $_SESSION["utente"]->permission("gare",$gara["codice"],"0",true); if ($continua) { if ($_SESSION["utente"]->gerarchia > 9 && $_SESSION["utente"]->codice_ente != $gara["codice_ente"] && $_SESSION["utente"]->codice_ente != $_SESSION["ente"]->codice) { $continua = false; } } } else { $continua = true; } } if ($continua) { $continua = false; $extensionClass= self::extensionExists(); if (!empty($extensionClass)) { $instance = new $extensionClass(); } else { $instance = new gara(); } $instance->info = $gara; $instance->commissario = $commissario; $instance->activeRound = false; $instance->quickAvailable = false; $instance->quickPanel = false; $instance->privata = false; $enteBeneficiario = Ente::getInfoFromID($gara["codice_ente"])[0] ?? null; if (isset($enteBeneficiario["soggettoPrivato"]) && $enteBeneficiario["soggettoPrivato"] == "S") { $instance->privata = true; } if ($instance->info["modalita"] == "extra" && $instance->getProcedura()["quick-extra"]) { $instance->quickAvailable = true; $instance->quickPanel = false; $quickPanel = $instance->getExtraInfo()["gara"]["quickPanel"] ?? null; if (isset($quickPanel) && $quickPanel == "S") { $instance->quickPanel = true; } } $rounds = $instance->getRounds(); $first = true; $timeRiferimentoNormativo = time(); if (!empty($rounds)) { foreach($rounds AS $round) { if ($first) { if (!empty($round["pubblicazione"])) { $timeRiferimentoNormativo = strtotime($round["pubblicazione"]); } $first = false; } if ($round["codice"] === $codice_round) { $instance->round = $round; } } if (empty($instance->round)) { $instance->round = $round; } $instance->round["infoFase"] = $instance->getProcedura()["fasi"][$instance->round["id"]] ?? []; } else { $instance->round = get_campi("b_gare_round"); $instance->round["numero"] = 1; } if ($instance->round["numero"] == $gara["fase_attiva"]) { $instance->activeRound = true; } if ($instance->round["numero"] < $gara["fase_attiva"]) { $instance->info["stato"] = 100; } if (isset($round) && $gara["stato"] == 20 && strtotime($round["scadenza"]) < time() && $instance->activeRound) { $instance->updateStato(21); } $extraInfo = $instance->getExtraInfo()["gara"] ?? null; if (!empty($extraInfo["normaRiferimento"]) && !empty(self::riferimentiNormativi()[$extraInfo["normaRiferimento"]])) { $instance->normaRiferimento = $extraInfo["normaRiferimento"]; } if (empty($instance->normaRiferimento)) { $instance->normaRiferimento = self::findRiferimentoNormativo($timeRiferimentoNormativo); } return $instance; } } } return false; } public static function findRiferimentoNormativo($time = null) { if (empty($time)) { return "2023-36"; } else { $versions = self::riferimentiNormativi(); if (!empty($versions)) { foreach($versions AS $key => $version) { $start = null; $end = null; if (!empty($version["inizio"])) { $start = strtotime($version["inizio"]); } if (!empty($version["fine"])) { $end = strtotime($version["fine"]); } if ((empty($start) || $start < $time) && (empty($end) || $end > $time)) { return $key; } } } } } public function getPublicExternalURL() { return "https://{$_SESSION["ente"]->getInfo()["dominio"]}/gare/dettaglio.php?codice={$this->info["codice"]}"; } public function getHubData() { if ($this->info["fase_attiva"] > 1 || $this->round['pubblica'] > 0) { $lotti = $this->getLotti(); $extraInfo = $this->getExtraInfo(); $return = [ 'b_hub_centrale' => [ 'codice_gestore'=> $_SESSION["ente"]->codice, 'codice_ente'=> $this->info["codice_ente"], 'codice_interno'=> $this->info["codice"], 'stato'=> $this->info["stato"], 'pubblica'=> $this->round["pubblica"], 'invito'=> (!$this->round["infoFase"]["aperta"]) ? "S" : "N", 'ambito'=> "gare", 'lotti'=> count($lotti), 'oggetto'=> $this->info["oggetto"], 'url'=> $this->getPublicExternalURL(), 'procedura'=> $this->info["procedura"], 'tipologia'=> $this->info["tipologia"], 'pubblicazione'=> mysql2datetime($this->round["pubblicazione"]), 'scadenza'=> mysql2datetime($this->round["scadenza"]), 'chiarimenti'=> mysql2datetime($this->round["chiarimenti"]), 'apertura'=> mysql2datetime($this->round["apertura"]), 'importo'=> $this->info["prezzoRiferimento"], 'nuts'=> $extraInfo["gara"]["nuts"], ] ]; if (!empty($lotti)) { $return['b_hub_cig'] = []; $return['b_hub_cup'] = []; foreach($lotti AS $lotto) { if (!empty($lotto["cig"])) { $return['b_hub_cig'][] = [ 'cig'=> $lotto["cig"], 'oggetto'=> $lotto["oggetto"], 'importo'=> $lotto["importoBase"] + $lotto["importoOpzioni"] + $lotto["importoManodopera"] + $lotto["oneriNoRibasso"], 'criterio'=> $lotto["criterio"] ]; } if (!empty($lotto["cup"])) { $return['b_hub_cup'][] = [ 'cup'=> $lotto["cup"], ]; } } } $cpv = $this->getCategorieMerceologiche(); if (!empty($cpv)) { $return['r_hub_cpv'] = []; foreach($cpv AS $categoria) { $return['r_hub_cpv'][] = [ 'codice' => $categoria, ]; } } $soa = $this->getSOA(); if (!empty($soa)) { $return['r_hub_soa'] = []; foreach($soa AS $categoria) { $return['r_hub_soa'][] = [ 'codice_categoria' => $categoria["codice_categoria"], ]; } } return $return; } } public function getProcedura() { $return = getProcedure(true, null, $this->info["timestamp_creazione"])[$this->info["procedura"]]; if ($this->info["accordo_quadro"] == "S") { $return["aggiudicazioneMultipla"] = true; } $return["key"] = $this->info["procedura"]; return $return; } public function getModalita() { return getModalita()[$this->info["modalita"]]; } public function getTotaleImporti() { $totale = self::getTotaleImportiFromTipologie($this->getExtraInfo()["gara"]["importi"]); return $totale; } public static function getTotaleImportiFromTipologie($tipologie) { $totale = 0; foreach ($tipologie as $importo) { $totale += $importo; } return $totale; } public function getInterpretazioneArt41() : String { $return = ""; if ($this->normaRiferimento == "2023-36") { $return = settingsManager::getValue("interpretazioneArt41"); if ($return == "chiedi") { $return = $this->getExtraInfo()["gara"]["interpretazioneArt41"] ?? "complessivo"; } } return $return; } public function updateBadges() { $badge = 0; $sql_bad = "SELECT b_gare_chiarimenti.codice FROM b_gare_chiarimenti JOIN b_gare_round ON b_gare_chiarimenti.codice_round = b_gare_round.codice JOIN b_gare ON b_gare_round.codice_gara = b_gare.codice WHERE b_gare_round.scadenza >= now() AND b_gare_chiarimenti.attivo = 'N' AND b_gare.codice = :codice "; $ris_badge = $this->db->go($sql_bad, [":codice" => $this->info["codice"]]); $badge += $ris_badge->rowCount(); $sql_bad = "SELECT b_gare_sopralluogo.codice FROM b_gare_sopralluogo JOIN b_gare_round ON b_gare_sopralluogo.codice_round = b_gare_round.codice JOIN b_gare ON b_gare_round.codice_gara = b_gare.codice WHERE b_gare_round.scadenza >= now() AND b_gare_sopralluogo.attivo = 'P' AND b_gare.codice = :codice "; $ris_badge = $this->db->go($sql_bad, [":codice" => $this->info["codice"]]); $badge += $ris_badge->rowCount(); $this->db->go("UPDATE b_gare SET badge = :badge WHERE codice = :codice", [":badge" => $badge, ":codice" => $this->info["codice"]]); } public function printOfferEconomica($edit = true, $bozza = true, $data = false) { if (!empty($this->lotto)) { $model = new editorManager("economica-gare", "gare-preview-" . $this->round["codice"]); if (!empty($model)) { $criteriEconomici = $this->getCriteriEconomici(); if (!empty($criteriEconomici)) { $inputs = []; $first = true; global $beRoot; $receveidData = $data; if (!empty($data) && is_numeric($data)) { $dettagli = $this->db->prepare("SELECT offerta,codice_partecipante FROM b_dettaglio_offerte_gare WHERE codice_offerta = :codice_offerta AND codice_dettaglio = :codice_dettaglio AND offerta IS NOT NULL"); $dettagli->bindValue(":codice_offerta", $data); } foreach($criteriEconomici AS $criterio) { if (!empty($criterio["auto"])) { ob_start(); if ($criterio["tipologia"] != "E") { $this->printOfferCriterio($criterio["codice"],$edit,$bozza,$data); } else { $elencoPrezzi = $this->getElencoPrezzi($criterio["codice"]); if (!empty($elencoPrezzi)) { ob_start(); include($beRoot . "/common/criteri/inputs/ep-input.php"); $inputs[] = ob_get_clean(); } else { alertManager::printAlertBox($criterio["denominazione"],__("Errore configurazione")); } } $inputs[] = ob_get_clean(); if ($first) { $parentCriteria = $criterio; $first = false; } } } if (!empty($parentCriteria)) { $model->vocabolario["gare"] = $this->info; $model->vocabolario["fase"] = $this->round; $formattedLotto = self::formatLotto($this->lotto,true); $model->vocabolario["lotto"] = $formattedLotto; if ($this->normaRiferimento == "2016-50") { $importi = __("Prezzo a base") . ": € " . $formattedLotto["importoBase"]; if ($this->lotto["importoManodopera"] > 0) { $importi .= " " . strtolower(__("di cui")) . " € " . $formattedLotto["importoManodopera"] . " " . strtolower(__("per costi della manodopera")); } $importi .= "
" . __("oneri per la sicurezza") . ": € " . $formattedLotto["oneriNoRibasso"]; } else if ($this->normaRiferimento == "2023-36") { if ($this->getInterpretazioneArt41() === "complessivo") { $importi = "Importo posto a base di gara: € " . $formattedLotto["importoRibassabile"]. ": "; $importi .= __("oneri per la sicurezza") . ": € " . $formattedLotto["oneriNoRibasso"]; } else { $importi = ""; } } $model->vocabolario["lotto"]["importi"] = $importi; if (!empty($receveidData) && is_numeric($receveidData)) { $dettagli->bindValue(":codice_dettaglio", $parentCriteria["codice"] . ".01"); $dettagli->execute(); if ($dettagli->rowCount() > 0) { $det = $dettagli->fetch(PDO::FETCH_ASSOC); $partecipante = $this->getPartecipante($det["codice_partecipante"]); $list_partecipanti = $this->listPartecipanti($partecipante["codice"]); $valore_sicurezza = $det["offerta"]; } $dettagli->bindValue(":codice_dettaglio", $parentCriteria["codice"] . ".02"); $dettagli->execute(); if ($dettagli->rowCount() > 0) { $valore_manodopera = $dettagli->fetch(PDO::FETCH_ASSOC)["offerta"]; } $data = []; $tmpCriterio["codice"] = $parentCriteria["codice"] . ".01"; $data[$tmpCriterio["codice"]] = $valore_sicurezza ?? ""; $tmpCriterio["codice"] = $parentCriteria["codice"] . ".02"; $data[$tmpCriterio["codice"]] = $valore_manodopera ?? ""; $data["partecipanti"] = $list_partecipanti; } $criterio = []; $criterio["denominazione"] = "ONERI SICUREZZA AZIENDALE"; $criterio["descrizione"] = "(esprimere il valore in cifre al netto di IVA)"; $criterio["codice"] = $parentCriteria["codice"] . ".01"; $criterio["decimali"] = $parentCriteria["decimali"]; $criterio["auto"] = ""; $criterio["vincoli"] = ""; ob_start(); include($beRoot . "/common/criteri/inputs/offer-input.php"); $inputs[] = ob_get_clean(); $criterio = []; $criterio["denominazione"] = "COSTO DELLA MANODOPERA"; $criterio["descrizione"] = "(esprimere il valore in cifre al netto di IVA)"; $criterio["codice"] = $parentCriteria["codice"] . ".02"; $criterio["decimali"] = $parentCriteria["decimali"]; $criterio["auto"] = ""; $criterio["vincoli"] = ""; ob_start(); include($beRoot . "/common/criteri/inputs/offer-input.php"); $inputs[] = ob_get_clean(); if (isset($data["partecipanti"])) { $model->vocabolario["partecipanti"] = $data["partecipanti"]; } } if (!empty($inputs)) { $inputs = implode("",$inputs); } } $criteriTecnici = $this->getCriteriTecnici(); if (!empty($criteriTecnici)) { if (!empty($receveidData)) { $data = $receveidData; } $inputsTecnici = []; foreach($criteriTecnici AS $criterio) { if (!empty($criterio["auto"]) && $criterio["busta"] == "economica") { ob_start(); $this->printOfferCriterio($criterio["codice"],$edit,$bozza,$data); $inputsTecnici[] = ob_get_clean(); } } if (!empty($inputsTecnici)) { $inputsTecnici = "

" . __("ELEMENTI NON ECONOMICI DELL'OFFERTA") . "



" . implode("",$inputsTecnici); if (empty($inputs)) { $inputs = $inputsTecnici; } else { $inputs .= $inputsTecnici; } } } if (!empty($inputs)) { $model->vocabolario["inputs"] = $inputs; $model = $model->getModello(); echo $model; } } } } public function printOfferCriterio($codice_criterio, $edit = true, $bozza = true, $data = false,$annotazioni = null) { $criterio = $this->getCriteri($codice_criterio)[0]; $criterio["vincoli"] = ""; if (!empty($criterio["auto"])) { if (!empty($data) && is_numeric($data)) { $dettagli = $this->db->prepare("SELECT offerta FROM b_dettaglio_offerte_gare WHERE codice_offerta = :codice_offerta AND codice_dettaglio = :codice_dettaglio AND offerta IS NOT NULL"); $dettagli->bindValue(":codice_offerta", $data); } global $beRoot; include($beRoot . "/common/criteri/inputs/offer-input.php"); } } public function printFormCriterio($codice_criterio, $edit = true, $bozza = true, $data = 0) { $criterio = $this->getCriteri($codice_criterio)[0]; $form = $this->getFormCriterio($codice_criterio); if (!empty($form)) { $attachID = "gare-form"; $dataSql = "SELECT codice, content FROM b_gare_form_data WHERE codice_input = :input AND codice_offerta = :offerta "; $viewFormAttachPath = "/backend/gare/open/viewFormAttachment.php"; global $beRoot; include($beRoot . "/common/criteri/inputs/form-input.php"); } } public function getLottiFromCriterio($codice_criterio) { if (!empty($this->getCriteri($codice_criterio))) { return $this->db->go("SELECT codice_lotto FROM r_gare_criteri_lotti WHERE codice_criterio = :criterio",[":criterio"=>$codice_criterio])->fetchAll(PDO::FETCH_COLUMN); } } public function getLottiFromRichiesta($codice_richiesta) { if (!empty($this->getRichiesta($codice_richiesta))) { return $this->db->go("SELECT codice_lotto FROM r_gare_richieste_lotti WHERE codice_richiesta = :richiesta",[":richiesta"=>$codice_richiesta])->fetchAll(PDO::FETCH_COLUMN); } } public function getCriteriEconomici() { return $this->returnCriteri($this->round["codice"], ["economico" => "S"]); } public function getCriteriTecnici() { return $this->returnCriteri($this->round["codice"], ["economico" => "N"]); } public function getCriteriValutabili($codice_criterio = NULL) { $tmpCriteri = $this->getCriteri($codice_criterio); $criteri = []; if (count($tmpCriteri) > 0) { foreach ($tmpCriteri as $criterio) { if (empty($this->getSubCriteri($criterio["codice"]))) { $criteri[] = $criterio; } } } return $criteri; } public function getCriteriTecniciValutabili() { $tmp = $this->getCriteriValutabili(); $criteri = []; foreach ($tmp as $criterio) { if ($criterio["economico"] == "N") { $criteri[] = $criterio; } } return $criteri; } public function getCriteriEconomiciValutabili() { $tmp = $this->getCriteriValutabili(); $criteri = []; foreach ($tmp as $criterio) { if ($criterio["economico"] == "S") { $criteri[] = $criterio; } } return $criteri; } public function returnCriteri($codice_round, $filters = []) { if (!empty($this->getRounds($codice_round))) { $bind = [":codice_round" => $codice_round]; $keysFilters = array_keys(get_campi("b_gare_criteri_valutazione")); $sql = "SELECT b_gare_criteri_valutazione.* FROM b_gare_criteri_valutazione "; if (!empty($this->lotto) && empty($filters["ignore-lotto"])) { $sql .= " JOIN r_gare_criteri_lotti ON b_gare_criteri_valutazione.codice = r_gare_criteri_lotti.codice_criterio "; } $sql .= " WHERE b_gare_criteri_valutazione.codice_round = :codice_round "; if (!empty($this->lotto) && empty($filters["ignore-lotto"])) { $sql .= " AND (r_gare_criteri_lotti.codice_lotto = 0 OR r_gare_criteri_lotti.codice_lotto = :lotto ) "; if ($this->lotto["criterio"] == "prezzo") { $sql .= " AND b_gare_criteri_valutazione.economico = 'S' "; } $bind[":lotto"] = $this->lotto["codice"]; } foreach ($filters as $key => $value) { if (in_array($key, $keysFilters, true) !== false) { $bind[":{$key}"] = $value; $sql .= " AND b_gare_criteri_valutazione.{$key} = :{$key} "; } else { if ($key != "ignore-lotto") { return null; } } } $sql .= " GROUP BY b_gare_criteri_valutazione.codice ORDER BY b_gare_criteri_valutazione.ordinamento, b_gare_criteri_valutazione.codice "; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getElencoPrezzi($codice_criterio) { return $this->db->go("SELECT * FROM b_gare_ep WHERE codice_criterio = :criterio ORDER BY ordinamento,codice",[":criterio"=>$codice_criterio])->fetchAll(PDO::FETCH_ASSOC); } public function printCriteriaTable() { $criteri = $this->getMacroCriteri(); if (!empty($criteri)) { global $beRoot; include($beRoot . "/common/criteri/model-table.php"); } } public function getDestinatariInterni(bool $onlyCode = false) { return $this->getManagerRegistro()->getUtentiCoinvoltiConRuolo("USR",$onlyCode); } public function chooseLotto($input,$target,$stati = []) { $lotti = $this->getLotti(); if (!empty($lotti)) { if (count($lotti) > 1) { if (!empty($input)) { $setLotto = $input; } } else { $setLotto = $lotti[0]["codice"]; } if (!empty($setLotto)) { if ($this->setLotto($setLotto)) { return true; } } else { $this->printSelectLotto($target,false,$stati); return false; } } return false; } public function printSelectLotto($target,$allOption = false,$stati = []) { include(__DIR__."/lotti/selectView.php"); } public function valutaStatoGenerale(?bool $force = false) { $lotti = $this->getLotti(); $stati = []; $lottiCompleti = 0; foreach($lotti AS $lotto) { //if ($lotto["stato"] > 0) { if (in_array($lotto["stato"],self::statiTermineProcedura())) { $lottiCompleti++; } $stati[] = $lotto["stato"]; //} } if (!empty($stati) && count($stati) == count($lotti)) { $stati = array_unique($stati); if (count($stati) === 1) { $this->updateStato($stati[0],$force); } else { $stato = 25; if (count($lotti) == $lottiCompleti) { $stato = 100; } $this->updateStato($stato,$force); } } } public static function ruoloAvvalimento(int $index) { return ["Requisito", "Miglioramento d'offerta"][$index-1] ?? "SCONOSCIUTO"; } public function savePartecipante($partecipante) { if (!empty($partecipante["codice"]) || !$this->getModalita()["online"]) { $continua = false; if (!empty($partecipante["codice"])) { if (!empty($this->getPartecipante($partecipante["codice"],true))) { $continua = true; unset($partecipante["codice_operatore"]); } } else { if (!isset($partecipante["codice_operatore"])) { $partecipante["codice_operatore"] = 0; } $partecipante["conferma"] = "S"; $continua = true; } if ($continua) { $partecipante["ruolo"] = (!empty($partecipante["raggruppamento"])) ? "04-CAPOGRUPPO" : ""; $partecipante["codice_lotto"] = $this->lotto["codice"]; $partecipante["codice_round"] = $this->round["codice"]; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "r_partecipanti_gare"; $salva->operazione = empty($partecipante["codice"]) ? "INSERT" : "UPDATE"; $salva->oggetto = $partecipante; if($salva->operazione === "INSERT") { $salva->oggetto["uuid"] = uuidgen_v4(); } $codice = $salva->save(); if ($codice > 0) { $this->db->go("DELETE FROM r_raggruppamenti_gare WHERE codice_padre = :codice",[":codice"=>$codice]); if (!empty($partecipante["raggruppamento"])) { foreach($partecipante["raggruppamento"] as $sub) { $sub["codice_padre"] = $codice; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "r_raggruppamenti_gare"; $salva->operazione = "INSERT"; $salva->oggetto = $sub; $salva->save(); } } $this->db->go("DELETE FROM r_avvalimenti_gare WHERE codice_padre = :codice",[":codice"=>$codice]); if (!empty($partecipante["avvalimento"])) { foreach($partecipante["avvalimento"] as $sub) { if(empty($sub["identifier_raggruppamento"]) || $sub["identifier_raggruppamento"] === "PARENT") { $sub["identifier_raggruppamento"] = null; } $sub["codice_padre"] = $codice; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "r_avvalimenti_gare"; $salva->operazione = "INSERT"; $salva->oggetto = $sub; $salva->save(); } } $this->addToLog(empty($partecipante["codice"]) ? "INSERT" : "UPDATE",__("Partecipante") . " #" . $codice); return $codice; } } return false; } } public function saveCriterio($criterio) { if (!empty($this->round)) { $continua = true; if (!empty($criterio["codice_padre"])) { $check = $this->getCriteri($criterio["codice_padre"]); if (!empty($check)) { $check = $check[0]; if (!empty($check["auto"])) { $continua = false; } else { $form = $this->getFormCriterio($check["codice"]); if (!empty($form)) { $continua = false; } } } } if ($continua) { $criterio["codice_round"] = $this->round["codice"]; if ($criterio["tipologia"] == "Q") { $criterio["auto"] = ""; $criterio["options"] = ""; } else { if (isset($criterio["auto"]) && !empty(($criterio["options"][$criterio["auto"]]))) { $criterio["options"] = json_encode($criterio["options"][$criterio["auto"]]); } else { $criterio["options"] = ""; } } if ($criterio["economico"] == "S") { $criterio["busta"] = "economica"; } $operazione = (is_numeric($criterio["codice"])) ? "UPDATE" : "INSERT"; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_criteri_valutazione"; $salva->operazione = $operazione; $salva->ignore = ["timestamp_modifica"]; $salva->oggetto = $criterio; $codice = $salva->save(); if ($codice !== false) { if ($operazione == "INSERT") { $this->bindCriterio($codice); } if ($criterio["tipologia"] != "Q") { $this->db->go("DELETE FROM b_gare_form WHERE codice_criterio = :codice",[":codice"=>$codice]); scriviLog("b_gare_form","DELETE",$this->db->getSQL(),$codice); } $subCriteri = $this->getSubCriteri($codice); if (!empty($subCriteri)) { foreach($subCriteri AS $sub) { $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_criteri_valutazione"; $salva->operazione = "UPDATE"; $salva->oggetto = [ "codice" => $sub["codice"], "decimali" => $criterio["decimali"], "economico" => $criterio["economico"], "tipologia" => $criterio["tipologia"], ]; $salva->save(); } } $this->checkRichiesteOnEditCriteri(); return $codice; } } } return false; } public function deleteCriterio(Int $codice) { $lock = $this->checkLock("criteri"); if (!$lock) { if (!empty($this->getCriteri($codice))) { $bind = array(":codice"=>$codice); $sql = "DELETE FROM b_gare_criteri_valutazione WHERE codice_padre = :codice "; $ris = $this->db->go($sql,$bind); $sql = "DELETE FROM b_gare_criteri_valutazione WHERE codice = :codice "; $ris = $this->db->go($sql,$bind); if ($ris->rowCount() === 1) { scriviLog("b_gare_criteri_valutazione","DELETE",$this->db->getSQL(),$codice); $error = false; $this->addToLog("DELETE",__("Criterio") . "#" . $codice); $this->checkRichiesteOnEditCriteri(); return true; } } } return false; } public function bindCriterio($criterio,$lotti = 0) { $this->db->go("DELETE FROM r_gare_criteri_lotti WHERE codice_criterio = :codice",[":codice"=>$criterio]); $insert = $this->db->prepare("INSERT INTO r_gare_criteri_lotti (codice_criterio,codice_lotto) VALUES (:criterio,:lotto)"); $insert->bindValue(":criterio",$criterio); $return = true; if (is_array($lotti)) { $ok = 0; foreach($lotti AS $lotto) { $insert->bindValue(":lotto",$lotto); $insert->execute(); if ($insert->rowCount() === 1) { $ok++; } } if (count($lotti) != $ok) { $return = false; } } else { $insert->bindValue(":lotto",0); $insert->execute(); if ($insert->rowCount() !== 1) { $return = false; } } if ($return) { $sub = $this->getSubCriteri($criterio); if (!empty($sub)) { foreach($sub AS $c) { $this->bindCriterio($c["codice"],$lotti); } } } $this->checkRichiesteOnEditCriteri(); return $return; } public function saveVociEP($criterio,$voci) { $codici = []; $error_input = ""; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_ep"; $ordinamento = 0; if (!empty($voci)) { foreach($voci AS $codice_input => $input) { if (is_numeric($codice_input)) { $input["codice"] = $codice_input; } if (empty($input["ordinamento"]) && !is_numeric($codice_input)) { $input["ordinamento"] = $ordinamento; } $input["codice_criterio"] = $criterio; $salva->operazione = (is_numeric($codice_input)) ? "UPDATE" : "INSERT"; $salva->oggetto = $input; $cod_input = $salva->save(); $codici[] = $cod_input; if (empty($cod_input)) { $error_input .= "
Error: " . $input["titolo"]; } $ordinamento++; } } if (empty($error_input)) { $codici = implode(",",$codici); $this->db->go("DELETE FROM b_gare_ep WHERE codice_criterio = :criterio AND codice NOT IN (".$codici.")",[":criterio"=>$criterio]); $this->addToLog("UPDATE",__("Elenco prezzi") . " - " . __("Criterio") . " #" . $criterio); } $this->checkRichiesteOnEditCriteri(); return $error_input; } public function saveRichiesta($richiesta) { if (!empty($this->busteDisponibili($richiesta["busta"]))) { if (empty($richiesta["codice"])) { $richiesta["ordinamento"] = count($this->getRichieste($richiesta["busta"])); } $richiesta["codice_round"] = $this->round["codice"]; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_richieste"; $salva->operazione = (!empty($richiesta["codice"])) ? "UPDATE" : "INSERT"; $salva->oggetto = $richiesta; $codice = $salva->save(); if (!empty($codice)) { if (empty($richiesta["codice"])) { $this->bindRichiesta($codice); } if (isset($richiesta["allegato-public"])) { foreach($richiesta["allegato-public"] as $allegato) { filesManager::saveFile($allegato["filename"],$codice,"gare-richiesta",$allegato["nome"] ?? "","A",$allegato["classificazione"] ?? ""); } } $this->addToLog($salva->operazione,__("Richiesta").": " . $richiesta["titolo"]); return $codice; } } return false; } public function deleteRichiesta($richiesta) { $richiesta = $this->getRichiesta($richiesta); if (!empty($richiesta) && $richiesta["locked"] == "N") { $sql = "DELETE FROM b_gare_richieste WHERE codice = :codice "; $ris = $this->db->go($sql,[":codice"=>$richiesta["codice"]]); if ($ris->rowCount() === 1) { scriviLog("b_gare_richieste","DELETE",$this->db->getSQL(),$richiesta["codice"]); $this->addToLog("DELETE",__("Richiesta").": " . $richiesta["titolo"]); return true; } } return false; } public function bindRichiesta($richiesta,$lotti = 0) { $this->db->go("DELETE FROM r_gare_richieste_lotti WHERE codice_richiesta = :codice",[":codice"=>$richiesta]); $check = $this->db->prepare("SELECT codice FROM r_gare_richieste_lotti WHERE codice_richiesta = :richiesta AND (codice_lotto = :lotto OR codice_lotto = 0)"); $insert = $this->db->prepare("INSERT INTO r_gare_richieste_lotti (codice_richiesta,codice_lotto) VALUES (:richiesta,:lotto)"); $insert->bindValue(":richiesta",$richiesta); $check->bindValue(":richiesta",$richiesta); if (is_array($lotti)) { $ok = 0; foreach($lotti AS $lotto) { $insert->bindValue(":lotto",$lotto); $check->bindValue(":lotto",$lotto); $check->execute(); if ($check->rowCount() === 0) { $insert->execute(); if ($insert->rowCount() === 1) { $ok++; } } else { $ok++; } } if (count($lotti) == $ok) { return true; } } else { $insert->bindValue(":lotto",0); $check->bindValue(":lotto",0); $check->execute(); if ($check->rowCount() === 0) { $insert->execute(); if ($insert->rowCount() === 1) { return true; } } else { return true; } } return false; } public function checkRichiesteOnEditCriteri() { if ($this->getModalita()["online"]) { $lottoSelezionato = $this->lotto; $this->lotto = null; $criteri = $this->getAllCriteri(); $binds = []; $tipologie = self::tipologieBusta(); $tipologie = array_keys($tipologie); $allLotti = $this->getLotti(); if (!empty($criteri)) { foreach ($criteri as $criterio) { $sub = $this->getSubCriteri($criterio["codice"]); if (empty($sub)) { $type = null; $lotti = $this->getLottiFromCriterio($criterio["codice"]); if (!empty($lotti)) { if (!empty($criterio["auto"])) { if ($criterio["economico"] == "S" || $criterio["busta"] == "economica") { $type = "economica"; } else if ($criterio["economico"] == "N") { $type = "tecnica"; } } else if ($criterio["tipologia"] == "Q" && !empty($this->getFormCriterio($criterio["codice"]))) { $type = "tecnica"; } if (!empty($type)) { if (!isset($binds[$type])) { $binds[$type] = []; } $binds[$type] = array_merge($binds[$type],$lotti); } } } } } foreach ($tipologie as $busta) { $bind = []; $bind[":codice_round"] = $this->round["codice"]; $bind[":busta"] = $busta; if (isset($binds[$busta])) { $check = $this->db->go("SELECT codice FROM b_gare_richieste WHERE codice_round = :codice_round AND busta = :busta AND locked = 'S'", $bind); if ($check->rowCount() == 0) { $richiesta = []; $richiesta["codice_round"] = $this->round["codice"]; $richiesta["busta"] = $busta; $richiesta["titolo"] = __("Offerta {$busta}"); $richiesta["descrizione"] = __("Caricare il file generato dal sistema in merito alla compilazione dell'offerta {$busta}"); $richiesta["controllo"] = "F"; $richiesta["ordinamento"] = 0; $richiesta["locked"] = "S"; $codiceRichiesta = $this->saveRichiesta($richiesta); } else { $codiceRichiesta = $check->fetch(PDO::FETCH_COLUMN); } if (count($binds[$busta]) == count($allLotti)) { $lotti = 0; } else { $lotti = $binds[$busta]; } $this->bindRichiesta($codiceRichiesta,$lotti); } else { $this->db->go("DELETE FROM b_gare_richieste WHERE busta = :busta AND locked = 'S' AND codice_round = :codice_round",[":busta"=>$busta,":codice_round"=>$this->round["codice"]]); scriviLog("b_gare_richieste", "DELETE", $this->db->getSQL()); } } $this->lotto = $lottoSelezionato; } } public function getCPVLotto(int $codice_lotto) : ?string { $res = $this->db->go( "SELECT cpv FROM b_gare_lotti WHERE codice_gara = :codice AND codice = :codice_lotto LIMIT 1", [":codice" => $this->info["codice"], ":codice_lotto" => $codice_lotto] ); if ($res->rowCount() < 1) return null; $categoria = $res->fetch(PDO::FETCH_ASSOC)["cpv"] ?? ""; if(empty($categoria)) return null; return str_pad($categoria, 8, "0", STR_PAD_RIGHT); } public function getSOASerialize($codice_lotto = null) { $soaLotto = $this->getSOA($codice_lotto); $categorie = getCategorieSOA(); foreach($soaLotto as $key => $soa ) { $soaLotto[$key]["categoria"] = $categorie[$soa["codice_categoria"]]["id"]; unset($soaLotto[$key]["codice_categoria"]); $soaLotto[$key]["prevalente"] = $soa["prevalente"] == "S"; } return $soaLotto; } public function getSOA($codice_lotto = null) { if (!isset($codice_lotto) && !empty($this->lotto)) { $codice_lotto = $this->lotto["codice"]; } if (!empty($codice_lotto)) { return $this->db->go("SELECT * FROM b_gare_soa WHERE codice_lotto = :lotto",[":lotto"=>$codice_lotto])->fetchAll(PDO::FETCH_ASSOC); } } public function getDettaglioSOA($forceAll = false) { $prevalenti = []; $scorporabili = []; $totale_sios = 0; $sios = []; $qo = []; $no_qo = []; $sios_30 = []; $sios_no_30 = []; $tutelate = []; $scorporabili = []; $og11 = []; $vincoli_soa = []; $flag_sios = false; $categorie = getCategorieSOA(); $classifica = $this->db->prepare("SELECT * FROM b_classifiche_soa WHERE attivo = 'S' AND minimo <= :importo AND (massimo >= :importo OR massimo = 0)"); if (empty($this->lotto) || $forceAll) { $lottiCheck = $this->getLotti(); } else { $lottiCheck = [$this->lotto]; } foreach($lottiCheck AS $lotto) { $soa = $this->getSOA($lotto["codice"]); if (!empty($soa)) { $vincoli_soa[] = 11; foreach($soa AS $categoria) { if ($categoria["prevalente"] == "S") { $variabile = &$prevalenti; } else { $variabile = &$scorporabili; } if (!isset($variabile[$categoria["codice_categoria"]])) { $variabile[$categoria["codice_categoria"]] = 0; } $variabile[$categoria["codice_categoria"]] += $categoria["importo"]; } } } if (!empty($scorporabili)) { foreach($scorporabili AS $id => $importo) { $categoria = $categorie[$id] ?? null; if (!empty($categoria)) { if ($categoria["sios"] == "S") { if ((($importo * 100) / $this->info["prezzoRiferimento"]) > 15) { $flag_sios = true; $vincoli_soa[] = 1; $sios[] = $categoria["id"]; $totale_sios += $importo; $classifica->bindValue(":importo",$importo); $classifica->execute(); if ($classifica->rowCount() > 0) { $cl = $classifica->fetch(PDO::FETCH_ASSOC); $classifica->bindValue(":importo",$importo * 0.7); $classifica->execute(); if ($classifica->rowCount() > 0) { $cl_ridotta = $classifica->fetch(PDO::FETCH_ASSOC); if ($cl_ridotta["id"] != $cl["id"]) { $sios_30[] = $categoria["id"]; $vincoli_soa[] = 2; } else { $sios_no_30[] = $categoria["id"]; $vincoli_soa[] = 3; } } } } } if ($categoria["obbligo_qualificazione"] == "S" && !$flag_sios) { if (((($importo*100)/$this->info["prezzoRiferimento"]) > 10) || $importo > 150000) { $vincoli_soa[] = 6; $qo[] = $categoria["id"]; } } if ($categoria["obbligo_qualificazione"] == "N") { $vincoli_soa[] = 7; $no_qo[] = $categoria["id"]; } if ($categoria["tutelate"] == "N") { $vincoli_soa[] = 8; $tutelate[] = $categoria["id"]; } if ($categoria["id"] == "OG 11") { $vincoli_soa[] = 9; } if (($categoria["id"] == "OS 3") || ($categoria["id"] == "OS 28") || ($categoria["id"] == "OS 30")) { if (!isset($og11[$categoria["id"]])) { $og11[$categoria["id"]] = 0; } $og11[$categoria["id"]] += $categoria["importo_base"]; } } } } else { $vincoli_soa[] = 10; } if (empty($tutelate)) { $vincoli_soa[]=13; } if (count($og11)==3) { $flag = 0; foreach($og11 AS $key=>$importo) { switch($key) { case "OS 3": if ((($importo*100)/$this->info["prezzoRiferimento"]) >= 10) { $flag++; } break; case "OS 28": if ((($importo*100)/$this->info["prezzoRiferimento"]) >= 25) { $flag++; } break; case "OS 30": if ((($importo*100)/$this->info["prezzoRiferimento"]) >= 25) { $flag++; } break; } } if ($flag == 3) { $vincoli_soa[]=9; } } if ($totale_sios>0) { if (($this->info["prezzoRiferimento"] - ($totale_sios*0.7))>20658000) { $vincoli_soa[] = 4; } else { $vincoli_soa[] = 5; } } else { $vincoli_soa[] = 12; } $vincoli_soa = array_unique($vincoli_soa); $sios = implode(",",$sios); $qo = implode(",",$qo); $no_qo = implode(",",$no_qo); $sios_30 = implode(",",$sios_30); $sios_no_30 = implode(",",$sios_no_30); $tutelate = implode(",",$tutelate); return ["vincoli_soa" => $vincoli_soa, "sios" => $sios, "qo" => $qo, "no_qo" => $no_qo, "sios_30" => $sios_30, "sios_no_30" => $sios_no_30, "tutelate" => $tutelate, "prevalenti" => $prevalenti, "scorporabili" => $scorporabili]; } public function getProgettazione($codice_lotto = null) { if (!isset($codice_lotto) && !empty($this->lotto)) { $codice_lotto = $this->lotto["codice"]; } if (!empty($codice_lotto)) { $where = " codice_lotto = :lotto "; $bind = [":lotto"=>$codice_lotto]; } else { $bind = [":gara"=>$this->info["codice"]]; $where = " codice_lotto IN (SELECT codice FROM b_gare_lotti WHERE codice_gara = :gara) "; } if (!empty($where)) { return $this->db->go("SELECT * FROM b_gare_progettazione WHERE {$where}",$bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getCriteri($codice = NULL) { $filters = []; if (!empty($codice)) { $filters = ["codice" => $codice]; } return $this->returnCriteri($this->round["codice"], $filters); } public function getAllCriteri($codice = NULL) { $filters = ["ignore-lotto"=>true]; if (!empty($codice)) { $filters = ["codice" => $codice]; } return $this->returnCriteri($this->round["codice"], $filters); } public function getMacroCriteri() { return $this->returnCriteri($this->round["codice"], ["codice_padre" => 0]); } public function getSubCriteri($codice_padre) { return $this->returnCriteri($this->round["codice"], ["codice_padre" => $codice_padre]); } public function getFormCriterio($codice_criterio) { $risultato = $this->db->go("SELECT * FROM b_gare_form WHERE codice_criterio = :codice_criterio ORDER BY ordinamento, codice", array(":codice_criterio" => $codice_criterio)); if ($risultato->rowCount() > 0) { return $risultato->fetchAll(PDO::FETCH_ASSOC); } return false; } private static function defaultAutenticationLevel() { return $_SESSION["ente"]->defaultAutenticationLevel(); } public function checkLock($id_cmd,$checkStato = null) { $return = true; $stato = $this->info["stato"]; if (!empty($this->lotto) && $this->lotto["stato"] > 0) { $stato = $this->lotto["stato"]; } if (!empty($checkStato)) { $stato = $checkStato; } if ($_SESSION["utente"]->readOnly) { return true; } else { if ($_SESSION["utente"]->hasSuperPowers()) { $return = false; } else { if (($stato >= 0) && !empty($id_cmd) && $_SESSION["utente"]->unlockSupporto()) { $cmd = self::getInfoModulo($id_cmd); if ($cmd !== false) { $loa = $cmd["authenticationLevel"] ?? self::defaultAutenticationLevel(); if ($_SESSION["utente"]->authenticationLevel < $loa) { return true; } if (isset($this->round)) { if ($this->round["numero"] >= $this->info["fase_attiva"]) { if (!$this->quickPanel) { if (($stato >= $cmd["stato_minimo"] || $cmd["stato_minimo"] == null) && ($stato <= $cmd["stato_massimo"] || $cmd["stato_massimo"] === null)) { $return = false; } if (!$return) { if ($cmd["apertura"] && time() < strtotime($this->round["apertura"])) { $return = true; } if ($cmd["scaduta"] && time() < strtotime($this->round["scadenza"])) { $return = true; } } } else { $return = false; } } } else { $return = false; } } } } } if ($return) { if($id_cmd == "partecipanti") { $npa = $this->getNpaInstance(); if(!empty($npa)) { $return = $npa->hasLockOnPartecipanti(false); } } if($id_cmd == "definitiva") { $npa = $this->getNpaInstance(); if(!empty($npa)) { $return = $npa->hasLockOnPartecipanti(true); } else if (!$this->usaGraduatoria()) { $return = false; } } } if ($id_cmd == "lotti" || $id_cmd == "criteri" || $id_cmd == "buste") { if ((($this->checkPartecipantiPresenti() && !$_SESSION["utente"]->hasSuperPowers()) || $this->info["stato"] > 20) && !$this->quickPanel) { $return = true; } if ($id_cmd == "lotti") { $npa = $this->getNpaInstance(); if (!empty($npa)) { $return = (!empty($npa->fascicolo["id_appalto"]) || !empty($npa->fascicolo["id_pianificazione"])); // Se sarebbe bloccato, verifichiamo che non ci siano modifiche/rettifiche in corso if($return) { $return = !$npa->hasPendingRettificheOrModifiche(null, ["CM1", "CM2"]); } } } } /*if ($id_cmd == "partecipanti") { $npa = $this->getNpaInstance(); if (!empty($npa)) { $return = $npa->hasConfirmedParticipantsCards(); } }*/ if ($id_cmd == "inviti" && $this->round["numero"] > 1 && !$_SESSION["utente"]->hasSuperPowers() && (!$this->round["infoFase"]["estrazione"] ?? true)) { $return = true; } if ($id_cmd == "preliminari" && !empty($this->getRounds())) { $return = true; } if(in_array($id_cmd, ["provvisoria", "definitiva"], true) && $return) { $npa = $this->getNpaInstance(); if(!empty($npa)) { $return = !$npa->hasPendingRettificheOrModifiche(null, ["S4"]); } } return $return; } public function alertModifichePericolose($id_cmd) { if ($id_cmd == "lotti" || $id_cmd == "criteri" || $id_cmd == "buste") { if ($this->checkPartecipantiPresenti() && $_SESSION["utente"]->hasSuperPowers()) { include __DIR__ . "/misc/alertModifichePericolose.php"; } } } public function checkOpeningPermission($partecipante, $richiesta, $aggiuntive = false) { $return = false; if (!empty($this->lotto)) { if (!empty($partecipante) && !empty($richiesta)) { if ((!empty($this->getRisposteElaborazione()["inversioneProcedimentale"])) && $this->getRisposteElaborazione()["inversioneProcedimentale"] == "S") { $return = true; // Se non c'è l'apertura sequenziale permetto l'apertura } else { $busta = $this->getBusta($partecipante, $richiesta, $aggiuntive); // controllo che la busta esista if (!empty($busta)) { if ($busta["open"] == "S") { // se è già aperta posso procedere all'apertura $return = true; } else { if (!$this->activeRound || !$this->checkLock("open")) { // Blocco se è l'ultimo round di lavorazione o se il comando è locked $infoPartecipante = $this->getPartecipante($partecipante); if ($infoPartecipante["escluso"] == "N" || $infoPartecipante["escluso"] == "P") { $tipologie = array_keys(self::tipologieBusta()); $tipologia = $this->db->go("SELECT busta FROM b_gare_richieste WHERE codice = :codice", [":codice" => $richiesta])->fetch(PDO::FETCH_ASSOC); if (!empty($tipologia)) { $tipologia = $tipologia["busta"]; $checkSeduta = $this->db->go("SELECT data FROM b_gare_sedute WHERE codice_round = :round AND busta = :busta ORDER BY codice DESC LIMIT 0,1", [":round" => $this->round["codice"], ":busta" => $tipologia]); $continua = true; if ($checkSeduta->rowCount() === 1) { $dataSeduta = $checkSeduta->fetch(PDO::FETCH_ASSOC)["data"]; $continua = false; if (strtotime($dataSeduta) < time()) { $continua = true; } } if ($continua) { $block = false; // la variabile sarà utilizzata per determinare l'esito dopo il ciclo foreach $buste = []; foreach ($tipologie as $tipo) { $buste[] = $tipo; if ($tipo == $tipologia) { break; } } if (count($buste) > 1) { $inBuste = implode("','", $buste); } else { $inBuste = $buste[0]; } $check = $this->db->go( "SELECT MIN(r_partecipanti_gare.codice) AS firstPartecipante, b_gare_richieste.busta FROM r_partecipanti_gare JOIN b_gare_buste ON r_partecipanti_gare.codice = b_gare_buste.codice_partecipante JOIN b_gare_richieste ON b_gare_buste.codice_richiesta = b_gare_richieste.codice WHERE r_partecipanti_gare.codice_round = :codice_round AND r_partecipanti_gare.conferma =\"S\" AND (r_partecipanti_gare.escluso = \"N\" OR r_partecipanti_gare.escluso = \"P\") AND b_gare_buste.open = 'N' AND r_partecipanti_gare.codice_lotto = :codice_lotto AND b_gare_richieste.busta IN ('{$inBuste}') GROUP BY b_gare_richieste.busta ", [":codice_round" => $this->round["codice"],":codice_lotto"=>$this->lotto["codice"]] ); // si controlla che non ci siano buste chiuse di partecipanti ammessi precedenti a quella del concorrente attuale if ($check->rowCount() == 1) { $check = $check->fetch(PDO::FETCH_ASSOC); if ($check["firstPartecipante"] != $partecipante || $check["busta"] != $tipologia) { $block = true; } } else { $block = true; } if (!$block) { $return = true; } } } } } } } } } if ($return && $this->commissario) { $tipologia = $this->db->go("SELECT busta FROM b_gare_richieste WHERE codice = :codice", [":codice" => $richiesta])->fetch(PDO::FETCH_ASSOC); $return = false; if (!empty($tipologia)) { $tipologia = $tipologia["busta"]; if ($tipologia != "amministrativa") { $criteri = $this->getCriteri(); foreach ($criteri as $criterio) { if ($criterio["tipologia"] == "Q" && (($criterio["economico"] == "S" && $tipologia == "economica") || ($criterio["economico"] == "N" && $tipologia == "tecnica"))) { $return = true; break; } } } } } } return $return; } public function checkSoglie() { $partecipanti = $this->getPartecipanti("ALL"); if (!empty($partecipanti)) { $codici_partecipanti = []; foreach($partecipanti AS $partecipante) { $codici_partecipanti[] = (int) $partecipante["codice"]; } $codici_partecipanti = implode(",",$codici_partecipanti); $punteggio = $this->db->prepare("SELECT b_gare_punteggi_partecipanti.codice, b_gare_punteggi_partecipanti.codice_partecipante, b_gare_punteggi_partecipanti.valore FROM b_gare_punteggi_partecipanti WHERE codice_criterio = :criterio AND codice_partecipante IN (".$codici_partecipanti.")"); $macro = $this->getMacroCriteri(); $esclusi = []; $checkSoglia = $this->getRisposteElaborazione()["sogliaMinima"] ?? false; if (!empty($checkSoglia) && $checkSoglia != "N") { foreach ($macro as $padre) { $sub = $this->getSubCriteri($padre["codice"]); if (!empty($sub)) { $somma = []; foreach ($sub as $s) { $punteggio->bindValue(":criterio", $s["codice"]); $punteggio->execute(); if ($punteggio->rowCount() > 0) { while ($punt = $punteggio->fetch(PDO::FETCH_ASSOC)) { if (!isset($somma[$punt["codice_partecipante"]])) { $somma[$punt["codice_partecipante"]] = 0; } $somma[$punt["codice_partecipante"]] += $punt["valore"]; if ($s["soglia"] > 0 && $punt["valore"] < $s["soglia"]) { $esclusi[] = ["partecipante" => $punt["codice_partecipante"], "codice_relazione" => $s["codice"], "criterio" => $s["denominazione"], "soglia" => $s["soglia"], "valore" => $punt["valore"]]; } } } } } else { $somma = []; $punteggio->bindValue(":criterio", $padre["codice"]); $punteggio->execute(); if ($punteggio->rowCount() > 0) { while ($punt = $punteggio->fetch(PDO::FETCH_ASSOC)) { if (!isset($somma[$punt["codice_partecipante"]])) { $somma[$punt["codice_partecipante"]] = 0; } $somma[$punt["codice_partecipante"]] += $punt["valore"]; } } } if (!empty($somma)) { foreach ($somma as $codice_partecipante => $valore) { if ($padre["soglia"] > 0 && $valore < $padre["soglia"]) { $esclusi[] = ["partecipante" => $codice_partecipante, "codice_relazione" => $padre["codice"], "criterio" => $padre["denominazione"], "soglia" => $padre["soglia"], "valore" => $valore]; } } } } if (!empty($esclusi)) { if ($checkSoglia == "E") { $partecipanti = []; foreach ($esclusi as $info) { if (!isset($partecipanti[$info["partecipante"]])) { $partecipanti[$info["partecipante"]] = __("Soglia minima non superata"); } $partecipanti[$info["partecipante"]] .= "
" . $info["criterio"] . " - " . __("Soglia") . ": " . $info["soglia"] . " - Punteggio: " . $info["valore"]; } $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "r_partecipanti_gare"; foreach ($partecipanti as $codice => $motivazione) { $salva->operazione = "UPDATE"; $salva->oggetto = ["codice" => $codice, "escluso" => "S", "motivazione" => $motivazione]; $salva->save(); } } else if ($checkSoglia == "A") { $updatePunteggio = $this->db->prepare("UPDATE b_gare_punteggi_partecipanti SET valore = 0 WHERE codice = :codice"); foreach ($esclusi as $info) { $updatePunteggio->bindValue(":codice",$info["codice_relazione"]); $updatePunteggio->execute(); } } } } return $esclusi; } } public function updateTotalePunteggi() { $this->checkSoglie(); $return = false; $partecipanti = $this->getPartecipanti("ALL"); $totali = []; $tecnici = []; $economici = []; $sommaMacroTecnici = []; $sommaMacroEconomici = []; if (!empty($partecipanti)) { $sql_punteggi = "SELECT r_partecipanti_gare.codice, b_gare_punteggi_partecipanti.valore, b_gare_criteri_valutazione.economico, b_gare_criteri_valutazione.codice AS codice_criterio, b_gare_criteri_valutazione.codice_padre FROM b_gare_punteggi_partecipanti JOIN r_partecipanti_gare ON b_gare_punteggi_partecipanti.codice_partecipante = r_partecipanti_gare.codice JOIN b_gare_criteri_valutazione ON b_gare_punteggi_partecipanti.codice_criterio = b_gare_criteri_valutazione.codice WHERE r_partecipanti_gare.codice_round = :codice AND r_partecipanti_gare.codice_lotto = :lotto"; $ris_punteggi = $this->db->go($sql_punteggi, array(":codice" => $this->round["codice"],":lotto"=>$this->lotto["codice"])); if ($ris_punteggi->rowCount() > 0) { $riparametra = $this->getRisposteElaborazione()["riparametrazioneMacroCriteri"] ?? null; $riparametra = ($riparametra === "S"); while ($punteggio = $ris_punteggi->fetch(PDO::FETCH_ASSOC)) { if ($riparametra) { $riferimento = (!empty($punteggio["codice_padre"])) ? $punteggio["codice_padre"] : $punteggio["codice_criterio"]; if ($punteggio["economico"] == "S") { if (!isset($sommaMacroEconomici[$riferimento])) { $sommaMacroEconomici[$riferimento] = []; } if (!isset($sommaMacroEconomici[$riferimento][$punteggio["codice"]])) { $sommaMacroEconomici[$riferimento][$punteggio["codice"]] = 0; } $sommaMacroEconomici[$riferimento][$punteggio["codice"]] += $punteggio["valore"]; } else { if (!isset($sommaMacroTecnici[$riferimento])) { $sommaMacroTecnici[$riferimento] = []; } if (!isset($sommaMacroTecnici[$riferimento][$punteggio["codice"]])) { $sommaMacroTecnici[$riferimento][$punteggio["codice"]] = 0; } $sommaMacroTecnici[$riferimento][$punteggio["codice"]] += $punteggio["valore"]; } } else { if ($punteggio["economico"] == "S") { if (!isset($economici[$punteggio["codice"]])) { $economici[$punteggio["codice"]] = 0; } $economici[$punteggio["codice"]] += $punteggio["valore"]; } else { if (!isset($tecnici[$punteggio["codice"]])) { $tecnici[$punteggio["codice"]] = 0; } $tecnici[$punteggio["codice"]] += $punteggio["valore"]; } if (!isset($totali[$punteggio["codice"]])) { $totali[$punteggio["codice"]] = 0; } $totali[$punteggio["codice"]] += $punteggio["valore"]; } } if ($riparametra) { if (!empty($sommaMacroTecnici)) { foreach($sommaMacroTecnici AS $criterio => $punteggi) { $criterio = $this->getCriteri($criterio)[0]; $normalizzati = tuttogareMath::proporzionale($punteggi,$criterio["peso"],$criterio["decimali"]); foreach($normalizzati AS $partecipante => $punteggio) { if (!isset($tecnici[$partecipante])) { $tecnici[$partecipante] = 0; } $tecnici[$partecipante] += $punteggio; if (!isset($totali[$partecipante])) { $totali[$partecipante] = 0; } $totali[$partecipante] += $punteggio; } } } if (!empty($sommaMacroEconomici)) { foreach($sommaMacroEconomici AS $criterio => $punteggi) { $criterio = $this->getCriteri($criterio)[0]; $normalizzati = tuttogareMath::proporzionale($punteggi,$criterio["peso"],$criterio["decimali"]); foreach($normalizzati AS $partecipante => $punteggio) { if (!isset($economici[$partecipante])) { $economici[$partecipante] = 0; } $economici[$partecipante] += $punteggio; if (!isset($totali[$partecipante])) { $totali[$partecipante] = 0; } $totali[$partecipante] += $punteggio; } } } } } $return = true; $salva = new salva(); $salva->debug = false; foreach ($partecipanti as $partecipante) { $totale = $totali[$partecipante["codice"]] ?? null; $totaleTecnico = $tecnici[$partecipante["codice"]] ?? null; $totaleEconomico = $economici[$partecipante["codice"]] ?? null; $partecipante["totale"] = number_format($totale, 5); $partecipante["totaleTecnico"] = number_format($totaleTecnico, 5); $partecipante["totaleEconomico"] = number_format($totaleEconomico, 5); $salva->nome_tabella = "r_partecipanti_gare"; $salva->operazione = "UPDATE"; $salva->oggetto = $partecipante; $salva->save(); } } return $return; } public function importScore($economici, $ammessi = TRUE) { $return = false; $asta = ($economici === "asta"); if ($asta) { $criteri = $this->getCriteriValutabili(); } else { $criteri = ($economici) ? $this->getCriteriEconomiciValutabili() : $this->getCriteriTecniciValutabili(); } if (!empty($criteri)) { $partecipanti = $this->getPartecipanti($ammessi); if (!empty($partecipanti)) { $salva = new salva(); $salva->debug = false; $ris_check = $this->db->prepare("SELECT * FROM b_gare_punteggi_partecipanti WHERE codice_partecipante = :codice_partecipante AND codice_criterio = :codice_criterio "); $errori_importazione = []; foreach ($criteri as $criterio) { $punteggi = []; $auto = false; if (!empty($criterio["auto"])) { $auto = true; $offerte = $this->getOfferte($criterio["codice"], TRUE, $ammessi, $asta); if (!empty($offerte)) { $options = json_decode($criterio["options"], true); if ($economici && count($criteri) === 1 && $this->getInterpretazioneArt41() === "scorporato") { $offerte = $this->getRibassoComplessivoArt41($offerte); } if ($this->lotto["formato"] === "assoluto" && tuttogareMath::getFormule()[$criterio["auto"]]["diretta"]) { $offerte = tuttogareMath::convertInversaForScore($offerte,$this->lotto["importoRibassabile"]); } if ($criterio["peso"] == 100 && $criterio["auto"] == "P" && $criterio["economico"] == "S" && $this->lotto["formato"] !== "r-assoluto") { $punteggi = $offerte; } else { switch ($criterio["auto"]) { case "I": $punteggi = tuttogareMath::inversamenteProporzionale($offerte, $criterio["peso"], $criterio["decimali"]); break; case "L": $punteggi = tuttogareMath::lineareSemplice($offerte, $criterio["peso"], $criterio["decimali"], $options); break; case "H": $punteggi = tuttogareMath::incrementoLineare($offerte, $criterio["peso"], $criterio["decimali"]); break; case "P": $punteggi = tuttogareMath::proporzionale($offerte, $criterio["peso"], $criterio["decimali"]); break; case "O": $punteggi = tuttogareMath::onOff($offerte, $criterio["peso"]); break; case "S": $punteggi = tuttogareMath::tabellare($offerte, $options,$criterio["peso"], $criterio["decimali"]); break; case "B": $punteggi = tuttogareMath::bilineare($offerte, $criterio["peso"], $criterio["decimali"], $options); break; case "Q": $punteggi = tuttogareMath::quadratica($offerte, $criterio["peso"], $criterio["decimali"], $options); break; default: return false; } } } } else if ($criterio["tipologia"] == "Q") { $auto = true; $punteggi = $this->getSommaMediaPunteggiCoefficienti($criterio["codice"], NULL, "punteggi"); } if (!empty($punteggi)) { foreach ($punteggi as $partecipante => $valore) { if (is_numeric($valore)) { $punteggio = array(); $punteggio["codice_partecipante"] = $partecipante; $punteggio["codice_criterio"] = $criterio["codice"]; $punteggio["valore"] = number_format($valore, $criterio["decimali"]); $ris_check->bindValue(":codice_partecipante", $punteggio["codice_partecipante"], PDO::PARAM_INT); $ris_check->bindValue(":codice_criterio", $punteggio["codice_criterio"], PDO::PARAM_INT); $ris_check->execute(); $operazione = "INSERT"; $continua = true; if ($ris_check->rowCount() == 1) { $old = $ris_check->fetch(PDO::FETCH_ASSOC); $operazione = "UPDATE"; $punteggio["codice"] = $old["codice"]; if ($old["valore"] == $valore) { $continua = false; } } if ($continua) { $salva->nome_tabella = "b_gare_punteggi_partecipanti"; $salva->operazione = $operazione; $salva->oggetto = $punteggio; $salva->save(); } } } } else if ($auto) { $errori_importazione[] = $criterio["denominazione"]; } } $return = $this->updateTotalePunteggi(); if ($return && !empty($errori_importazione)) { $return = $errori_importazione; } } } return $return; } public static function algoritmiAnomalie() { global $config; return jsonToArray($config["jsonFolder"]."/gare-algoritimiAnomalia.json"); } public static function domandeStandardAnomalia() { $domande = []; $domande["decimali"] = ["label"=>"Decimali","options"=>[0,1,2,3,4,5,6,7,8,9]]; $domande["arrotondamento"] = ["label"=>"Arrotondamento","options"=>["S"=>"Si","N"=>"No"]]; $domande["soloSoglia"] = ["label"=>"Applicazione decimali e arrotondamenti","options"=>["S"=>"Solo soglia","N"=>"Tutti i passaggi"]]; return $domande; } public function getAnomaliaSorteggiata() { $extraInfo = $this->getExtraInfo(); if (isset($this->lotto) && !empty($extraInfo["lotto"]["anomaliaSorteggiata"])) { return $extraInfo["lotto"]["anomaliaSorteggiata"]; } } public function getRispostaElaborazioneAlgoritmoAnomalia() : ?String { $risposta = $this->getRisposteElaborazione()["esclusioneAutomaticaDlgs36"] ?? null; if (empty($risposta)) { $risposta = $this->getRisposteElaborazione()["anomaliaSoprasogliaDlgs36"] ?? null; } return $risposta; } public function getAlgoritmoAnomalia($excludeSorteggio = false) { $algoritmi = self::algoritmiAnomalie(); $return = []; if (!empty($this->lotto) && !empty($algoritmi) && !$this->privata) { $partecipanti = count($this->getPartecipantiForAnomalia()); $firstRound = $this->getRounds()[0] ?? false; if (!empty($partecipanti) && !empty($firstRound)) { $anomaliaSorteggiata = $this->getAnomaliaSorteggiata(); if (!empty($anomaliaSorteggiata)) { if (!empty($algoritmi[$anomaliaSorteggiata])) { $algoritmi = [$anomaliaSorteggiata => $algoritmi[$anomaliaSorteggiata]]; } else { $algoritmi = []; } } if (!empty($algoritmi)) { foreach($algoritmi AS $idAlgo => $algoritmo) { if ( (in_array($this->normaRiferimento,$algoritmo["idNormeApplicazione"]) !== false) && (in_array($this->lotto["criterio"],$algoritmo["criteri"]) !== false) && (in_array($this->info["procedura"],$algoritmo["procedureEscluse"]) === false) && (empty($algoritmo["inizio"]) || (strtotime($algoritmo["inizio"]) <= strtotime($firstRound["pubblicazione"]))) && (empty($algoritmo["fine"]) || (strtotime($algoritmo["fine"]) >= strtotime($firstRound["pubblicazione"]))) && (empty($algoritmo["partecipantiMinimi"]) || ($algoritmo["partecipantiMinimi"] <= $partecipanti)) && (empty($algoritmo["partecipantiMassimi"]) || ($algoritmo["partecipantiMassimi"] >= $partecipanti)) && (empty($algoritmo["tipologia"]) || in_array($this->info["tipologia"],$algoritmo["tipologia"]) !== false) && (!$excludeSorteggio || !$algoritmo["algoritmoSorteggio"]) ) { $include = true; $path = __DIR__."/provvisoria/calcoloAnomalie/{$idAlgo}/check.php"; if (file_exists($path)) { $include = false; include($path); } if($include) { $return[$idAlgo] = $algoritmo; } } } } } } return $return; } public function calcolaAnomalia($algo,$settings) { $errors = __("Errore generale nel calcolo"); foreach($this->getAlgoritmoAnomalia() AS $idAlgo => $algoritmo) { if ($idAlgo == $algo) { $path = __DIR__."/provvisoria/calcoloAnomalie/{$idAlgo}/calcolo.php"; if (file_exists($path)) { $soloSoglia = ($settings["soloSoglia"] == "S"); $arrotondamento = ($settings["arrotondamento"] == "S"); $decimali = (int) $settings["decimali"]; $this->db->go("UPDATE r_partecipanti_gare SET anomalia = 'N', motivazione_anomalia = '' WHERE codice_round = :round AND codice_lotto = :lotto AND a_verificata = 'N' AND a_facoltativa = 'N'",[":round"=>$this->round["codice"],":lotto"=>$this->lotto["codice"]]); $this->db->go("UPDATE r_partecipanti_gare SET escluso = 'N', motivazione = '', esclusione_automatica = 'N' WHERE codice_round = :round AND codice_lotto = :lotto AND esclusione_automatica = 'S'",[":round"=>$this->round["codice"],":lotto"=>$this->lotto["codice"]]); include($path); if (isset($extraInfo)) { foreach($extraInfo AS $key => $value) { $this->saveExtraInfo($key,$value,"lotto"); } } if (isset($soglia_anomalia)) { $this->db->go("UPDATE b_gare_lotti SET sogliaAnomalia = :soglia WHERE codice = :codice",[":soglia"=>$soglia_anomalia,":codice"=>$this->lotto["codice"]]); } } else { $errors = __("Impossibile eseguire calcolo dell'anomalia"); } break; } } return $errors; } public function aggiudica($aggiudicatari = 1) { if (!empty($this->lotto)) { $requestedAggiudicatari = $aggiudicatari; $salva = new salva(); $salva->debug = false; $sql = "UPDATE r_partecipanti_gare SET aggiudicatario = 'N', posizione = 0 WHERE codice_round = :codice AND codice_lotto = :lotto "; $this->db->go($sql,array(":codice"=>$this->round["codice"],":lotto"=>$this->lotto["codice"])); $sql = "SELECT * FROM r_partecipanti_gare WHERE codice_round = :codice AND codice_lotto = :lotto AND conferma = 'S' AND escluso = 'N' ORDER BY totale DESC"; $ris_partecipanti = $this->db->go($sql,array(":codice"=>$this->round["codice"],":lotto"=>$this->lotto["codice"])); $partecipanti = $ris_partecipanti->fetchAll(PDO::FETCH_ASSOC); $current = null; $riparametrazioneAssoluta = $this->getRisposteElaborazione()["riparametrazioneAssoluta"] ?? "N"; if ($riparametrazioneAssoluta === "S") { $criteriTecnici = $this->getMacroCriteri(); $punteggioMassimo = 0; $decimali = 3; foreach($criteriTecnici AS $criterio) { if ($criterio["economico"] == "N") { $punteggioMassimo += $criterio["peso"]; if ($decimali < $criterio["decimali"]) { $decimali = $criterio["decimali"]; } } } $punteggi = []; foreach($partecipanti AS $partecipante) { $punteggi[$partecipante["codice"]] = $partecipante["totaleTecnico"]; } $punteggi = tuttogareMath::proporzionale($punteggi,$punteggioMassimo,$decimali); reset($partecipanti); foreach($partecipanti AS $ind => $partecipante) { $partecipante["totaleTecnico"] = $punteggi[$partecipante["codice"]]; $partecipante["totale"] = $partecipante["totaleTecnico"] + $partecipante["totaleEconomico"]; $partecipanti[$ind] = $partecipante; } usort($partecipanti, function($a, $b) { return $b["totale"] > $a["totale"]; }); reset($partecipanti); } $count = 0; $posizione = 0; foreach($partecipanti AS $partecipante) { $count++; if ($current != $partecipante["totale"]) { $posizione = $count; } if ($aggiudicatari > 0 || $current == $partecipante["totale"]) { $partecipante["aggiudicatario"] = "S"; $partecipante["posizione"] = $posizione; if ($current != $partecipante["totale"]) { $aggiudicatari--; } $current = $partecipante["totale"]; } else { $partecipante["posizione"] = $posizione; $partecipante["aggiudicatario"] = "N"; } $salva->nome_tabella = "r_partecipanti_gare"; $salva->operazione = "UPDATE"; $salva->oggetto = $partecipante; $salva->save(); } $this->saveExtraInfo("aggiudicatari-{$this->round["codice"]}",$requestedAggiudicatari,"lotto"); } } public function getCostiManodoperaPartecipanti() : ?Array { $criteri = $this->getCriteriEconomiciValutabili(); $partecipanti = $this->getPartecipanti("ALL"); if (!empty($criteri) && !empty($partecipanti)) { $first = reset($criteri); $tmp = $this->getDettaglioOfferta("N",["{$first["codice"]}.02"],$partecipanti); if (!empty($tmp)) { $return = []; foreach ($tmp as $partecipante => $costo) { $return[$partecipante] = reset($costo); } return $return; } } return null; } public function getRibassoComplessivoArt41(Array $offerte, Bool $importoAssoluto = false) : ? Array { $costi = $this->getCostiManodoperaPartecipanti(); $formato = $this->lotto["formato"]; if (!empty($costi)) { $tmp = []; foreach($offerte AS $partecipante => $offerta) { if ($formato == "assoluto" || $formato == "r-assoluto") { $offerta = $offerta + ($costi[$partecipante] ?? 0); } else { if ($formato == "ribasso" || $formato == "nulla") { $offerta = $this->lotto["importoBase"] * $offerta / 100; $offerta = $this->lotto["importoBase"] - $offerta; $offerta += $costi[$partecipante] ?? 0; } else if ($formato == "rialzo") { $offerta = $this->lotto["importoBase"] * $offerta / 100; $offerta = $this->lotto["importoBase"] + $offerta; $offerta += $costi[$partecipante] ?? 0; } if (!$importoAssoluto) { $offerta = 100 - ($offerta * 100 / $this->lotto["importoRibassabile"]); } } $tmp[$partecipante] = $offerta; } $offerte = $tmp; } return (empty($offerte)) ? null : $offerte; } private function getDettaglioOfferta(String $tipologia, Array $codici_dettaglio, Array $partecipanti, ?String $busta = null) : ?Array { $return = []; $filtroTipologia = ""; if (!empty($busta)) { $filtroTipologia = " AND tipo = :tipoOfferta AND verificata = 'S'"; } else { $asta = $this->getAsta(true); $filtroTipologia = " AND verificata <> 'P'"; if (!empty($asta->info) && $asta->getScadenza(true)) { $filtroTipologia = " AND verificata = 'S'"; } } $sql = "SELECT offerta FROM b_dettaglio_offerte_gare WHERE codice_dettaglio = :dettaglio AND codice_partecipante = :partecipante AND offerta IS NOT NULL AND tipo = :tipologia AND codice_offerta IN (SELECT MAX(codice) AS last_offer FROM b_offerte_gare WHERE codice_partecipante = :partecipante {$filtroTipologia})"; $getOffer = $this->db->prepare($sql); $getOffer->bindValue(":tipologia", $tipologia); if (!empty($busta)) { $getOffer->bindValue(":tipoOfferta", $busta); } foreach ($partecipanti as $partecipante) { if (!empty($codici_dettaglio)) { $found = false; foreach ($codici_dettaglio as $dettaglio) { $quantita = 1; if (is_array($dettaglio)) { $quantita = $dettaglio["quantita"]; $dettaglio = $dettaglio["codice"]; } $getOffer->bindValue(":dettaglio", $dettaglio); $getOffer->bindValue(":partecipante", $partecipante["codice"]); $getOffer->execute(); if ($getOffer->rowCount() == 1) { $found = true; $tmpOfferta = $getOffer->fetch(PDO::FETCH_COLUMN); if ($tmpOfferta !== false) { $dettagli[$dettaglio] = ($tmpOfferta * $quantita); } } } if ($found) { $return[$partecipante["codice"]] = $dettagli; } } } return (empty($return)) ? null : $return; } public function getOfferte($codice_criterio, $totale = true, $ammessi = TRUE, $asta = false) { $criterio = $this->getCriteri($codice_criterio); if (!empty($criterio)) { $criterio = $criterio[0]; $partecipanti = $this->getPartecipanti($ammessi); $offerte = []; $codici_dettaglio = [$codice_criterio]; if ($criterio["tipologia"] == "E") { $codici_dettaglio = []; $voci = $this->getElencoPrezzi($criterio["codice"]); if (!empty($voci)) { foreach($voci AS $voce) { $codice_d = $criterio["codice"] . "." . $voce["codice"]; $codici_dettaglio[] = ["codice"=>$codice_d,"quantita"=>$voce["quantita"]]; } } } $dettagli = $this->getDettaglioOfferta($criterio["tipologia"],$codici_dettaglio,$partecipanti, (empty($asta)) ? $criterio["busta"] : null); if (!empty($dettagli)) { if (!$totale) { $offerte = $dettagli; } else { foreach($dettagli AS $partecipante => $ds) { foreach($ds AS $d) { if (!isset($offerte[$partecipante])) $offerte[$partecipante] = 0; $offerte[$partecipante] += $d; } } } } return $offerte; } return false; } public function getCoefficientiValutazione($codice_criterio = NULL, $codice_utente = NULL) { $tmp = $this->getManagerCommissione("commissione")->getCoefficientiValutazione($codice_criterio, $codice_utente); $coefficienti = []; $partecipanti = $this->getPartecipanti(); if (!empty($partecipanti)) { $codiciPartecipanti = []; foreach($partecipanti AS $par) { $codiciPartecipanti[] = $par["codice"]; } if (!empty($tmp) && !empty($partecipanti)) { if ((!empty($codice_criterio)) && (!empty($codice_utente))) { foreach($tmp AS $codicePart => $coef) { if (in_array($codicePart,$codiciPartecipanti) !== false) { $coefficienti[$codicePart] = $coef; } } } else if (!empty($codice_utente)) { foreach($tmp AS $codiceCriterio => $coefP) { foreach($coefP AS $codicePart => $coef) { if (in_array($codicePart,$codiciPartecipanti) !== false) { $coefficienti[$codiceCriterio][$codicePart] = $coef; } } } } else if (!empty($codice_criterio)) { foreach($tmp AS $codiceUtente => $coefP) { foreach($coefP AS $codicePart => $coef) { if (in_array($codicePart,$codiciPartecipanti) !== false) { $coefficienti[$codiceUtente][$codicePart] = $coef; } } } } else { foreach($tmp AS $codiceCriterio => $coefU) { foreach($coefU AS $codiceUtente => $coefP) { foreach($coefP AS $codicePart => $coef) { if (in_array($codicePart,$codiciPartecipanti) !== false) { $coefficienti[$codiceCriterio][$codiceUtente][$codicePart] = $coef; } } } } } } } return $coefficienti; } public function getSommaMediaPunteggiCoefficienti($codice_criterio, $codice_utente = NULL, $output = NULL) { $valutazioni = $this->getCoefficientiValutazione($codice_criterio); $criterio = $this->getCriteri($codice_criterio)[0]; $commissari = $this->getCommissari("commissione", $codice_utente); $settings = $this->getManagerCommissione("commissione")->getInfo(); $partecipanti = $this->getPartecipanti(TRUE); $somme = []; $medie = []; $normalizzazione = []; $count = 0; if (!empty($commissari)) { foreach ($commissari as $commissario) { foreach ($partecipanti as $partecipante) { if (isset($valutazioni[$commissario["codice_utente"]][$partecipante["codice"]])) { $count++; if (!isset($somme[$partecipante["codice"]])) { $somme[$partecipante["codice"]] = 0; } $somme[$partecipante["codice"]] += $valutazioni[$commissario["codice_utente"]][$partecipante["codice"]]; } } } if ($count == count($commissari) * count($partecipanti)) { foreach ($partecipanti as $partecipante) { $medie[$partecipante["codice"]] = $somme[$partecipante["codice"]] / count($commissari); if ($settings["riparametra"] == "S") { $normalizzazione = tuttogareMath::proporzionale($medie, 1, null); } else { $normalizzazione = $medie; } } if (!empty($normalizzazione)) { foreach ($normalizzazione as $partecipante => $coef) { if ($settings["arrotonda"] == "S") { $punteggi[$partecipante] = number_format($coef * $criterio["peso"], $criterio["decimali"]); } else { $punteggi[$partecipante] = truncate($coef * $criterio["peso"], $criterio["decimali"]); } } switch ($output) { case "somme": $return = $somme; break; case "medie": $return = $medie; break; case "normalizzazione": $return = $normalizzazione; break; case "punteggi": $return = $punteggi; break; default: $return = ["somme" => $somme, "medie" => $medie, "normalizzazione" => $normalizzazione, "punteggi" => $punteggi]; } } } } return $return ?? false; } public function getManagerAvvisi() { if (empty($this->managerAvvisi)) { $avvisiProcedura = new avvisiProcedura($_SESSION["ente"]->codice, "gare", $this->info["codice"], $this->round["codice"]); if (!empty($avvisiProcedura)) { $this->managerAvvisi = $avvisiProcedura; } } return $this->managerAvvisi; } public function getManagerCommissione($tipologia) { $manager = new Commissione("gare", $this->round["codice"], $tipologia); if (!empty($manager)) { $this->managerCommissione = $manager; } return $this->managerCommissione; } public function getManagerIncarichi() { $manager = new Incarichi("gare", $this->info["codice"]); if (!empty($manager)) { $this->managerIncarichi = $manager; } return $this->managerIncarichi; } public function getManagerDGUE() { $manager = new DGUE("gare", $this->round["codice"]); if (!empty($manager)) { $this->managerDGUE = $manager; } return $this->managerDGUE; } public function getDestinatari($ignoreStato = false) { $return = []; if (!empty($this->lotto)) { $lotti = [$this->lotto]; } else { $lotti = $this->getLotti(); } foreach($lotti AS $lotto) { if ($this->setLotto($lotto["codice"])) { $destinatari = $this->getPartecipanti() ?? []; if ($this->info["stato"] < 21 || $ignoreStato) { $destinatari = array_merge($destinatari, ($this->getInvitati() ?? [])); } $tmp = array_column($destinatari,"codice_operatore"); if (!empty($tmp)) { $return = array_merge($return,$tmp); } if ($this->info["stato"] < 21 || $ignoreStato) { $manuali = $this->getInvitatiManuali(); if (!empty($manuali)) { $return = array_merge($return,array_column($manuali,"pec")); } } } } if (count($lotti) > 1) { $this->lotto = null; } $return = array_unique($return); return $return; } public function addDGUERequest() { if (!$this->checkLock("buste") && $this->db->go("SELECT codice FROM b_gare_richieste WHERE titolo = 'DGUE' AND codice_round = :codice_round AND busta = 'amministrativa'", [":codice_round" => $this->round["codice"]]) ->rowCount() == 0 ) { $richiesta = []; $richiesta["codice_round"] = $this->round["codice"]; $richiesta["ordinamento"] = 0; $richiesta["titolo"] = "DGUE"; $richiesta["descrizione"] = __("Documento di Gara Unico Europeo"); $richiesta["controllo"] = "F"; $richiesta["busta"] = "amministrativa"; $this->saveRichiesta($richiesta); } } public function deleteDGUERequest() { if (!$this->checkLock("buste")) { $this->db->go("DELETE FROM b_gare_richieste WHERE titolo = 'DGUE' AND codice_round = :codice_round AND busta = 'amministrativa'", [":codice_round" => $this->round["codice"]]); } } public function lottiMisti() { return (!empty($this->getLottiMP()) && !empty($this->getLottiOEPV())); } public function getDomandeElaborazione() { global $config; $tmp = jsonToArray($config["jsonFolder"]."/gare-elaborazione.json"); $return = []; $economici = (!empty($this->getLottiMP())); $tecnici = (!empty($this->getLottiOEPV())); $multiLotto = (count($this->getLotti()) > 1); $soglia = $this->getSogliaGara(); if (!empty($tmp)) { foreach($tmp AS $key => $domanda) { if ((empty($domanda["inizio"]) || strtotime($domanda["inizio"]) <= strtotime($this->info["timestamp_creazione"])) && (empty($domanda["fine"]) || strtotime($domanda["fine"]) >= strtotime($this->info["timestamp_creazione"]))) { $insert = true; if (!empty($domanda["procedureEscluse"]) && in_array($this->info["procedura"],$domanda["procedureEscluse"]) !== false) { $insert = false; } if (!empty($domanda["idNormeApplicazione"]) && in_array($this->normaRiferimento,$domanda["idNormeApplicazione"]) === false) { $insert = false; } if ($soglia == "sottosoglia" && !$domanda["sottosoglia"]) { $insert = false; } if ($soglia == "soprasoglia" && !$domanda["soprasoglia"]) { $insert = false; } if (($this->getModalita()["online"] && !$domanda["online"]) || (!$this->getModalita()["online"] && !$domanda["offline"])) { $insert = false; } if (($multiLotto && !$domanda["multi_lotto"]) || (!$multiLotto && !$domanda["mono_lotto"])) { $insert = false; } if (!empty($this->round["infoFase"]) && (($this->round["infoFase"]["graduatoria"] && !$domanda["graduatoria"]) || (!$this->round["infoFase"]["graduatoria"] && !$domanda["istanza_semplice"]))) { $insert = false; } if (!empty($domanda["tipologieEscluse"]) && in_array($this->info["tipologia"],$domanda["tipologieEscluse"]) !== false) { $insert = false; } if (!empty($domanda["criteri"]) && $insert) { $insert = false; if ($economici && in_array("prezzo",$domanda["criteri"]) !== false) { $insert = true; } if ($tecnici && in_array("vantaggiosa",$domanda["criteri"]) !== false) { $insert = true; } } if ($this->privata && !$domanda["privata"]) { $insert = false; } if($this->quickPanel && ! $domanda["quickPanel"]) { $insert = false; } if (!empty($domanda["impostazioneModuloNecessaria"])) { foreach($domanda["impostazioneModuloNecessaria"] AS $set => $value) { $v = settingsManager::getValue($set) ?? null; if (empty($v) || $v !== $value) { $insert = false; break; } } } if ($insert) { $return[$key] = $domanda; } } } } return $return; } public function getDatiMinimi() { $datiMinimi = $this->db->go("SELECT * FROM b_impostazioni_dati_minimi WHERE attivo = 'S' AND soft_delete = 'N'")->fetchAll(PDO::FETCH_ASSOC); $return = []; if (!empty($datiMinimi)) { foreach($datiMinimi AS $domanda) { $tipologie = json_decode($domanda["tipologie"],true); if (in_array($this->info["tipologia"],$tipologie) !== false) { $return[$domanda["codice"]] = $domanda; } } } return $return; } public function getRisposteElaborazione() { return json_decode($this->getExtraInfo()["round"]["elaborazione"] ?? "",true); } public function modalitaLotti() { return $this->getRisposteElaborazione()["modalita_lotti"] ?? "libera"; } public function getRisposteDatiMinimi() { return json_decode($this->getExtraInfo()["round"]["datiMinimi"] ?? "",true); } public function accessoAttiAutomatico() { $risposta = $this->getRisposteElaborazione()["accessoArt36"] ?? "N"; return ($risposta == "S"); } public function abilitaBusteSecretate() { return $this->accessoAttiAutomatico(); } public function usaGraduatoria() { $return = true; $risposte = $this->getRisposteElaborazione(); if (!empty($risposte["usaGraduatoria"]) && $risposte["usaGraduatoria"] == "N") { $return = false; } return $return; } public function validaElaborazione() { $domandeElaborazione = $this->getDomandeElaborazione(); $return = []; if (!empty($domandeElaborazione)) { $risposteElaborazione = $this->getRisposteElaborazione(); foreach($domandeElaborazione AS $idDomanda => $infoDomanda) { if ($infoDomanda["obbligatorio"] && (!isset($risposteElaborazione[$idDomanda]) || $risposteElaborazione[$idDomanda] === "")) { $return[$idDomanda] = $infoDomanda["quesito"]; } else { if (!empty($infoDomanda["incompatibilita"])) { foreach($infoDomanda["incompatibilita"] AS $idIncompatibile => $valoriIncompatibili) { if (isset($risposteElaborazione[$idIncompatibile])) { if (!is_array($valoriIncompatibili)) { $valoriIncompatibili = [$valoriIncompatibili]; } if (in_array($risposteElaborazione[$idIncompatibile],$valoriIncompatibili)) { $return[$idDomanda] = $domandeElaborazione[$idIncompatibile]["quesito"] . ":" . __("Risposta incompatibile"); } } } } } } } if (!$_SESSION["utente"]->fromHere() && $_SESSION["ente"]->getInfo()["permit_cross"] == "N") { $domandeMinimi = $this->getDatiMinimi(); if (!empty($domandeMinimi)) { $risposteElaborazione = $this->getRisposteDatiMinimi(); foreach($domandeMinimi AS $idDomanda => $infoDomanda) { if ($infoDomanda["obbligatorio"] == "S" && (!isset($risposteElaborazione[$idDomanda]) || $risposteElaborazione[$idDomanda] === "" || (is_array($risposteElaborazione[$idDomanda]) && empty($risposteElaborazione[$idDomanda])))) { $return[$idDomanda] = $infoDomanda["titolo"]; } } } } if (empty($return)) { $return = true; } return $return; } public function inizializzaFase($key,$fase) { $continua = true; $infoRda = $this->getExtraInfo()["gara"]["rda"] ?? null; $rounds = $this->getRounds(); if (!$fase["ripetibile"] && !empty($rounds)) { foreach($rounds AS $round) { if ($round["id"] == $key) { $continua = false; } } } if ($continua) { $lotti = $this->getLotti(); if (!empty($lotti) || $this->quickAvailable) { $numero = 1; if (!empty($rounds)) { foreach($rounds AS $round) { $numero = $round["numero"] + 1; } } $newRound = []; $newRound["id"] = $key; $newRound["codice_gara"] = $this->info["codice"]; $newRound["numero"] = $numero; $newRound["pubblica"] = 0; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "b_gare_round"; $salva->operazione = "INSERT"; $salva->oggetto = $newRound; $codice_round = $salva->save(); if ($codice_round) { if ($numero > 1) { $this->db->go("UPDATE b_gare SET stato = 10 WHERE codice = :codice",[":codice"=>$this->info["codice"]]); $statiConclusivi = implode(",",self::statiTermineProcedura()); $this->db->go("UPDATE b_gare_lotti SET stato = 0 WHERE codice_gara = :codice AND stato NOT IN ({$statiConclusivi})",[":codice"=>$this->info["codice"]]); if (!isset($lotti)) { $lotti = $this->getLotti(); } $invitati = []; foreach($lotti AS $lotto) { if (!in_array($lotto["stato"],gara::statiTermineProcedura())) { $this->setLotto($lotto["codice"]); $partecipanti = $this->getPartecipanti(TRUE); if (!empty($partecipanti)) { $invitati[$lotto["codice"]] = array_column($partecipanti,"codice_operatore"); $invitati[$lotto["codice"]] = array_filter($invitati[$lotto["codice"]]); } } } $this->lotto = null; } $this->round = $this->getRounds($codice_round)[0] ?? null; $this->db->go("UPDATE b_gare SET fase_attiva = :numero WHERE codice = :codice",[":numero"=>$numero,":codice"=>$this->info["codice"]]); if (!empty($invitati)) { foreach($invitati AS $codice_lotto => $operatori) { foreach($operatori AS $oe) { $this->saveInvito($codice_lotto,$oe,"N",false); } } } if ($fase["graduatoria"]) { $formati = []; $soloPrezzo = true; if (!isset($lotti)) { $lotti = $this->getLotti(); } if (!empty($lotti)) { foreach($lotti AS $lotto) { $formati[] = $lotto["formato"]; if ($lotto["criterio"] != "prezzo") { $soloPrezzo = false; } } $formati = array_unique($formati); if (count($formati) === 1 && $soloPrezzo) { $formato = reset($formati); if (!empty($formato) && $formato != "nulla") { $criterio = []; $criterio["codice"] = ""; $criterio["denominazione"] = __(self::formatiOffertaDisponibili()[$formato] ?? "Ribasso"); $criterio["descrizione"] = __("{$criterio["denominazione"]} sull'importo a base di gara"); $criterio["economico"] = "S"; $criterio["auto"] = (in_array($formato,["ribasso","rialzo"])) ? "P" : "I"; $criterio["peso"] = "100"; $criterio["decimali"] = "3"; $criterio["tipologia"] = "N"; $this->saveCriterio($criterio); } } } } if (!empty($infoRda) && $infoRda["remote"]) { if (isset($_SESSION["ente"]->erpConnector) && method_exists($_SESSION["ente"]->erpConnector,"aggiungiInfoRDAaGara")) { $_SESSION["ente"]->erpConnector->aggiungiInfoRDAaGara($this); } }elseif($codici_rda = $this->getRda()){ $this->aggiungiInfoRDAaGara($codici_rda); } $this->addToLog("INSERT","Creata fase: " . $key); return $codice_round; } } } return false; } public function aggiungiInfoRDAaGara(Array $codici_rda = []) { if(!empty($codici_rda)){ $tmpCriteri = $tmpArticoli = []; $count = 0; $criteriDisponibili = $this->getCriteriEconomici(); foreach ($codici_rda as $codice_rda) { $rda = rda::init($codice_rda, ['articoli', 'criteri']); if($rda->info['codice']){ if($rda->relazioni['articoli']){ foreach ($rda->relazioni['articoli'] as $articolo) { $count++; $tmpArticoli["i_{$count}"] = [ "titolo" => $articolo["denominazione"], "descrizione" => $articolo["denominazione"], "unita" => "UdM", "tipo" => "misura", "quantita" => $articolo["quantita"] ]; } } if($rda->relazioni['criteri']){ foreach ($rda->relazioni['criteri'] as $criterio) { if ($criterio["economico"] == "N") { $tmpCriteri[] = [ 'codice' => '', 'denominazione' => $criterio['denominazione'], 'descrizione' => '', 'economico' => $criterio['economico'], 'auto' => '', 'peso' => $criterio['peso'], 'decimali' => '3', 'tipologia' => $criterio["economico"] == 'S' ? 'N' : 'Q' ]; } } } $rda->relazioni['allegato'] = filesManager::listFiles($rda->info["codice"],"rda","A",0,false); if (!empty($rda->relazioni["allegato"])) { foreach($rda->relazioni["allegato"] as $allegato) { $allegato = filesManager::fileInfo($allegato['codice'], $allegato['name'], $allegato['sourceID'], $allegato['sourceType']); filesManager::saveFileFromBuffer(NULL, base64_decode($allegato["content"]),$this->round["codice"],"gare-reserved",$allegato["titolo"]); } } } } if(!empty($tmpArticoli)){ foreach ($criteriDisponibili as $criterio) { if (!empty($criterio["auto"])) { $criterio["tipologia"] = "E"; $this->saveCriterio($criterio); $this->saveVociEP($criterio["codice"],$tmpArticoli); break; } } } if(!empty($tmpCriteri)){ foreach ($tmpCriteri as $tmpCriterio) { $this->saveCriterio($tmpCriterio); } } } } public function selfFill() { if ($this->info["stato"] >= 10 && $this->activeRound) { if (!$this->usaGraduatoria()) { $criteri = $this->getCriteri(); if (!empty($criteri)) { foreach($criteri AS $criterio) { $this->deleteCriterio($criterio["codice"]); } } } $risposte = $this->getRisposteElaborazione(); if (!empty($risposte["slotGiustificativi"])) { $titolo =__("Giustificativi manodopera"); $richieste = $this->getRichieste(); $element = null; if (!empty($richieste)) { foreach($richieste AS $tmp) { if ($tmp["titolo"] == $titolo) { $element = $tmp["codice"]; break; } } } if ($risposte["slotGiustificativi"] === "S" && empty($element)) { $richiesta = []; $richiesta["codice_round"] = $this->round["codice"]; $richiesta["busta"] = "economica"; $richiesta["titolo"] = $titolo; $richiesta["descrizione"] = __("Se applicabile, utilizza questo spazio per caricare i tuoi giustificativi per il ribasso della manodopera"); $richiesta["controllo"] = "N"; $richiesta["ordinamento"] = 90; $richiesta["locked"] = "N"; $this->saveRichiesta($richiesta); } else if ($risposte["slotGiustificativi"] === "N" && !empty($element)) { $this->deleteRichiesta($element); } } } } public function getManagerRichieste() { $manager = new richiesteOE("gare", $this->info["codice"], $this->lotto["codice"]); if (!empty($manager)) { $this->managerRichieste = $manager; } return $this->managerRichieste; } public function getManagerPubblicita() { $manager = new pubblicitaLegale("gare", $this->info["codice"], $this->round["codice"]); if (!empty($manager)) { $this->managerPubblicita = $manager; } return $this->managerPubblicita; } public function getChiarimenti(int $codice = NULL) { $bind = [":codice_round" => $this->round["codice"]]; $sql_chiarimenti = "SELECT b_gare_chiarimenti.* FROM b_gare_chiarimenti WHERE b_gare_chiarimenti.codice_round = :codice_round "; if (!empty($codice)) { $sql_chiarimenti .= " AND b_gare_chiarimenti.codice = :codice "; $bind[":codice"] = $codice; } $sql_chiarimenti .= " ORDER BY b_gare_chiarimenti.timestamp "; $tmp = $this->db->go($sql_chiarimenti, $bind)->fetchAll(PDO::FETCH_ASSOC); $return = []; if (!empty($tmp)) { $i = 0; foreach ($tmp as $t) { $i++; $t["count"] = $i; $oeInfo = oeManager::getOE($t["codice_richiedente"]); if(! empty($oeInfo["ragione_sociale"])) { $t["ragione_sociale"] = $oeInfo["ragione_sociale"]; } $return[] = $t; } } if (!empty($codice) && !empty($return)) { $return = $return[0]; } return $return; } public function getSopralluoghi(int $codice = NULL) { $bind = [":codice_round" => $this->round["codice"]]; $sql_sopralluoghi = "SELECT b_gare_sopralluogo.* FROM b_gare_sopralluogo WHERE b_gare_sopralluogo.codice_round = :codice_round "; if (!empty($codice)) { $sql_sopralluoghi .= " AND b_gare_sopralluogo.codice = :codice "; $bind[":codice"] = $codice; } $sql_sopralluoghi .= " ORDER BY b_gare_sopralluogo.timestamp "; $tmp = $this->db->go($sql_sopralluoghi, $bind)->fetchAll(PDO::FETCH_ASSOC); $return = []; if (!empty($tmp)) { foreach ($tmp as $t) { $oeInfo = oeManager::getOE($t["codice_richiedente"]); $t["ragione_sociale"] = $oeInfo["ragione_sociale"] ?? "Ragione sociale non presente"; $return[] = $t; } } if (!empty($codice) && !empty($return)) { $return = $return[0]; } return $return; } public function getAvvalimento($partecipante) { if (!empty($this->lotto)) { $bind = [":codice_round" => $this->round["codice"], ":codice_partecipante" => $partecipante,":codice_lotto" => $this->lotto["codice"]]; $sql = "SELECT r_avvalimenti_gare.*, r_raggruppamenti_gare.ragione_sociale AS nome_padre FROM r_avvalimenti_gare JOIN r_partecipanti_gare ON r_avvalimenti_gare.codice_padre = r_partecipanti_gare.codice LEFT JOIN r_raggruppamenti_gare ON r_avvalimenti_gare.identifier_raggruppamento = r_raggruppamenti_gare.identifier WHERE r_partecipanti_gare.codice_round = :codice_round AND r_partecipanti_gare.codice = :codice_partecipante AND codice_lotto = :codice_lotto"; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getRaggruppamento($partecipante) { if (!empty($this->lotto)) { $bind = [":codice_round" => $this->round["codice"], ":codice_partecipante" => $partecipante,":codice_lotto" => $this->lotto["codice"]]; $sql = "SELECT r_raggruppamenti_gare.* FROM r_raggruppamenti_gare JOIN r_partecipanti_gare ON r_raggruppamenti_gare.codice_padre = r_partecipanti_gare.codice WHERE r_partecipanti_gare.codice_round = :codice_round AND r_partecipanti_gare.codice = :codice_partecipante AND codice_lotto = :codice_lotto"; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getSorgenteInvitati() : String { $return = __DIR__ . "/inviti/sorgenti/"; $source = "default.php"; $derivazione = $this->getProcedura()["derivazione"] ?? null; if (!empty($derivazione)) { switch($derivazione) { case "accordo": $source = "accordo.php"; break; default: throw new Exception("Derivazione sconosciuta", 404); break; } } else { if (($this->round["infoFase"]["graduatoria"] ?? false) && $this->round["numero"] > 1) { $source = "indagine.php"; } } $return .= $source; return $return; } public function sorteggiaInvitati(String $tokenOE, String $lotto, Int $partecipanti, String $descrizione = "", Array $esclusioni = []) : Bool { $estrazione = oeManager::getEstrazione("gare", $this->info["codice"], $lotto); if (empty($estrazione)) { if (!empty($lotto)) { $lotti = [$lotto]; } else { $lotti = array_column($this->getLotti(), "codice"); } $continua = true; foreach ($lotti as $checkLotto) { if ($this->setLotto($checkLotto)) { if (!empty($this->countInvitati()) && $tokenOE != "indagine") { $continua = false; break; } } else { $continua = false; break; } } if ($continua) { unset($this->lotto); $continua = false; $oeManager = new oeManager; if ($tokenOE == "accordo") { $accordo = accordiQuadro::init($this->info["derivazione"]); if (!empty($accordo)) { $aggiudicatari = $accordo->getAggiudicatari(); if (!empty($aggiudicatari)) { $ooee = array_column($aggiudicatari, "codice_operatore"); $ooee = array_filter($ooee); if (!empty($ooee)) { $continua = true; $oeManager->operatoriSorteggio = $ooee; } } } } else if ($tokenOE == "indagine") { $invitati = $this->getInvitati($lotto); if (!empty($invitati)) { $ooee = array_column($invitati, "codice_operatore"); $ooee = array_filter($ooee); if (!empty($ooee)) { $continua = true; $deleteInvitati = true; $oeManager->operatoriSorteggio = $ooee; } } } else { $continua = true; $oeManager->setFilters($_SESSION["exportoperatoriSettings"][$tokenOE]); } if ($continua) { $esito = $oeManager->eseguiEstrazione($_SESSION["ente"]->codice, $partecipanti, $esclusioni, $descrizione, "gare", true, $this->info["codice"], $lotto); if (is_numeric($esito)) { if (!empty($_SESSION["exportoperatoriSettings"][$tokenOE]["elenco"])) { $filtroElenco = explode("|", $_SESSION["exportoperatoriSettings"][$tokenOE]["elenco"]); if (count($filtroElenco) == 2) { $sources = oeManager::tipiElenco(); $tabellePartecipanti = oeManager::tabelleElenco(); if (in_array($filtroElenco[0], array_keys($sources)) !== false && !empty($tabellePartecipanti[$filtroElenco[0]])) { $tipo_elenco = $filtroElenco[0]; $codice_elenco = $filtroElenco[1]; $this->saveExtraInfo("tipo_elenco_invito", $tipo_elenco, "round"); $this->saveExtraInfo("codice_elenco_invito", $codice_elenco, "round"); } } } $estrazione = oeManager::getEstrazione("gare", $this->info["codice"], $lotto); $relazioni = $oeManager->getRelazioniEstrazione($estrazione["codice"]); if (!empty($deleteInvitati)) { $this->db->go("DELETE FROM r_inviti_gare WHERE codice_round = :codice_round AND codice_lotto = :lotto ",[":codice_round"=>$this->round["codice"],":lotto"=>$lotto]); } foreach ($relazioni as $relazione) { if ($relazione["selezionato"] == "S" || $relazione["selezionato"] == "A") { $this->saveInvito($lotto, $relazione["codice_operatore"], true, true); } } ob_start(); oeManager::printReportEstrazione($estrazione, $relazioni, true); $report = ob_get_clean(); $report = "{$report}"; $pdf = documentConverter::getPDFWithWKHTML($report,"A4","landscape"); $sezione = ($this->accessoAttiAutomatico()) ? "gare-accessoatti" : "gare-reserved"; filesManager::saveFileFromBuffer(null,$pdf,$this->round["codice"],$sezione,__("Verbale estrazione") . " - " . date("Y-m-d H:i:s")); return true; } else { throw new Exception("Errore nel sorteggio"); } } else { throw new Exception("Errore identificazione Operatori"); } } else { throw new Exception("Invitati già selezionati"); } } else { throw new Exception("Estrazione già presente"); } return false; } public function saveInvito($lotto,$operatore,$sorteggio,$updateContatori = true) { $insert = $this->db->prepare("INSERT INTO r_inviti_gare (codice_operatore,codice_round,codice_lotto,sorteggio,utente_modifica) VALUES (:oe,:fase,:lotto,:sorteggio,:utente) "); $oe = oeManager::getOE($operatore); $insert->bindValue(":fase",$this->round["codice"]); $insert->bindValue(":lotto",$lotto); $insert->bindValue(":sorteggio",($sorteggio ? "S" : "N")); $insert->bindValue(":utente",$_SESSION["utente"]->codice ?? -1); if (!empty($oe)) { $insert->bindValue(":oe",$oe["codice"]); $insert->execute(); $this->addToLog("INSERT",__("Invito operatore") . ":" . $oe["ragione_sociale"]); if ($updateContatori) { $invito = []; $invito["codice_ente"] = $_SESSION["ente"]->codice; $invito["contesto"] = "gare"; $invito["codice_elemento"] = $this->round["codice"]; $invito["data_invito"] = date("d-m-Y"); $invito["sub_elemento"] = $lotto; $extraInfo = $this->getExtraInfo(); if (!empty($extraInfo["round"]["tipo_elenco_invito"])) { $invito["tipo_elenco"] = $extraInfo["round"]["tipo_elenco_invito"]; $invito["codice_elenco"] = $extraInfo["round"]["codice_elenco_invito"]; } $invito["codice_fiscale_operatore"] = $oe["codice_fiscale_impresa"]; $soa = []; $tmpSoa = $this->getSOA(); if (!empty($tmpSoa)) { foreach($tmpSoa AS $categoria) { $classifica = getClassificaSOAFromImporto($categoria["importo"]); $soa[] = ["categoria"=>$categoria["codice_categoria"],"classifica"=>$classifica]; } } $progettazione = []; $tmpProg = $this->getProgettazione(); if (!empty($tmpProg)) { $progettazione = array_column($tmpProg,"codice_categoria"); } oeManager::saveInvito($invito,$this->getCategorieMerceologiche(),$soa,$progettazione); } return true; } return false; } public function saveTempInvito($lotto,$codice_fiscale,$denominazione,$pec,$updateContatori = true) { $invito = []; $invito["contesto"] = "gare"; $invito["codice_elemento"] = $this->round["codice"]; $invito["sub_elemento"] = $lotto; $invito["codice_fiscale_operatore"] = $codice_fiscale; $invito["denominazione"] = $denominazione; $invito["pec"] = $pec; $invito["attivo"] = "S"; $salva = new salva(); $salva->debug = false; $salva->nome_tabella = "temp_inviti"; $salva->operazione = "INSERT"; $salva->oggetto = $invito; $codice_invito = $salva->save(); if (!empty($codice_invito)) { $this->addToLog("INSERT",__("Invito operatore manuale") . ":" . $denominazione); if ($updateContatori) { $invito = []; $invito["codice_ente"] = $_SESSION["ente"]->codice; $invito["contesto"] = "gare"; $invito["codice_elemento"] = $this->round["codice"]; $invito["data_invito"] = date("d-m-Y"); $invito["sub_elemento"] = $lotto; $invito["codice_fiscale_operatore"] = $codice_fiscale; oeManager::saveInvito($invito,$this->getCategorieMerceologiche()); } return $codice_invito; } return false; } public function inviaInvito($destinatari) { $this->round = $this->getRounds($this->round["codice"])[0]; $this->round["infoFase"] = $this->getProcedura()["fasi"][$this->round["id"]] ?? []; if (strtotime($this->round["pubblicazione"]) < time()) { $editor = new editorManager("msg-invito-gara",0); $editor->vocabolario["ragione-sociale"] = $_SESSION["ente"]->getInfo()["denominazione"]; $editor->vocabolario["fase"] = $this->round; $editor->vocabolario["gara"] = $this->info; $editor->vocabolario["link"] = $_SESSION["config"]["link_sito"]."/gare/dettaglio.php?codice=".$this->info["codice"]; $editor->vocabolario["nome-sito"] = $_SESSION["config"]["nome_sito"]; $editor->vocabolario["description"] = $this->info["oggetto"]; $corpo = $editor->getModello(); $mailer = new Communicator(); $mailer->oggetto = __('Invito') . " - " . $this->info["oggetto"]; $mailer->corpo = $corpo; $mailer->codice_pec = $this->info["codice_pec"]; $mailer->comunicazione = true; $mailer->sezione = "gare"; $mailer->codice_gara = $this->info["codice"]; $mailer->coda = true; $mailer->destinatari = $destinatari; return $mailer->send(); } else{ $this->db->go("UPDATE b_gare SET invito_programmato = 'S' WHERE codice = :codice",[":codice"=>$this->info["codice"]]); return true; } } public function getInvitati($codice_lotto = null) { $filtro_lotto = null; if (isset($codice_lotto)) { $filtro_lotto = $codice_lotto; } else if (!empty($this->lotto)) { $filtro_lotto = $this->lotto["codice"]; } $bind = [":codice_round" => $this->round["codice"]]; $sql = "SELECT * FROM r_inviti_gare WHERE codice_round = :codice_round "; if (isset($filtro_lotto)) { $bind[":codice_lotto"]=$filtro_lotto; $sql .= " AND (codice_lotto = :codice_lotto OR codice_lotto = 0) "; } return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } public function getInvitatiManuali($codice_lotto = null) { $filtro_lotto = null; if (isset($codice_lotto)) { $filtro_lotto = $codice_lotto; } else if (!empty($this->lotto)) { $filtro_lotto = $this->lotto["codice"]; } $bind = [":codice_round" => $this->round["codice"]]; $sql = "SELECT * FROM temp_inviti WHERE contesto = 'gare' AND attivo = 'S' AND codice_elemento = :codice_round "; if (isset($filtro_lotto)) { $bind[":codice_lotto"]=$filtro_lotto; $sql .= " AND (sub_elemento = :codice_lotto OR sub_elemento = 0) "; } return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } public function countInvitati($codice_lotto = null) { return count($this->getInvitati($codice_lotto)) + count($this->getInvitatiManuali($codice_lotto)); } public function checkPartecipantiPresenti() { return !empty($this->db->go("SELECT codice FROM r_partecipanti_gare WHERE codice_round = :codice_round",[":codice_round"=>$this->round["codice"]])->rowCount()); } public function returnPartecipanti($filters = [],$all = false) { if (!empty($this->lotto)) { $bind = [":codice_round" => $this->round["codice"],":codice_lotto" => $this->lotto["codice"]]; $sql = "SELECT * FROM r_partecipanti_gare WHERE codice_round = :codice_round AND codice_lotto = :codice_lotto "; if (empty($all)) { $filters["conferma"] = "S"; } $where = []; $keys = array_keys(get_campi("r_partecipanti_gare")); foreach($keys AS $key) { if (isset($filters[$key])) { $where[] = "$key = :{$key}"; $bind[":{$key}"] = $filters[$key]; } } if (!empty($where)) { $sql .= " AND " . implode(" AND ",$where); } return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getPartecipante($codice,$all = false) { return $this->returnPartecipanti(["codice"=>$codice],$all)[0] ?? null; } public function getPartecipantiForAnomalia() { $tmps = $this->returnPartecipanti(); $partecipanti = []; foreach($tmps AS $tmp) { if ($tmp["escluso"] == "N" || $tmp["esclusione_automatica"] == "S") { $partecipanti[] = $tmp; } } return $partecipanti; } public function getPartecipanti($ammessi = NULL,$valutazione = null) { if (!empty($this->lotto)) { $filters = []; $all = false; if ($ammessi === TRUE) { $filters = ["escluso"=>"N"]; } else if ($ammessi === "ALL") { $all = true; } $return = $this->returnPartecipanti($filters,$all); if ($valutazione && !empty($return) && $this->getModalita()["online"]) { $tmp = $return; $return = []; $richieste = $this->getRichieste("tecnica"); if (!empty($richieste)) { $checkPunteggio = $this->db->prepare("SELECT b_gare_punteggi_partecipanti.codice FROM b_gare_punteggi_partecipanti JOIN b_gare_criteri_valutazione ON b_gare_punteggi_partecipanti.codice_criterio = b_gare_criteri_valutazione.codice WHERE codice_partecipante = :partecipante AND b_gare_criteri_valutazione.economico = 'N'"); foreach($tmp AS $partecipante) { $checkPunteggio->execute([":partecipante"=>$partecipante["codice"]]); if ($checkPunteggio->rowCount() > 0) { $return[$partecipante["codice"]] = $partecipante; } else { foreach($richieste AS $richiesta) { $busta = $this->getBusta($partecipante["codice"],$richiesta["codice"]); if (!empty($busta) && $busta["open"] == "S") { $return[$partecipante["codice"]] = $partecipante; break; } } } } $return = array_values($return); } } return $return; } } public function getGraduatoria($ammessi = NULL) { $partecipanti = []; $tmp = $this->getPartecipanti($ammessi); if (!empty($tmp)) { $ammessi = []; $esclusi = []; foreach($tmp AS $partecipante) { if ($partecipante["escluso"] == "N") { $ammessi[] = $partecipante; } else { $esclusi[] = $partecipante; } } if (!empty($ammessi)) { usort($ammessi, "sortPartecipantiTotale"); } if (!empty($esclusi)) { usort($esclusi, "sortPartecipantiTotale"); } $partecipanti = array_merge($ammessi,$esclusi); } return $partecipanti; } public function checkImported($busta) { $imported = explode(".", $busta); if (is_array($imported)) { $imported = end($imported); if ($imported == "imported-offer") { return true; } } return false; } public function downloadBusta(array $busta) { global $config; $richiesta = $this->getRichiesta($busta["codice_richiesta"]); $partecipante = $this->getPartecipante($busta["codice_partecipante"]); $imported = $this->checkImported($busta["nomeFile"]); $file_content = $busta["content"]; if (P7Manager::bustaEstensioneSoloP7M($busta["nomeFile"])) { $ext = getTypeAndExtension($file_content, true); $busta["nomeFile"] = str_replace(".p7m", "{$ext["ext"]}", $busta["nomeFile"]); } if ($imported === true) { $ext = getTypeAndExtension($file_content, true); $busta["nomeFile"] = str_replace(".imported-offer", "{$ext["ext"]}", $busta["nomeFile"]); } if (strpos($busta["nomeFile"], ".x-empty") !== false) { $ext = getTypeAndExtension($file_content, true); $busta["nomeFile"] = substr($busta["nomeFile"], 0, strpos($busta["nomeFile"], ".x-empty")) . "." . $ext["ext"]; } if ($_POST["openP7M"] == "S") { $path = $config["chunk_folder"] . "/" . $_SESSION["utente"]->codice; if (!is_dir($path)) { mkdir($path); } $path .= "/" . $busta["nomeFile"]; file_put_contents($path, $file_content); $file_content = ""; if (file_exists($path)) { $p7m = new P7Manager($path); if ($p7m !== false) { $file_content = $p7m->extract(true); $file_info = new finfo(FILEINFO_MIME_TYPE); $mime_type = $file_info->buffer($file_content); $ext = P7manager::extFromMime($mime_type); $busta["mime"] = $mime_type; $busta["nomeFile"] = str_replace(".p7m", ".{$ext}", $busta["nomeFile"]); } unlink($path); } } if (!empty($file_content)) { $busta["nomeFile"] = $partecipante["codice_fiscale"] . "-" . $richiesta["busta"] . "-" . $busta["nomeFile"]; header('Content-Description: File Transfer'); header('Content-Disposition: attachment; filename=' . str_replace("-", ".", $busta["nomeFile"])); header('Content-Type: ' . $busta["mime"]); header('Content-Transfer-Encoding: binary'); header('Connection: Keep-Alive'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); echo $file_content; return true; } } public function decryptBusta(array $busta,string $private,string $type) { switch ($type) { case "busta": $table = "b_gare_buste"; $decDescrizione = false; break; case "emendamento": $table = "b_gare_emendamenti"; $decDescrizione = true; break; case "segreto": $table = "b_gare_buste_secretate"; $decDescrizione = true; break; } $return = __("Errore nella richiesta"); if (!empty($table)) { $imported = $this->checkImported($busta["nomeFile"]); $key = openssl_pkey_get_private($private); if (@openssl_private_decrypt($busta["salt"],$salt,$key)) { global $config; $addSalt = $config["simple_encrypt"]["offer"]; $busta["content"] = openssl_decrypt($busta["content"],"AES128",$salt,OPENSSL_RAW_DATA,$addSalt); if ($decDescrizione) { $busta["descrizione"] = simple_decrypt($busta["descrizione"],$salt); } if ($busta["content"] !== false && !empty($busta["password"])) { if ($imported === true) { $fileInfo = getTypeAndExtension($busta["content"],true); $busta["mime"] = $fileInfo["type"]; $busta["nomeFile"] = str_replace(".imported-offer","",$busta["nomeFile"]) . $fileInfo["ext"]; } $content = simple_encrypt($busta["content"],$busta["password"]); if (!empty($content) && file_put_contents($busta["path"],$content)) { unset($busta["content"]); $busta["open"] = "S"; $busta["utente_decrypt"] = $_SESSION["utente"]->codice; $busta["timestamp_decrypt"] = date('Y-m-d H:i:s'); $salva = new salva(); $salva->debug = false; $salva->nome_tabella = $table; $salva->operazione = "UPDATE"; $salva->oggetto = $busta; $salva->expect = array("codice","nomeFile","mime","content","open","utente_decrypt","timestamp_decrypt"); if ($decDescrizione) { $salva->expect[] = "descrizione"; } $esito = $salva->save(); if ($esito > 0) { $return = true; } } else { $return = __("Errore nel salvataggio del contenuto decriptato") . " - #001"; } } else { $return = __("Errore nella decriptazione del contenuto") . " - #001"; } } else { $return = __("Chiave errata") . " - #002"; } } return $return; } public function getBusta($partecipante, $richiesta, $aggiuntive = false, bool $contenuto = false) { $return = false; $select = "*"; if (!$aggiuntive) { $sql = "SELECT {$select} FROM b_gare_buste WHERE codice_partecipante = :partecipante AND codice_richiesta = :richiesta ORDER BY codice DESC"; } else { $sql = "SELECT {$select} FROM b_gare_buste_aggiuntive WHERE codice_partecipante = :partecipante AND codice_richiesta = :richiesta ORDER BY codice DESC"; } $bind = [":partecipante" => $partecipante, ":richiesta" => $richiesta]; $return = $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); if (!empty($return)) { $return = $return[0]; $return["path"] = $this->getSpecificBustaPath($return); if ($contenuto) { adaptMemoryLimitToFile($return["path"]); $content = file_get_contents($return["path"]); if (!empty($content)) { if ($return["open"] == "S") { $content = simple_decrypt($content,base64_decode($return["content"])); } else { $return["password"] = base64_decode($return["content"]); } $return["content"] = $content; } } } return $return; } public function getSpecificBustaPath($busta) { return $this->getBustePath($busta["codice_partecipante"])."/{$busta["codice_richiesta"]}-{$busta["sha1"]}"; } public function getBustePath(int $partecipante = null) { if (!empty($this->lotto) && !empty($this->round)) { global $config; $path = "{$config["mediaFolder"]}/{$_SESSION["ente"]->codice}/gare-buste/{$this->info["codice"]}/{$this->round["codice"]}/{$this->lotto["codice"]}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; if (!empty($partecipante)) { $return = false; $path .= "/{$partecipante}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; } } if ($return) { return $path; } } } } public function getBustaSecretata($partecipante, $richiesta, $derivazione, bool $contenuto = false) { $return = false; $select = "*"; $sql = "SELECT {$select} FROM b_gare_buste_secretate WHERE derivazione = :derivazione AND codice_partecipante = :partecipante AND codice_richiesta = :richiesta ORDER BY codice DESC"; $bind = [":partecipante" => $partecipante, ":richiesta" => $richiesta, ":derivazione" => $derivazione]; $return = $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); if (!empty($return)) { $return = $return[0]; $return["path"] = $this->getSpecificSecretatePath($return); if ($contenuto) { adaptMemoryLimitToFile($return["path"]); $content = file_get_contents($return["path"]); if (!empty($content)) { if ($return["open"] == "S") { $content = simple_decrypt($content,base64_decode($return["content"])); } else { $return["password"] = base64_decode($return["content"]); } $return["content"] = $content; } } } return $return; } public function getSpecificSecretatePath($busta) { return $this->getBustePath($busta["codice_partecipante"])."/{$busta["codice_richiesta"]}-{$busta["derivazione"]}-{$busta["sha1"]}"; } public function getSecretatePath(int $partecipante = null) { if (!empty($this->lotto) && !empty($this->round)) { global $config; $path = "{$config["mediaFolder"]}/{$_SESSION["ente"]->codice}/gare-secretate/{$this->info["codice"]}/{$this->round["codice"]}/{$this->lotto["codice"]}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; if (!empty($partecipante)) { $return = false; $path .= "/{$partecipante}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; } } if ($return) { return $path; } } } } public function getEmendamento($partecipante, $richiesta, bool $contenuto = false) { $return = false; $select = "*"; $sql = "SELECT {$select} FROM b_gare_emendamenti WHERE codice_partecipante = :partecipante AND codice_richiesta = :richiesta "; $bind = [":partecipante" => $partecipante, ":richiesta" => $richiesta]; $return = $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); if (!empty($return)) { $return = $return[0]; $return["path"] = $this->getSpecificEmendamentoPath($return); if ($contenuto) { adaptMemoryLimitToFile($return["path"]); $content = file_get_contents($return["path"]); if (!empty($content)) { if ($return["open"] == "S") { $content = simple_decrypt($content,base64_decode($return["content"])); } else { $return["password"] = base64_decode($return["content"]); } $return["content"] = $content; } } } return $return; } public function getSpecificEmendamentoPath($busta) { return $this->getEmendamentoPath($busta["codice_partecipante"])."/{$busta["codice_richiesta"]}-{$busta["sha1"]}"; } public function getEmendamentoPath(int $partecipante = null) { if (!empty($this->lotto) && !empty($this->round)) { global $config; $path = "{$config["mediaFolder"]}/{$_SESSION["ente"]->codice}/gare-emendamenti/{$this->info["codice"]}/{$this->round["codice"]}/{$this->lotto["codice"]}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; if (!empty($partecipante)) { $return = false; $path .= "/{$partecipante}"; if (!file_exists($path)) { mkdir($path,0777,true); } if (is_dir($path)) { $return = true; } } if ($return) { return $path; } } } } public function arrangePartecipantiForANAC($tmp) { $partecipanti = []; foreach ($tmp as $partecipante) { $raggruppamento = $this->getRaggruppamento($partecipante["codice"]); if (!empty($raggruppamento)) { $partecipante["raggruppamento"] = $raggruppamento; } unset($partecipante["codice"]); $partecipanti[] = $partecipante; } return $partecipanti; } public function updatePartecipantiANAC() { if (!empty($this->lotto["cig"])) { $tmp = $this->getPartecipanti(); if (!empty($tmp)) { $partecipanti = $this->arrangePartecipantiForANAC($tmp); anac::updatePartecipanti190($this->lotto["cig"], $partecipanti); } } } public function creaIstanzaANAC(string $smart_cig = "N") { $return = false; $record = $this->info; $lotti = $this->getLotti(); $beneficiario = Ente::getInfoFromID($record["codice_ente"])[0]; $relazioni = anac::relazioniModulo("gare", $this->info["codice"]); if (empty($relazioni)) { $gara = []; $gara["codice"] = 0; $gara["smart_cig"] = $smart_cig; $gara["oggetto"] = $record["oggetto"]; $gara["anno_riferimento"] = date("Y"); $gara["codice_ente"] = $record["codice_ente"]; $gara["codice_gestore"] = $_SESSION["ente"]->codice; $gara["dati"]["cf_sua"] = $beneficiario["cf"]; $gara["dati"]["denominazione_sua"] = $beneficiario["denominazione"]; $gara["dati"]["categorie_merc"] = [999]; if ($smart_cig == "N") { $gara["dati"]["importo"] = $record["prezzoRiferimento"]; $gara["dati"]["numero_lotti"] = count($lotti); $gara["dati"]["tipo_scheda"] = ""; $gara["dati"]["modo_indizione"] = ""; $gara["dati"]["allegato_ix"] = ""; $gara["dati"]["modo_realizzazione"] = ""; $gara["dati"]["motivo_rich_cig"] = ""; $gara["dati"]["cig_acc_quadro"] = ""; $gara["dati"]["durata_accquadro_convenzione_gara"] = ""; $gara["dati"]["escluso_avcpass"] = ""; $gara["dati"]["urgenza_dl133"] = ""; $gara["dati"]["estrema_urgenza"] = ""; $gara["dati"]["strumento_svolgimento"] = ""; $gara["dati"]["id_f_delegate"] = ""; $gara["dati"]["cf_amm_agente_gara"] = ""; } else { $lottoDB = $lotti[0]; $gara["lotto"]["cig"] = $lottoDB["cig"]; $gara["lotto"]["importo"] = $record["prezzoRiferimento"]; $gara["dati"]["codiceProceduraSceltaContraente"] = anac::getSceltaContraenteFromGara($record["procedura"],"S",$record["timestamp_creazione"]); $gara["dati"]["codiceClassificazioneGara"] = ""; $gara["dati"]["codiceFattispecieContrattuale"] = ""; $gara["dati"]["cigAccordoQuadro"] = ""; $gara["cup"] = $lottoDB["cup"]; $gara["dati"]["motivo_rich_cig_catmerc"] = ""; } $anac = new anac(); $anac->modulo = "gare"; $esito_gara = $anac->saveGara($gara); if ($esito_gara["esito"] === true) { $return["codice_gara_simog"] = $esito_gara["codice"]; $creazione = true; $anac = anac::init($esito_gara["codice"]); if ($smart_cig == "S") { $relazione = $anac->saveRelazione("gare", $record["codice"], $lottoDB["codice"], $anac->getLotti()[0]["codice"]); if (empty($relazione)) { $this->db->go("DELETE FROM b_simog WHERE codice = :codice", [":codice" => $esito_gara["codice"]]); $return["errore_lotto"] = true; } } } else { $return["msg"] = ""; if (!empty($esito_gara["errori"])) { $return["msg"] = implode("
", $esito_gara["errori"]); } } } else { $relazioni = reset($relazioni); $return["codice_gara_simog"] = $relazioni["gara_simog"]; $anac = anac::init($return["codice_gara_simog"]); } if (!empty($anac->info) && $anac->info["smart_cig"] == "N") { foreach ($lotti as $lottoDB) { $relazioni = anac::relazioniModulo("gare", $record["codice"], $lottoDB["codice"]); if (empty($relazioni)) { $lotto = []; $lotto["codice"] = 0; $lotto["codice_simog"] = $anac->info["codice"]; $lotto["oggetto"] = $lottoDB["oggetto"]; $lotto["cig"] = $lottoDB["cig"]; $lotto["cup"] = $lottoDB["cup"]; $lotto["importo"] = $lottoDB["importoBase"]; $lotto["dati"]["importo_attuazione_sicurezza"] = $lottoDB["oneriNoRibasso"]; $lotto["cpv"] = [$lottoDB["cpv"]]; $lotto["id_scelta_contraente"] = anac::getSceltaContraenteFromGara($record["procedura"],"N",$record["timestamp_creazione"]); $lotto["dati"]["condizioni"] = ""; $lotto["dati"]["id_aff_riservati"] = ""; $lotto["dati"]["tipo_contratto"] = ""; $lotto["dati"]["id_categoria_prevalente"] = ""; $lotto["dati"]["categoria_merc"] = ""; $lotto["dati"]["flag_escluso"] = ""; $lotto["dati"]["id_esclusione"] = ""; $lotto["dati"]["flag_regime"] = ""; $lotto["dati"]["art_regime"] = ""; $lotto["dati"]["luogo_nuts"] = ""; $lotto["dati"]["flag_dl50"] = ""; $lotto["dati"]["prima_annualita"] = ""; $lotto["dati"]["annuale_cui_mininf"] = ""; $lotto["dati"]["tipoappalto"] = ""; $lotto["dati"]["id_motivo_coll_cig"] = ""; $lotto["dati"]["cig_origine_rip"] = ""; $lotto["dati"]["flag_no_adesione_iniziativa"] = ""; $lotto["dati"]["flag_sa_non_classificata"] = ""; $esito_lotto = $anac->saveLotto($lotto,true,true); if ($esito_lotto["esito"] === true) { $relazione = $anac->saveRelazione("gare", $record["codice"], $lottoDB["codice"], $esito_lotto["codice"]); if (empty($relazione) && !empty($creazione)) { $this->db->go("DELETE FROM b_simog WHERE codice = :codice", [":codice" => $esito_gara["codice"]]); $return["errore_lotto"] = true; } anac::importazioneSuggerimenti190Lotto($lotto); } else { $return["msg"] = ""; $return["errore_lotto"] = true; if (!empty($esito_lotto["errori"])) { $return["msg"] = implode("
", $esito_lotto["errori"]); } } } } } return $return; } public function selezioneManualeAggiudicatari() { return ($this->quickPanel || !$this->usaGraduatoria() || (settingsManager::getValue("proponiAggiudicazioneMultiplaManuale") === "S" && ($this->getRisposteElaborazione()["aggiudicazioneManuale"] ?? "N") == "S")); } public function getAggiudicatari($codice_lotto = NULL) { if (!empty($codice_lotto)) { $lottoSearch = $this->getLotti($codice_lotto)[0] ?? false; } else if (!empty($this->lotto)) { $lottoSearch = $this->lotto; } if (!empty($lottoSearch)) { $bind = [":codice_round" => $this->round["codice"],":codice_lotto" => $lottoSearch["codice"]]; $sql = "SELECT * FROM r_partecipanti_gare WHERE codice_round = :codice_round AND aggiudicatario = 'S' AND codice_lotto = :codice_lotto"; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } } public function getAggiudicatario($codice) { return $this->returnPartecipanti(["codice"=>$codice,"aggiudicatario"=>"S"])[0] ?? ""; } public function getImportoAggiudicazione() { $aggiudicatari = $this->getImportoAggiudicazionePartecipanti(); if (!empty($aggiudicatari)) { $totale = 0; foreach ($aggiudicatari as $aggiudicatario) { if (!empty($aggiudicatario["offerta"])) { $totale += $aggiudicatario["offerta"]; } } return $totale; } } public static function formatiOffertaDisponibili () { return [ "ribasso" => "Ribasso percentuale", "rialzo" => "Rialzo percentuale", "assoluto" => "Ribasso con prezzo assoluto", "r-assoluto" => "Rialzo con prezzo assoluto", "nulla" => "Non prevista" ]; } public function getImportoAggiudicazionePartecipanti($totale = true, $onlyAggiudicatario = true) { $partecipanti = $this->getGraduatoria(); $criteri = $this->getCriteriEconomici(); $formato = $this->lotto["formato"]; $aggiudicatari = []; foreach ($partecipanti as $partecipante) { if (!$onlyAggiudicatario || $partecipante["aggiudicatario"] == "S") { $aggiudicatari[$partecipante["codice"]] = $partecipante; } } if (!empty($criteri)) { $extraInfoLotto = $this->getExtraInfo()["lotto"] ?? null; if (count($criteri) === 1 && !empty($extraInfoLotto["ribassoAggiudicazione-{$this->round["codice"]}"])) { $criterio = reset($criteri); $ribasso = number_format($extraInfoLotto["ribassoAggiudicazione-{$this->round["codice"]}"],$criterio["decimali"],".",""); foreach ($aggiudicatari as $i => $aggiudicatario) { if ($totale) { if (!isset($aggiudicatario["offerta"])) { $aggiudicatario["offerta"] = 0; } if ($this->normaRiferimento == "2023-36") { $offerta = ($this->lotto["importoBase"] + $this->lotto["importoManodopera"]) * $ribasso / 100; $offerta = ($this->lotto["importoBase"] + $this->lotto["importoManodopera"]) - $offerta; } else { $offerta = $this->lotto["importoBase"] * $ribasso / 100; $offerta = $this->lotto["importoBase"] - $offerta; } $offerta += $this->lotto["oneriNoRibasso"]; $aggiudicatario["offerta"] += $offerta; $aggiudicatari[$i] = $aggiudicatario; } else { $aggiudicatari[$i]["offerta"][$criteri[0]["codice"]] = $ribasso; } } } else { foreach ($criteri as $criterio) { $offerte = $this->getOfferte($criterio["codice"], $totale); if (!empty($offerte)) { if (count($criteri) === 1 && $this->getInterpretazioneArt41() === "scorporato") { $offerte = $this->getRibassoComplessivoArt41($offerte,true); foreach ($aggiudicatari as $i => $aggiudicatario) { if (!isset($aggiudicatario["offerta"])) { $aggiudicatario["offerta"] = 0; } $offerta = number_format($offerte[$aggiudicatario["codice"]],$criterio["decimali"],".",""); $offerta += $this->lotto["oneriNoRibasso"]; $aggiudicatario["offerta"] += $offerta; $aggiudicatari[$i] = $aggiudicatario; } } else { foreach ($aggiudicatari as $i => $aggiudicatario) { if ($totale) { if (!isset($aggiudicatario["offerta"])) { $aggiudicatario["offerta"] = 0; } if (!empty($offerte[$aggiudicatario["codice"]])) { $offerta = number_format($offerte[$aggiudicatario["codice"]],$criterio["decimali"],".",""); if ($formato == "ribasso" || $formato == "rialzo" || (($criterio["auto"] == "P" || $criterio["auto"] == "B" || $criterio["auto"] == "Q") && ($offerta < 100))) { if ($this->normaRiferimento == "2023-36") { $offerta = ($this->lotto["importoBase"] + $this->lotto["importoManodopera"]) * $offerta / 100; if ($formato != "rialzo") { $offerta = ($this->lotto["importoBase"] + $this->lotto["importoManodopera"]) - $offerta; } else { $offerta = ($this->lotto["importoBase"] + $this->lotto["importoManodopera"]) + $offerta; } } else { $offerta = $this->lotto["importoBase"] * $offerta / 100; if ($formato != "rialzo") { $offerta = $this->lotto["importoBase"] - $offerta; } else { $offerta = $this->lotto["importoBase"] + $offerta; } } } $offerta += $this->lotto["oneriNoRibasso"]; $aggiudicatario["offerta"] += $offerta; $aggiudicatari[$i] = $aggiudicatario; } } else { $aggiudicatari[$i]["offerta"][$criterio["codice"]] = $offerte[$aggiudicatario["codice"]] ?? NULL; } } } } } } } return $aggiudicatari; } public function getSedute($codice = null) { $bind = [":round" => $this->round["codice"]]; $sql = "SELECT * FROM b_gare_sedute WHERE codice_round = :round "; if (!empty($codice)) { $bind[":codice"] = $codice; $sql .= " AND codice = :codice "; } $sql .= " ORDER BY codice DESC "; return $this->db->go($sql, $bind)->fetchAll(PDO::FETCH_ASSOC); } public function listPartecipanti($partecipante = null) { if (!empty($partecipante)) { $partecipante = $this->getPartecipante($partecipante,true); $raggruppamento = $this->getRaggruppamento($partecipante["codice"]); $list_partecipanti = ""; if (!empty($raggruppamento)) { $list_partecipanti = "RAGGRUPPAMENTO
" . $partecipante["ragione_sociale"] . " - " . $partecipante["codice_fiscale"] . " - 04-CAPOGRUPPO"; foreach ($raggruppamento as $membro) { $list_partecipanti .= "
" . $membro["ragione_sociale"] . " - " . $membro["codice_fiscale_impresa"] . " - " . $membro["ruolo"]; } } $avvalimento = $this->getAvvalimento($partecipante["codice"]); if (!empty($avvalimento)) { $list_partecipanti .= "
AVVALIMENTO"; foreach ($avvalimento as $membro) { $list_partecipanti .= "
" . $membro["ragione_sociale"] . " - " . $membro["codice_fiscale_impresa"] . " - " . $membro["ruolo"]; } } if (empty($list_partecipanti)) { $list_partecipanti = $partecipante["ragione_sociale"] . " - " . $partecipante["codice_fiscale"]; } return $list_partecipanti; } else { return false; } } public function getCommissari($tipologia, $codice_utente = NULL) { return $this->getManagerCommissione($tipologia)->getCommissari($codice_utente); } public function getConferences($codice = NULL) { $conference = []; foreach ($this->getRounds() as $round) { $tmp = conferenceManager::getMeetingsFromDB("gare", $this->info["codice"], "seduta", $round["codice"]); if (!empty($tmp)) { $conference = array_merge($conference, $tmp); } $seggio = new Commissione("gare", $round["codice"], "seggio"); if (!empty($seggio->getInfo())) { $tmp = conferenceManager::getMeetingsFromDB("commissioni", $seggio->getInfo()["codice"], $seggio->tipologia, 0); if (!empty($tmp)) { $conference = array_merge($conference, $tmp); } } $commissione = new Commissione("gare", $round["codice"], "commissione"); if (!empty($commissione->getInfo())) { $tmp = conferenceManager::getMeetingsFromDB("commissioni", $commissione->getInfo()["codice"], $commissione->tipologia, 0); if (!empty($tmp)) { $conference = array_merge($conference, $tmp); } } } if (!empty($conference)) { if (!empty($codice)) { $tmp = $conference; $conference = []; foreach ($tmp as $meet) { if ($meet["codice"] == $codice) { $conference = $meet; break; } } } else { $timestamp = array_column($conference, 'timestamp'); array_multisort($timestamp, SORT_DESC, $conference); } } return $conference; } static function getModuli($filters = null, $stato = null, $fase = null, $quick = false) { global $config; $moduli = jsonToArray($config["jsonFolder"] . "/gare-panel.json"); $tmp = []; foreach ($moduli as $id_modulo => $modulo) { $insert = true; if (is_array($filters) && !empty($filters)) { foreach ($filters as $key => $value) { if ($modulo[$key] !== $value) { $insert = false; } } } if ($quick) { if (!$modulo["quick-panel"]) { $insert = false; } } else { if ($insert && $stato !== null) { if ($modulo["stato_minimo"] > $stato) { $insert = false; } if ($insert && $fase !== null) { if ($modulo["fase_minima"] !== null && $fase < $modulo["fase_minima"]) { $insert = false; } if ($modulo["fase_massima"] !== null && $fase > $modulo["fase_massima"]) { $insert = false; } } } } if (is_array($modulo["stati_esclusi"]) && in_array($stato, $modulo["stati_esclusi"]) !== false) { $insert = false; } if ($insert) { $tmp[$id_modulo] = $modulo; } $moduli = $tmp; } return $moduli; } static function getInfoModulo($radice) { $return = false; if (!empty($radice)) { $moduli = self::getModuli(false); if (!empty($moduli[$radice])) { $return = $moduli[$radice]; $return["id"] = $radice; $return["titolo"] = __($return["titolo"]); $return["descrizione"] = __($return["descrizione"]); } } return $return; } public function getAvvisi() { return $this->getManagerAvvisi()->getAvvisi("N"); } public function printAvvisi() { return $this->getManagerAvvisi()->printPublic(); } public function getContratti() { return stipula::getContrattiFromModulo("gare", $this->lotto["codice"]); } public function getPubblicazioniGUUE() { global $beRoot; include_once($beRoot."/guue/class/TedEsender.class.php"); return TedEsender::getPubblicazioniFromModulo("gare", $this->info["codice"]); } public function getStatoPannello() { $statoMax = $this->info["stato"]; $statoMin = null; foreach($this->getLotti() AS $lotto) { if ($lotto["stato"] > 0) { if ($lotto["stato"] > $statoMax) { $statoMax = $lotto["stato"]; } if ($lotto["stato"] < $statoMin || $statoMin === null) { $statoMin = $lotto["stato"]; } } } if ($statoMin === null) { $statoMin = $this->info["stato"]; } if (!$this->usaGraduatoria() && $statoMin == 21) { $statoMin = 21; $statoMax = 30; } return ["min"=>$statoMin,"max"=>$statoMax]; } public function serialize(bool $checkPubblica = true) : ?array { if($checkPubblica) { // TODO Verificare che si trovi in uno stato finale E abbia i CIG, in quel caso possiamo procedere all'invio // Verifica che sia pubblica per tutti if($this->round["pubblica"] != 2) { return null; } // Verifica della data di pubblicazione $dataPubblicazione = $this->round["pubblicazione"]; if(strtotime($dataPubblicazione) > time()){ return null; } } global $pdo; global $config; $data = []; $whitelist = [ "anno", "stato", "procedura", "modalita", "tipologia", "accordo_quadro", "oggetto", "fase_attiva", "prezzoRiferimento", "extraInfo", "timestamp_creazione" ]; $whitelist_lotto = [ "cig", "cup", "cpv", "criterio", "formato", "oggetto", "descrizione", "importoBase", "importoManodopera", "oneriNoRibasso", "importoOpzioni", "importoAggiudicazione", "sogliaAnomalia", "extraInfo", "stato" ]; $whitelist_partecipante = [ "codice_operatore", "stato", "codice_fiscale", "ragione_sociale", "escluso", "aggiudicatario", "tipo" ]; $whitelist_round = [ "id", "pubblica", "pubblicazione", "chiarimenti", "sopralluogo", "scadenza", "extraInfo", "attivo", "metadata_fase" ]; $whitelist_allegati = [ "url", "mime", "name", "titolo" ]; // Dati base foreach($this->info as $key => $entry) { if(!in_array($key, $whitelist, true)) continue; if(is_string($entry) && valid_json($entry, $entry_data, true)) { $entry = $entry_data; } $data[$key] = $entry; } $data["url"] = $this->getPublicExternalURL(); // Stazione Appaltante $data["ente"] = $this->getEnteBeneficiario(["denominazione"]); // Lotti foreach($this->getLotti() as $lotto) { $codiceLotto = $lotto['codice']; $target = &$data['lotti'][$codiceLotto]; $this->setLotto($lotto['codice']); foreach($lotto as $key => $entry) { if(!in_array($key, $whitelist_lotto, true)) continue; if(is_string($entry) && valid_json($entry, $entry_data, true)) { $entry = $entry_data; } $target[$key] = $entry; } $target['soa'] = $this->getSOASerialize(); $target['cpv'] = $this->getCPVLotto($lotto['codice']); $target["id_lotto"] = "{$this->getPublicIdentifier()}-L-{$codiceLotto}"; // Partecipanti if($this->pubblicaPartecipanti($lotto['codice'])) { foreach($this->getPartecipanti("ALL") ?? [] as $partecipante) { if(empty($partecipante['uuid'])) { continue; } $targetP = &$target['partecipanti'][$partecipante['uuid']]; if($partecipante["codice_operatore"] > 0) { $oe = oeManager::getOE($partecipante["codice_operatore"]); if($oe) { $partecipante["tipo"] = $oe["tipo"]; } } foreach($partecipante as $key => $entry) { if(!in_array($key, $whitelist_partecipante, true)) { continue; } if(is_string($entry) && valid_json($entry, $entry_data, true)) { $entry = $entry_data; } $targetP[$key] = $entry; } $targetP["raggruppamento"] = array_column($this->getRaggruppamento($partecipante['codice']), null, "identifier"); $targetP["avvalimento"] = array_column($this->getAvvalimento($partecipante['codice']), null, "identifier"); } } } // Allegati // Round $rounds = $this->getRounds(); if(!empty($rounds)) { $i = 0; foreach($rounds as $round) { if($checkPubblica) { if($round["pubblica"] != 2) { continue; } $dataPubblicazione = $round["pubblicazione"]; if(strtotime($dataPubblicazione) > time()){ continue; } } $round['attivo'] = $round["numero"] == $this->round["numero"]; $round['metadata_fase'] = $this->getProcedura()["fasi"][$round["id"]] ?? []; $target = &$data['round'][$i++]; foreach($round as $key => $entry) { if(!in_array($key, $whitelist_round, true)) { continue; } if(is_string($entry) && valid_json_recursive($entry, $entry_data)) { $entry = $entry_data; } $target[$key] = $entry; } $allegati = filesManager::listFilesWithLink(NULL, $round["codice"],"gare-public","A") ?? []; $link = $config["protocollo"] . getCurrentDomain(); if(!empty($allegati)) { foreach($allegati as $index => $allegato) { $allegato['url'] = $link . filesManager::getAttachURL($allegato, $round["codice"], "gare-public", false); foreach($allegato as $key => $entry) { if(!in_array($key, $whitelist_allegati, true)) { continue; } $target['allegati'][$index][$key] = $entry; } } } } } array_walk_recursive($data, function(&$val, &$key) use($pdo){ if($key === "nuts" && !empty($val)) { $res = $pdo->go( "SELECT descrizione FROM b_nuts WHERE nuts = :nuts LIMIT 1", [":nuts" => $val] ); $val = ["id" => $val, "descrizione" => ""]; if ($res->rowCount() > 0) { $val["descrizione"] = $res->fetch(PDO::FETCH_ASSOC)["descrizione"]; } } if ($val === "S" || $val === "SI") { $val = true; } elseif($val === "N" || $val === "NO") { $val = false; } }); recursive_unset($data, ["utente_modifica", "utente_creazione", "codice", "codice_lotto", "timestamp"]); $npa = $this->getNpaInstance(); $data["codice_gara"] = $this->getPublicIdentifier(); if($npa) { if(!empty($npa->fascicolo["id_appalto"])) $data["id_appalto"] = $npa->fascicolo["id_appalto"]; if(!empty($npa->fascicolo["codice_appalto"])) $data["codice_appalto"] = $npa->fascicolo["codice_appalto"]; } return $data; } public function getModelli($codice = null) { $statoMax = $this->getStatoPannello()["max"]; $lotti = $this->getLotti(); if (!empty($lotti)) { $criteri = array_column($lotti,"criterio"); } $bind = [ ":norma" => "%\"{$this->normaRiferimento}\"%", ":procedura" => "%\"{$this->info["procedura"]}\"%", ":tipologia" => "%\"{$this->info["tipologia"]}\"%", ":fase"=>$statoMax, ":reservedEnte"=>"__reserved-{$_SESSION["ente"]->codice}-%", ":dataPubblicazione"=>($this->getRounds()[0]["pubblicazione"] ?? date('Y-m-d')) ]; if (!empty($criteri)) { $criteri = array_unique($criteri); if (count($criteri) === 1) { $criterio = reset($criteri); $bind[":criterio"] = "%\"{$criterio}\"%"; } } $sql = "SELECT * FROM b_impostazioni_modelli_gara WHERE attivo = 'S' AND soft_delete = 'N' AND norma LIKE :norma AND (criterio LIKE :criterio OR criterio IS NULL OR criterio = '') AND (tipologia LIKE :tipologia OR tipologia IS NULL OR tipologia = '') AND (procedura LIKE :procedura OR procedura IS NULL OR procedura = '') AND fase_minima <= :fase AND (tipo NOT LIKE '__reserved-%' OR tipo LIKE :reservedEnte) AND (dataInizio IS NULL OR dataInizio <= :dataPubblicazione) AND (dataFine IS NULL OR dataFine >= :dataPubblicazione) "; if (!empty($codice)) { $bind[":codice"] = $codice; $sql .= " AND codice = :codice"; } $sql .= " ORDER BY ordinamento ASC, codice ASC"; $return = $this->db->go($sql,$bind)->fetchAll(PDO::FETCH_ASSOC); if (!empty($codice)) { $return = $return[0]; } return $return; } public function checkLockModello($codice) { $modello = $this->getModelli($codice); $statoMax = $this->getStatoPannello()["max"]; if ($statoMax <= $modello["fase_massima"]) { return false; } return true; } public function getDestinatariModello($codice) { $modello = $this->getModelli($codice); if (!empty($modello["destinatari"])) { switch($modello["destinatari"]) { case "T": $destinatari = $this->getDestinatari(true); break; case "P": // __("Partecipanti") $destinatari = array_column($this->getPartecipanti(),"codice_operatore"); break; case "O": // __("Ammessi") $partecipanti = $this->getPartecipanti(); foreach($partecipanti AS $partecipante) { if ($partecipante["escluso"] == "N") { $destinatari[] = $partecipante["codice_operatore"]; } } break; case "N": // __("Esclusi") $partecipanti = $this->getPartecipanti(); foreach($partecipanti AS $partecipante) { if ($partecipante["escluso"] == "S") { $destinatari[] = $partecipante["codice_operatore"]; } } break; case "A": // __("Aggiudicatari") $destinatari = array_column($this->getAggiudicatari(),"codice_operatore"); break; case "E": // __("Non aggiudicatari") $partecipanti = $this->getPartecipanti(); foreach($partecipanti AS $partecipante) { if ($partecipante["aggiudicatario"] == "N") { $destinatari[] = $partecipante["codice_operatore"]; } } break; } if (!empty($destinatari)) { $destinatari = array_unique($destinatari); $destinatari = array_filter($destinatari); return $destinatari; } } return false; } /** * checkCPVServiziArt74 * * @param Int $cpv * @return bool */ function checkCPVServiziArt74(Int $cpv) : bool { $cpv = (int) str_pad($cpv, 8, '0', STR_PAD_RIGHT); if(in_array($cpv, [75200000, 75231200, 75231240, 79611000, 79622000, 79624000, 79625000, 98133100, 98133000, 98200000, 98500000, 85321000, 85322000, 75000000, 75121000, 75122000, 75124000, 79950000, 79951000, 79952000, 79952100, 79953000, 79954000, 79955000, 79956000, 75300000, 75310000, 75311000, 75312000, 75313000, 75313100, 75314000, 75320000, 75330000, 75340000, 98000000, 98120000, 98132000, 98133110, 98130000, 98131000, 55521000, 55521100, 55521200, 55520000, 55522000, 55523000, 55524000, 55510000, 55511000, 55512000, 55523100, 75231100, 75123000, 79430000, 98113100, 79722000, 79723000, 98900000, 98910000, 64000000, 64100000, 64110000, 64111000, 64112000, 64113000, 64114000, 64115000, 64116000, 64122000, 50116510, 71550000])) { return true; } if($cpv >= 85000000 && $cpv <= 85323000) { return true; } if($cpv >= 98513000 && $cpv <= 98514000) { return true; } if($cpv >= 79995000 && $cpv <= 79995200) { return true; } if($cpv >= 80000000 && $cpv <= 80660000) { return true; } if($cpv >= 92000000 && $cpv <= 92700000) { return true; } if($cpv >= 55100000 && $cpv <= 55410000) { return true; } if($cpv >= 55521000 && $cpv <= 55521200) { return true; } if($cpv >= 79100000 && $cpv <= 79140000) { return true; } if($cpv >= 75100000 && $cpv <= 75120000) { return true; } if($cpv >= 75125000 && $cpv <= 75131000) { return true; } if($cpv >= 75200000 && $cpv <= 75231000) { return true; } if($cpv >= 75231210 && $cpv <= 75231230) { return true; } if($cpv >= 75240000 && $cpv <= 75252000) { return true; } if($cpv >= 79700000 && $cpv <= 79721000) { return true; } return false; } /** * Get the current bidding threshold. * * @return ?string */ function getSogliaGara() : ?string { $soglia = "sottosoglia"; $tipologia_ente = $this->db->go("SELECT tipologia_ente FROM b_enti WHERE codice = :codice_ente", [":codice_ente" => $this->info["codice_ente"]])->fetch(PDO::FETCH_COLUMN, 0); if(empty($tipologia_ente)) $tipologia_ente = 15; $tipologia_ente = array_column(ente::tipologieEnte(), null, "codice")[$tipologia_ente]; $tipologia = $this->info["tipologia"][0]; $prezzo = $this->info["prezzoRiferimento"]; $elaborazione = $this->getRisposteElaborazione(); $concessione = $elaborazione["concessione"] ?? "N"; $concessione = ($concessione == "S"); $cpvs = $this->getCategorieMerceologiche(); $servizi_art74 = false; if (! empty($cpvs)) { foreach($cpvs AS $cpv) { if($this->checkCPVServiziArt74($cpv)) { $servizi_art74 = true; break; } } } if ($concessione) { if($prezzo >= 5538000.00) { $soglia = "soprasoglia"; } } else { switch($tipologia) { case "L": if($prezzo >= 5538000.00) { $soglia = "soprasoglia"; } break; case "S": case "F": if(!empty($elaborazione) && $elaborazione["settoreRiferimento"] == "speciale") { if($prezzo >= 443000.00 && (!$servizi_art74 || $prezzo >= 1000000)) { $soglia = "soprasoglia"; } } else { if ($servizi_art74) { if ($prezzo >= 750000) { $soglia = "soprasoglia"; } } else { if($tipologia_ente["centrale"] == "S") { if($prezzo >= 143000.00) { $soglia = "soprasoglia"; } } else { if($prezzo >= 221000.00) { $soglia = "soprasoglia"; } } } } break; } } return $soglia; } public function getPublicIdentifier() : string { return generatePublicIdentifier("G", $this->info["codice_ente"], $this->info["codice"]); } /** * Get a new NuovaPiattaformaAppalti instance for the given tender. * * @return NuovaPiattaformaAppalti */ function getNpaInstance() : ?NuovaPiattaformaAppalti { if($this->npa) return $this->npa; $sql = "SELECT * FROM b_npa WHERE modulo_riferimento = :modulo_riferimento AND id_riferimento = :codice_riferimento ORDER BY revisione_fascicolo DESC LIMIT 0,1"; $bind = [":codice_riferimento" => $this->info["codice"], ":modulo_riferimento" => "gare"]; $fascicolo = $this->db->go($sql, $bind)->fetch(PDO::FETCH_ASSOC); if(! empty($fascicolo["codice"])) { $this->npa = NuovaPiattaformaAppalti::init($fascicolo["codice"], null, null, "gare", $this->info["codice"]); return $this->npa; } return null; } public function getRup() : ?Array { $incaricati = $this->getManagerIncarichi()->getIncaricati(); if (!empty($incaricati)) { $incaricati = array_column($incaricati, null, "ruolo"); if(! empty($incaricati[14])) { return $incaricati[14]; } } return null; } /** * Retrieves descendant cards for the given dossier. * * @return ?Array */ function getDescendantCards(bool $arrangeByCategory = true) : ?Array { $npa = $this->getNpaInstance(); if(! empty($npa)) { $elaborazione = $this->getRisposteElaborazione(); $soglia = $this->getSogliaGara(); $schede = $npa->getCardsAndItsDescendantsList($elaborazione["settoreRiferimento"], $soglia, ($elaborazione["concessione"] ?? "N") == "S", false); $procedura = $this->getProcedura(); if(count($procedura["fasi"]) < 2) { $schede = array_filter($schede, function($key) { return $key != "S1"; }, ARRAY_FILTER_USE_KEY); } return $arrangeByCategory ? $npa->arrangeCardsByCategory($schede) : $schede; } return null; } /** * Get the list of available cards for the NPA * * @return ?Array */ public function getInitialCards() : ?Array { $rounds = $this->getRounds(); $elaborazione = $this->getRisposteElaborazione(); $soglia = $this->getSogliaGara(); return NuovaPiattaformaAppalti::getInitialCards("gare", $this->info["procedura"], $rounds[0]["id"], $elaborazione["settoreRiferimento"], $soglia, ($elaborazione["concessione"] ?? "N") == "S") ; } /** * Updates the CIG (Contract Identification Code) within the application * * @param Int $codice * @param String $cig * @return Bool */ public function updateCig(Int $codice, String $cig) : void { $this->db->go("UPDATE b_gare_lotti SET cig = :cig WHERE codice = :codice", [":codice" => $codice, ":cig" => $cig]); $this->triggerUpdates(); } function getEnteBeneficiario(array $extraFields = []): ?array { if (empty($this->info) || empty($this->info["codice_ente"])) return null; $tmp = Ente::getInfoFromID($this->info["codice_ente"]); if (empty($tmp)) return null; $return = null; $tmp = reset($tmp); if (!empty($tmp["cf"])) { $return = ["codice_fiscale" => $tmp["cf"], "codice_ausa" => $tmp["codice_ausa"]]; } else { if (!empty($tmp["sua"]) && $tmp["ufficio"] == "S") { $tmp = Ente::getInfoFromID($tmp["sua"]); if (!empty($tmp)) { $tmp = reset($tmp); } } if (!empty($tmp["cf"])) { $return = ["codice_fiscale" => $tmp["cf"], "codice_ausa" => $tmp["codice_ausa"]]; } } if(!empty($return)) { foreach($extraFields as $extraField) { $return[$extraField] = $tmp[$extraField] ?? null; } } return $return; } public function deleteRound() : bool { if ($this->activeRound && $this->round["numero"] > 1 && !$this->checkPartecipantiPresenti()) { $check = $this->db->go("DELETE FROM b_gare_round WHERE codice_gara = :gara AND codice = :codice",[":gara"=>$this->info["codice"],":codice"=>$this->round["codice"]]); if ($check->rowCount() > 0) { $check = $this->db->go("UPDATE b_gare SET fase_attiva = fase_attiva - 1, stato = 21 WHERE codice = :gara",[":gara"=>$this->info["codice"]]); if ($check->rowCount() > 0) { return true; } } } return false; } public function clone() : Bool { $return = false; $copyInfo = $this->getExtraInfo()["gara"]["copyInfo"] ?? null; if (!empty($copyInfo["codice"])) { $source = self::init($copyInfo["codice"]); if (!empty($source)) { $cloner = new CloneGara($source,$this); return $cloner->clone(); } } return $return; } function getAggiudicazioneProdotti() :?Array { if(!empty($this->info)){ global $pdo; $sql = "SELECT r_gara_prodotto.codice_prodotto as codice, b_prodotti.denominazione, b_prodotti.codice_oe, b_prodotti.brand, b_prodotti.prezzo, b_prodotti.percIva FROM r_gara_prodotto LEFT JOIN b_prodotti ON r_gara_prodotto.codice_prodotto = b_prodotti.codice WHERE r_gara_prodotto.codice_gara = :codice_gara"; $ris = $pdo->go($sql, [':codice_gara' => $this->info['codice']]); if($ris->rowCount() > 0){ return $ris->fetchAll(PDO::FETCH_ASSOC); } } return []; } public function canAddOrRemovePartecipanti() { if($this->checkLock("partecipanti")) return false; $npa = $this->getNpaInstance(); if($npa !== null) return !$npa->hasLockOnPartecipanti(false, false); return true; } public function canAddOrRemoveLotti() { $partecipanti = $this->db->go("SELECT codice FROM r_partecipanti_gare WHERE codice_round IN (SELECT codice FROM b_gare_round WHERE codice_gara = :gara)",[":gara"=>$this->info["codice"]]); if(!$this->activeRound || $this->checkLock("lotti") || $partecipanti->rowCount() > 0) return false; $npa = $this->getNpaInstance(); if($npa !== null) return empty($npa->fascicolo["id_appalto"]) && empty($npa->fascicolo["id_pianificazione"]); return true; } public function inviteOE(array $selected, ?int $codice_lotto, ?array $invito_manuale = null, bool $delete = false) { global $pdo; $invitati = []; if (!empty($codice_lotto)) { $this->setLotto($codice_lotto); } $invitatiDB = array_column($this->getInvitati(),"codice_operatore"); if (!empty($selected)) { foreach($selected AS $oe) { if (in_array($oe,$invitatiDB) === false) { if ($this->saveInvito($codice_lotto,$oe,false,true)) { $invitati[] = $oe; if ($this->info["stato"] >= 20) { $this->inviaInvito([$oe]); } } } else { $invitati[] = $oe; } } } if($delete) { $invitatiDB = array_column($this->getInvitati(),"codice_operatore"); $deleteInvito = $pdo->prepare("DELETE FROM r_inviti_gare WHERE codice_round = :codice_round AND codice_lotto = :lotto AND codice_operatore = :operatore "); $deleteInvito->bindValue(":codice_round",$this->round["codice"]); $deleteInvito->bindValue(":lotto",$codice_lotto); $deleteStoricoInvito = $pdo->prepare("DELETE FROM b_inviti WHERE contesto = 'gare' AND codice_elemento = :codice_round AND sub_elemento = :lotto AND codice_fiscale_operatore = :operatore "); $deleteStoricoInvito->bindValue(":codice_round",$this->round["codice"]); $deleteStoricoInvito->bindValue(":lotto",$codice_lotto); foreach($invitatiDB AS $oe) { if (in_array($oe,$invitati) === false) { $deleteInvito->bindValue(":operatore",$oe); $deleteInvito->execute(); $oe = oeManager::getOE($oe); $this->addToLog("DELETE",__("Invito operatore") . ":" . $oe["ragione_sociale"]); ob_start(); $deleteInvito->debugDumpParams(); $dumpParams = ob_get_clean(); scriviLog("r_inviti_gare","DELETE",$dumpParams); if (!empty($oe["codice_fiscale_impresa"])) { $deleteStoricoInvito->bindValue(":operatore",$oe["codice_fiscale_impresa"]); $deleteStoricoInvito->execute(); ob_start(); $deleteStoricoInvito->debugDumpParams(); $dumpParams = ob_get_clean(); scriviLog("b_inviti","DELETE",$dumpParams); } } } if (!empty($invito_manuale)) { $deleteInvito = $pdo->prepare("DELETE FROM temp_inviti WHERE codice = :codice AND contesto = 'gare' AND attivo = 'S' AND codice_elemento = :codice_round AND sub_elemento = :lotto"); $deleteInvito->bindValue(":codice_round",$this->round["codice"]); $deleteInvito->bindValue(":lotto",$codice_lotto); foreach($invito_manuale AS $codice => $codice_fiscale) { $deleteInvito->bindValue(":codice",$codice); $deleteInvito->execute(); ob_start(); $deleteInvito->debugDumpParams(); $dumpParams = ob_get_clean(); scriviLog("temp_inviti","DELETE",$dumpParams); if (!empty($codice_fiscale)) { $deleteStoricoInvito->bindValue(":operatore",$codice_fiscale); $deleteStoricoInvito->execute(); ob_start(); $deleteStoricoInvito->debugDumpParams(); $dumpParams = ob_get_clean(); scriviLog("b_inviti","DELETE",$dumpParams); } } } } } /** * getRda * * @return array */ public function getRda() { if(!empty($this->info)){ global $pdo; $sql = "SELECT b_rda.codice FROM r_gara_rda LEFT JOIN b_rda ON r_gara_rda.codice_rda = b_rda.codice WHERE r_gara_rda.codice_gara = :codice_gara"; return $pdo->go($sql, [':codice_gara' => $this->info['codice']])->fetchAll(PDO::FETCH_COLUMN) ?? []; } } /** * updateStateRda * * @return void */ public function updateStateRda() { if(!empty($this->getRda())){ $statoRda = '0'; if(in_array($this->info['stato'], ['95', '99'] )){ $statoRda = '10'; } if(in_array($this->info['stato'], ['35', '50'])){ $statoRda = '30'; } if(in_array($this->info['stato'], ['90'])){ $statoRda = '90'; } if($statoRda > 0){ $statoRda = StatoRda::getStati(null, $statoRda); if(!empty($statoRda)){ $statoRda = reset($statoRda); foreach ($this->getRda() as $rda) { $rda = Rda::init($rda); $rda->moveStatus($statoRda['codice']); } } } } } }