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

1082 righe
39 KiB

<?php
require_once dirname(__DIR__, 2) . "/inc/traits/api.trait.php";
require_once dirname(__DIR__, 2) . "/inc/traits/deleghe.trait.php";
require_once dirname(__DIR__, 2) . "/inc/traits/npalogger.trait.php";
require_once dirname(__DIR__, 2) . "/inc/traits/render.trait.php";
require_once __DIR__ . "/fvoe.document.class.php";
require_once __DIR__ . "/fvoe.documents.collection.class.php";
class FVOEInizializationType {
const CODICE_FVOE = "codice_fvoe";
const UUID_PARTECIPANTE_E_MODULO = "uuid_partecipante_e_modulo";
const CODICE_LOTTO_E_CODICE_OPERATORE = "codice_lotto_e_codice_operatore";
const UUID_PARTECIPANTE_CF_E_CODICE_LOTTO = "uuid_partecipante_cf_e_codice_lotto";
const CF_E_CODICE_LOTTO = "codice_fiscale_azienda_e_codice_lotto_npa";
}
class FVOE {
use API, Deleghe, NpaLogger, NuovaPiattaformaAppaltiRenderTrait;
/**
* Fascicolo NPA
*
* @var array
*/
public $fascicolo;
/**
* Lotto NPA
*
* @var array
*/
private $lotto;
/**
* Operatore Economico
*
* @var array
*/
private $operatoreEconomico;
/**
* documents
*
* @var array
*/
private $documents;
/**
* Configurazione API
*
* @var mixed
*/
private $api_config;
/**
* Informazioni del fascicolo dell'Operatore Economico
*
* @var array
*/
public $info;
/**
* stati
*
* @var array
*/
public $stati;
/**
* tipologia documenti
*
* @var array
*/
public $tipologia_documenti;
/**
* Definisce quali sezioni sono inibite dall'utente
*/
public $locked_sections = [];
/**
* Definisce quali elementi sono inibiti per l'utente
*
* @var array
*/
public $locked_fields = [];
// Query Statements
private static PDOStatement $stmUUID;
private static PDOStatement $stmOperatore;
private static PDOStatement $stmPartecipanteGareFromUUID;
private static PDOStatement $stmPartecipanteGareFromCodice;
private static PDOStatement $stmFascicolo;
private static PDOStatement $stmLottoFromCodice;
private static PDOStatement $stmLottoFromCodiceRiferimentoAndModulo;
private static PDOStatement $stmUUIDPartecipanteCodiceLotto;
private static PDOStatement $stmFVOE;
private static PDOStatement $stmCFeCodiceLotto;
private static PDOStatement $stmPartecipanteGareFromCodiceFiscale;
private static string $datetimeFormat;
/**
* Formato della data
*
* @var string
*/
private const DATE_FORMAT = "Y-m-d\TH:i:s\Z";
/**
* Query initialization
*
* @var bool
*/
private static bool $queryInitialized = false;
/**
* Class constructor
*
* @return void
*/
private function __construct() {
self::$datetimeFormat = "Y-m-d H:i:s";
$this->stati = jsonToArray(__DIR__ . "/json/stati.json");
$this->tipologia_documenti = jsonToArray(__DIR__ . "/json/tipologia_documenti.json");
$this->api_config = require dirname(__DIR__, 2) . "/inc/configurazione.php";
}
/**
* Query Initialization
*
* @return void
*/
private static function initializeQuery() : void
{
global $pdo;
if (!self::$queryInitialized) {
self::$stmUUID = $pdo->prepare("SELECT * FROM b_fvoe WHERE `uuid_partecipante` = :uuid_partecipante AND stato >= 0 LIMIT 0,1");
self::$stmCFeCodiceLotto = $pdo->prepare("SELECT * FROM b_fvoe WHERE `codice_fiscale` = :codice_fiscale AND `codice_lotto_npa` = :codice_lotto_npa AND stato >= 0 LIMIT 0,1");
self::$stmUUIDPartecipanteCodiceLotto = $pdo->prepare("SELECT * FROM b_fvoe WHERE `uuid_partecipante` = :uuid_partecipante AND `codice_lotto_npa` = :codice_lotto_npa AND stato >= 0 LIMIT 0,1");
self::$stmFVOE = $pdo->prepare("SELECT * FROM b_fvoe WHERE `codice` = :codice_fvoe AND stato >= 0 LIMIT 0,1");
self::$stmOperatore = $pdo->prepare("SELECT * FROM b_fvoe WHERE `codice_lotto_npa` = :codice_lotto_npa AND `codice_operatore` = :codice_operatore AND stato >= 0 LIMIT 0,1");
self::$stmPartecipanteGareFromUUID = $pdo->prepare("SELECT * FROM r_partecipanti_gare WHERE `uuid` = :uuid_partecipante LIMIT 0,1");
self::$stmPartecipanteGareFromCodice = $pdo->prepare("SELECT * FROM r_partecipanti_gare WHERE `codice` = :codice LIMIT 0,1");
self::$stmPartecipanteGareFromCodiceFiscale = $pdo->prepare("SELECT * FROM r_partecipanti_gare WHERE `codice_fiscale` = :codice_fiscale AND `codice_lotto` = :codice_lotto LIMIT 0,1");
self::$stmFascicolo = $pdo->prepare("SELECT * FROM b_npa WHERE `codice` = :codice_npa LIMIT 0,1");
self::$stmLottoFromCodice = $pdo->prepare("SELECT `b_npa_lotti`.* FROM `b_npa_lotti` LEFT JOIN `b_npa` ON `b_npa`.`codice` = `b_npa_lotti`.`codice_npa` WHERE `b_npa_lotti`.`codice` = :codice_lotto_npa AND `b_npa`.`id_riferimento` > 0 LIMIT 0,1");
self::$stmLottoFromCodiceRiferimentoAndModulo = $pdo->prepare("SELECT `b_npa_lotti`.* FROM `b_npa_lotti` LEFT JOIN `b_npa` ON `b_npa`.`codice` = `b_npa_lotti`.`codice_npa` WHERE `b_npa_lotti`.`lotto_riferimento` = :lotto_riferimento AND `b_npa`.`modulo_riferimento` = :modulo_riferimento AND `id_riferimento` > 0 LIMIT 0,1");
self::$queryInitialized = true;
}
}
/**
* Class initialization
*
* @param mixed $reference
* @param int $type
* @return FVOE
*/
public static function init($reference, string $type): FVOE
{
self::initializeQuery();
$fvoe = new self();
switch ($type) {
case FVOEInizializationType::CODICE_FVOE:
// Verifico che in $reference ci sia un numero
if (! is_numeric($reference) || $reference <= 0) {
throw new InvalidArgumentException("Il riferimento deve essere un numero >= 0 (int) codice_fvoe.");
}
self::$stmFVOE->execute([':codice_fvoe' => $reference]);
$fvoe->info = self::$stmFVOE->fetch(PDO::FETCH_ASSOC);
if(empty($fvoe->info["codice"])) {
throw new InvalidArgumentException("FVOE non trovato.");
}
break;
case FVOEInizializationType::CF_E_CODICE_LOTTO:
// Verifico che in $reference ci siano i valori di cf e codice_lotto_npa
if (! is_array($reference) || count($reference) != 2) {
throw new InvalidArgumentException("Il riferimento deve essere un array [cf, codice_lotto_npa].");
}
list($cf, $codice_lotto_npa) = $reference;
self::$stmCFeCodiceLotto->execute([":codice_fiscale" => $cf, ":codice_lotto_npa" => $codice_lotto_npa]);
$fvoe->info = self::$stmCFeCodiceLotto->fetch(PDO::FETCH_ASSOC);
// Se si tratta di un nuovo fascicolo dell'operatore economico
if(empty($fvoe->info["codice"])) {
$fvoe->info = get_campi("b_fvoe");
$fvoe->info["stato"] = 0;
$fvoe->info["codice_fiscale"] = $cf;
$fvoe->info["codice_lotto_npa"] = $codice_lotto_npa;
}
break;
case FVOEInizializationType::UUID_PARTECIPANTE_E_MODULO:
// Verifico che in $reference ci siano i valori di uuid_partecipante e modulo_riferimento
if (! is_array($reference) || count($reference) != 2) {
throw new InvalidArgumentException("Il riferimento deve essere un array [uuid_partecipante, modulo_riferimento].");
}
list($uuid_partecipante, $modulo_riferimento) = $reference;
if(! in_array($modulo_riferimento, ["gare"])) {
throw new InvalidArgumentException("Il valore di modulo_riferimento non è valido.");
}
// Recupero le informazioni del fascicolo attraverso il codice uuid univoco del partecipante
self::$stmUUID->execute([':uuid_partecipante' => $uuid_partecipante]);
$fvoe->info = self::$stmUUID->fetch(PDO::FETCH_ASSOC);
// Se si tratta di un nuovo fascicolo dell'operatore economico
if(empty($fvoe->info["codice"])) {
$fvoe->info = get_campi("b_fvoe");
$fvoe->info["stato"] = 0;
$fvoe->info["modulo"] = $modulo_riferimento;
$fvoe->info["uuid_partecipante"] = $uuid_partecipante;
if($fvoe->info["modulo"] == "gare") {
// Se il modulo di riferimento è gare recupero il partecipante con il suo codice uuid da r_partecipanti_gare
self::$stmPartecipanteGareFromUUID->execute([":uuid_partecipante" => $fvoe->info["uuid_partecipante"]]);
$fvoe->operatoreEconomico = self::$stmPartecipanteGareFromUUID->fetch(PDO::FETCH_ASSOC);
if(! empty($fvoe->operatoreEconomico["codice_lotto"])) {
// Imposto i dati utili nel fascicolo dell'operatore economico
$fvoe->info["codice_operatore"] = $fvoe->operatoreEconomico["codice"];
$fvoe->info["codice_fiscale"] = $fvoe->operatoreEconomico["codice_fiscale"];
// Recupero il lotto di riferimento da b_npa_lotti utilizzando il lotto di partecipazione della r_partecipanti_gare
self::$stmLottoFromCodiceRiferimentoAndModulo->execute([":lotto_riferimento" => $fvoe->operatoreEconomico["codice_lotto"], ":modulo_riferimento" => $fvoe->info["modulo"]]);
$fvoe->lotto = self::$stmLottoFromCodiceRiferimentoAndModulo->fetch(PDO::FETCH_ASSOC);
if(! empty($fvoe->lotto["codice"])) {
// Imposto il codice del lotto per poter recuperare dopo le info del fascicolo npa
$fvoe->info["codice_lotto_npa"] = $fvoe->lotto["codice"];
}
}
}
}
break;
case FVOEInizializationType::CODICE_LOTTO_E_CODICE_OPERATORE:
if (! is_array($reference) || count($reference) != 2) {
throw new InvalidArgumentException("Il riferimento deve essere un array [codice_lotto_npa, codice_operatore].");
}
list($codice_lotto_npa, $codice_operatore) = $reference;
self::$stmOperatore->execute([':codice_lotto_npa' => $codice_lotto_npa, ':codice_operatore' => $codice_operatore]);
$fvoe->info = self::$stmOperatore->fetch(PDO::FETCH_ASSOC);
// Se si tratta di un nuovo fascicolo dell'operatore economico
if(empty($fvoe->info["codice"])) {
$fvoe->info = get_campi("b_fvoe");
$fvoe->info["stato"] = 0;
// Se disponibile, imposto il codice lotto
if(! empty($codice_lotto_npa)) {
$fvoe->info["codice_lotto_npa"] = $codice_lotto_npa;
}
// Se disponibile, imposto il codice dell'operatore economico
if(! empty($codice_operatore)) {
$fvoe->info["codice_operatore"] = $codice_operatore;
}
}
break;
case FVOEInizializationType::UUID_PARTECIPANTE_CF_E_CODICE_LOTTO:
// Verifico che in $reference ci siano i valori di uuid_partecipante e codice_lotto_npa
if (! is_array($reference) || count($reference) != 3) {
throw new InvalidArgumentException("Il riferimento deve essere un array [uuid_partecipante, cf, codice_lotto_npa].");
}
if(! preg_match('/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/', $reference[0])) {
throw new InvalidArgumentException("Il riferimento uuid_partecipante deve essere uno uuid valido.");
}
list($uuid_partecipante, $cf, $codice_lotto_npa) = $reference;
self::$stmUUIDPartecipanteCodiceLotto->execute([':uuid_partecipante' => $uuid_partecipante, ':codice_lotto_npa' => $codice_lotto_npa]);
$fvoe->info = self::$stmUUIDPartecipanteCodiceLotto->fetch(PDO::FETCH_ASSOC);
// Se si tratta di un nuovo fascicolo dell'operatore economico
if(empty($fvoe->info["codice"])) {
$fvoe->info = get_campi("b_fvoe");
$fvoe->info["stato"] = 0;
$fvoe->info["codice_lotto_npa"] = $codice_lotto_npa;
$fvoe->info["uuid_partecipante"] = $uuid_partecipante;
}
$fvoe->info["codice_fiscale"] = $cf;
break;
default:
throw new InvalidArgumentException("Tipologia di riferimento non valida.");
break;
}
// Recupero le informazioni del lotto
if(! empty($fvoe->info["codice_lotto_npa"]) && empty($fvoe->lotto)) {
self::$stmLottoFromCodice->execute([":codice_lotto_npa" => $fvoe->info["codice_lotto_npa"]]);
$fvoe->lotto = self::$stmLottoFromCodice->fetch(PDO::FETCH_ASSOC);
}
// Imposto il codice del fascicolo npa (se si tratta di un nuovo fascicolo dell'operatore economico)
if(empty($fvoe->info["codice_npa"]) && ! empty($fvoe->lotto["codice_npa"])) {
$fvoe->info["codice_npa"] = $fvoe->lotto["codice_npa"];
}
// Recupero le informazioni del fascicolo npa
if(! empty($fvoe->info["codice_npa"])) {
self::$stmFascicolo->execute([":codice_npa" => $fvoe->info["codice_npa"]]);
$fvoe->fascicolo = self::$stmFascicolo->fetch(PDO::FETCH_ASSOC);
}
// Imposto il modulo (se si tratta di un nuovo fascicolo dell'operatore economico)
if(empty($fvoe->info["modulo"]) && ! empty($fvoe->fascicolo["modulo_riferimento"])) {
$fvoe->info["modulo"] = $fvoe->fascicolo["modulo_riferimento"];
}
//
//
//
//
//
// if($fvoe->info["modulo"] == "gare") {
// // Se il modulo di riferimento è gare recupero il partecipante con il suo codice fiscale da r_partecipanti_gare
// static::$stmPartecipanteGareFromCodiceFiscale->execute([":codice_fiscale" => $fvoe->info["codice_fiscale", ":codice_lotto" => ""]]);
// $fvoe->operatoreEconomico = self::$stmPartecipanteGareFromCodiceFiscale->fetch(PDO::FETCH_ASSOC);
// if(! empty($fvoe->operatoreEconomico["codice_lotto"])) {
// // Imposto i dati utili nel fascicolo dell'operatore economico
// $fvoe->info["codice_operatore"] = $fvoe->operatoreEconomico["codice"];
// $fvoe->info["codice_fiscale"] = $fvoe->operatoreEconomico["codice_fiscale"];
// // Recupero il lotto di riferimento da b_npa_lotti utilizzando il lotto di partecipazione della r_partecipanti_gare
// self::$stmLottoFromCodiceRiferimentoAndModulo->execute([":lotto_riferimento" => $fvoe->operatoreEconomico["codice_lotto"], ":modulo_riferimento" => $fvoe->info["modulo"]]);
// $fvoe->lotto = self::$stmLottoFromCodiceRiferimentoAndModulo->fetch(PDO::FETCH_ASSOC);
// if(! empty($fvoe->lotto["codice"])) {
// // Imposto il codice del lotto per poter recuperare dopo le info del fascicolo npa
// $fvoe->info["codice_lotto_npa"] = $fvoe->lotto["codice"];
// }
// }
// }
//
//
//
//
//
$fvoe->operatoreEconomico = get_campi("r_partecipanti_gare");
$fvoe->operatoreEconomico["codice_lotto"] = $fvoe->lotto["lotto_riferimento"] ?? null;
$fvoe->operatoreEconomico["codice_fiscale"] = $fvoe->info["codice_fiscale"];
// Recupero le informazioni del partecipante
if(! empty($fvoe->info["modulo"]) && $fvoe->info["modulo"] == "gare") {
if(! empty($fvoe->lotto["lotto_riferimento"]) && ! empty($fvoe->info["codice_fiscale"])) {
static::$stmPartecipanteGareFromCodiceFiscale->execute([":codice_fiscale" => $fvoe->info["codice_fiscale"], ":codice_lotto" => $fvoe->lotto["lotto_riferimento"]]);
if(static::$stmPartecipanteGareFromCodiceFiscale->rowCount() == 1) {
$fvoe->operatoreEconomico = self::$stmPartecipanteGareFromCodiceFiscale->fetch(PDO::FETCH_ASSOC);
}
}
if(empty($fvoe->operatoreEconomico["codice"]) && ! empty($fvoe->info["codice_operatore"])) {
self::$stmPartecipanteGareFromCodice->execute([":codice" => $fvoe->info["codice_operatore"]]);
if(self::$stmPartecipanteGareFromCodice->rowCount() == 1) {
$fvoe->operatoreEconomico = self::$stmPartecipanteGareFromCodice->fetch(PDO::FETCH_ASSOC);
}
}
if(empty($fvoe->operatoreEconomico["codice"]) && ! empty($fvoe->info["uuid_partecipante"])) {
self::$stmPartecipanteGareFromUUID->execute([":uuid_partecipante" => $fvoe->info["uuid_partecipante"]]);
if(self::$stmPartecipanteGareFromUUID->rowCount() == 1) {
$fvoe->operatoreEconomico = self::$stmPartecipanteGareFromUUID->fetch(PDO::FETCH_ASSOC);
}
}
}
if(! empty($fvoe->operatoreEconomico["codice"])) {
// Imposto i dati utili nel fascicolo dell'operatore economico
$fvoe->info["codice_operatore"] = $fvoe->operatoreEconomico["codice"];
$fvoe->info["codice_fiscale"] = $fvoe->operatoreEconomico["codice_fiscale"];
if(empty($fvoe->lotto["codice"])) {
// Recupero il lotto di riferimento da b_npa_lotti utilizzando il lotto di partecipazione della r_partecipanti_gare
self::$stmLottoFromCodiceRiferimentoAndModulo->execute([":lotto_riferimento" => $fvoe->operatoreEconomico["codice_lotto"], ":modulo_riferimento" => $fvoe->info["modulo"]]);
$fvoe->lotto = self::$stmLottoFromCodiceRiferimentoAndModulo->fetch(PDO::FETCH_ASSOC);
}
// Imposto il codice del lotto per poter recuperare dopo le info del fascicolo npa
$fvoe->info["codice_lotto_npa"] = $fvoe->lotto["codice"];
}
return $fvoe;
}
/**
* Verifica se l'utente corrente può accedere al Fascicolo dell'OE
*
* @return bool
*/
public function isAccessible() : bool {
if(! empty($_SESSION["utente"]) && $_SESSION["utente"]->authenticationLevel >= 2) {
$utente = $_SESSION["utente"]->getInfo()["cf"];
if(! empty($this->fascicolo["codice"])) {
$npa = NuovaPiattaformaAppalti::init($this->fascicolo["codice"]);
$cfs = $npa->getUserFromRole(DelegheRoles::ANY, RoleSyncBehaviour::NEVER_SYNC);
if(in_array($utente, $cfs)) {
return true;
}
}
}
return false;
}
/**
* Richiesta di accesso al FVOE
*
* @param \DateTime $end
* @param mixed $message
* @return bool
*/
public function requestAccess(?\DateTime $authorizationEndDate = null, ?string &$message = "") : bool
{
if (! $this->getServiceStatusBool(true)) {
$message = __("Impossibile completare la richiesta: i server ANAC non sono raggiungibili. Riprova tra qualche minuto.");
return false;
}
if (! NuovaPiattaformaAppalti::hasLockOnPartecipantiStatic($this->fascicolo["codice"])) {
$message = __("Impossibile completare la richiesta: E' necessario trasmettere le schede partecipanti.");
return false;
}
if(empty($this->lotto["codice"])) {
$message = __("Impossibile completare la richiesta: E' necessario selezionare un lotto.");
return false;
}
// Popoliamo message con qualcosa di generico
$message = __("Errore interno sconosciuto");
$operazione = new Salva();
$operazione->debug = false;
$operazione->nome_tabella = "b_npa_operazioni_schede";
$operazione->operazione = "INSERT";
$operazione->expect = ["codice_partecipante", "codice_lotto", "operazione"];
$operazione->oggetto = [
"codice_partecipante" => $this->operatoreEconomico["uuid"],
"codice_lotto" => $this->lotto["codice"],
"operazione" => "ACCESSO-FVOE"
];
$fvoe = new Salva();
$fvoe->debug = false;
$fvoe->nome_tabella = "b_fvoe";
$fvoe->operazione = "INSERT";
$fvoe->expect = ["codice_npa", "codice_lotto_npa", "codice_partecipante", "codice_operatore", "codice_fiscale", "uuid_partecipante", "stato", "modulo", "utente_modifica"];
$fvoe->oggetto = &$this->info;
date_default_timezone_set('Europe/Rome');
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]);
// Andiamo a verificare che ci sia un'operazione di richiesta accesso in attesa
$richiesta_accesso = NuovaPiattaformaAppalti::fetchLastOperation(null, "ACCESSO-FVOE", null, false, $this->info["codice_lotto_npa"], $this->info["uuid_partecipante"]);
// Se c'è
if (! empty($richiesta_accesso)) {
// Popoliamo il messaggio di errore
$message = __("Errore durante la verifica dello stato di accesso al fascicolo");
$fvoe->operazione = "UPDATE";
$fvoe->expect = ["codice", "stato", "data_inizio", "data_fine", "id_richiesta_accesso", "chiave_accesso"];
$operazione->operazione = "UPDATE";
$operazione->expect = ["codice", "esito", "risultato"];
$operazione->oggetto = $richiesta_accesso;
// Andiamo a chiedere al server lo stato della richiesta di accesso
$request = [
"codiceFiscale" => $this->operatoreEconomico["codice_fiscale"],
"idAppalto" => $this->fascicolo["id_appalto"]
];
$apiMessage = "";
$result_str = $this->apiCall("fvoe", "check-access-request", $request, $claims, [], $apiMessage);
if (is_json($result_str)) {
$message = __("Impossibile verificare l'esito dell'operazione. Contatta l'Help Desk tecnico.");
$result = json_decode($result_str);
$operazione->oggetto["risultato"] = serialize($result);
$operazione->oggetto["esito"] = "KO";
if ($result->status == 200 && ! empty($result->autorizzazione)) {
if(empty($result->autorizzazione->chiaveAccesso)) {
$message = "INFO - Attendi che l'operatore economico conceda l'accesso al fascicolo";
return false;
}
global $config;
$message = null;
$this->info["stato"] = 20;
$this->info["data_inizio"] = date('d/m/Y H:i:s', strtotime($result->autorizzazione->dataInizio));
$this->info["data_fine"] = date('d/m/Y H:i:s', strtotime($result->autorizzazione->dataFine));
$this->info["id_richiesta_accesso"] = $result->autorizzazione->richiestaAccesso->idRichiesta;
$this->info["chiave_accesso"] = $result->autorizzazione->chiaveAccesso;
$this->info["chiave_accesso"] = simple_encrypt($this->info["chiave_accesso"], $config["simple_encrypt"]["chiave_fvoe"]);
$fvoe->save();
$operazione->oggetto["esito"] = "OK";
$operazione->save();
return true;
}
$operazione->save();
return false;
}
return false;
}
$dataFineAutorizzazione = date(self::DATE_FORMAT, strtotime('2099/12/31'));
if ($authorizationEndDate instanceof DateTime) { $dataFineAutorizzazione = $authorizationEndDate->format(self::DATE_FORMAT); }
// Creiamo la richiesta di accesso al Fascicolo
$request = [
"dataInizioAutorizzazione" => date(self::DATE_FORMAT, strtotime('now')),
"dataFineAutorizzazione" => $dataFineAutorizzazione,
"operatoriEconomici" => [
[
"codiceFiscale" => $this->operatoreEconomico["codice_fiscale"]
]
],
"appalto" => [
"idAppalto" => $this->fascicolo["id_appalto"],
"lotti" => [
[
"cig" => $this->lotto["cig"]
]
]
]
];
// Effettuiamo la richiesta
$apiMessage = "";
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]);
$result_str = $this->apiCall("fvoe", "submit-access-request", $request, $claims, [], $apiMessage);
$result = self::manageANACResponse($result_str, $message);
if($result === null) {
$message = empty($apiMessage) ? $message : $apiMessage;
return false;
}
$message = __("Errore in fase di invio della richiesta.");
// Verifichiamo la risposta
// Se non ci viene fornita una risposta con successo
if ($result->status !== 200) {
// Aggiorniamo lo status
$operazione->expect[] = "esito";
$operazione->expect[] = "risultato";
$operazione->oggetto["esito"] = "KO";
$operazione->oggetto["risultato"] = serialize($result);
$operazione->save();
$message = __("Errore in fase di richiesta accesso FVOE.");
if(! empty($result->errori)) {
$dictionary = NuovaPiattaformaAppalti::getErrorsDictionary();
foreach ($result->errori as $errore) {
$errorInfo = $dictionary[$errore->codice ?? null] ?? [];
if(! empty($errorInfo["descrizione"]["it"]) && $errorInfo["codice"]) {
$message = "{$errorInfo["codice"]} {$errorInfo["descrizione"]["it"]}";
}
}
} elseif(! empty($result->title)) {
$message = "{$message} {$result->title}";
}
$this->info["stato"] = 0;
$this->info["modulo"] = $this->fascicolo["modulo_riferimento"];
$fvoe->expect[] = "errori";
$this->info["errori"] = serialize($result->errori ?? $result);
if(! empty($this->info["codice"])) {
$fvoe->operazione = "UPDATE";
$fvoe->expect[] = "codice";
}
$fvoe->save();
return false;
}
// Conferma andata con successo
$operazione->expect[] = "id_richiesta";
$fvoe->expect[] = "errori";
$operazione->oggetto["id_richiesta"] = $result->idRichiesta;
$this->info["stato"] = 10;
$this->info["modulo"] = $this->fascicolo["modulo_riferimento"];
$this->info["errori"] = "";
if(! empty($this->info["codice"])) {
$fvoe->operazione = "UPDATE";
$fvoe->expect[] = "codice";
}
if ($operazione->save() && $fvoe->save()) {
$message = "";
return true;
}
return false;
}
/**
* Recupera il documento per la specifica tipologia dal database
*
* @param mixed $tipologia
* @param mixed $cached
* @return FVOEDocumentsCollection
*/
public function fetchDocumentsByType(string $tipologia, bool $cached = true) : FVOEDocumentsCollection {
if(! isset($this->documents[$tipologia]) || ! $cached) {
$this->documents[$tipologia] = new FVOEDocumentsCollection($this->info["codice"], $tipologia);
}
return $this->documents[$tipologia];
}
/**
* Ottieni la lista dei documenti disponibili nel fascicolo dell'operatore economico
*
* @param mixed $filters
* @param mixed $page
* @param mixed $message
* @return bool
*/
public function updateDocuments(?array $filters = [], ?string &$message = "") : bool
{
global $config;
if(! empty($_SESSION["fvoe-sync"][$this->info["id_richiesta_accesso"]])) {
return true;
}
// Prevalorizziamo $message
$message = __("Errore interno sconosciuto");
// Verifichiamo che i servizi siano disponibili
if (! $this->getServiceStatusBool(true)) {
$message = __("Impossibile completare la richiesta: i server ANAC non sono raggiungibili. Riprova tra qualche minuto.");
return false;
}
// Creiamo la richiesta di accesso al Fascicolo
$request = ["chiaveAccesso" => simple_decrypt($this->info["chiave_accesso"], $config["simple_encrypt"]["chiave_fvoe"])];
// Organizzo i filtri
if(! empty($filters)) {
$allowedKeys = [
"dataCreazioneA",
"dataCreazioneDa",
"dataEmissioneA",
"dataEmissioneDa",
"dataFineValiditaA",
"dataFineValiditaDa",
"dataInserimentoA",
"dataInserimentoDa",
"dataProtocolloA",
"dataProtocolloDa",
"datiAggiuntivi",
"numeroProtocollo",
"page",
"perPage",
"stato",
"tipo",
];
// Se ci sono date valide le trasformo nel formato ISO 8601 as profiled by RFC 3339
array_walk($filters, function(&$value, $key) {
if(strpos($key, "data") !== false && ! empty($value)) {
$value = strtotime($value);
$value = $value !== false ? gmdate(self::DATE_FORMAT, $value) : null;
}
});
// Rimuovo gli elementi nulli o non consentiti
$filters = array_filter($filters, function($value, $key) use ($allowedKeys, &$filters) {
return $value !== null && in_array($key, $allowedKeys);
}, ARRAY_FILTER_USE_BOTH);
// Imposto i filtri nella richiesta
$request += $filters;
}
$page = $pages = 1;
do {
$request["page"] = $page;
// Effettuiamo la richiesta
$apiMessage = "";
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]);
$result_str = $this->apiCall("fvoe", "search-documents", $request, $claims, [], $apiMessage);
$result = self::manageANACResponse($result_str, $message);
if($result === null) {
$message = empty($apiMessage) ? $message : $apiMessage;
return false;
}
// Verifichiamo la risposta
// Se non ci viene fornita una risposta con successo
if ($result->status !== 200) {
// Verificare la risposta
$list = [];
if(! empty($result->title)) {
$list[] = "{$message} {$result->title}";
}
if(! empty($result->errori)) {
$dictionary = NuovaPiattaformaAppalti::getErrorsDictionary();
foreach ($result->errori as $errore) {
$errorInfo = $dictionary[$errore->codice ?? null] ?? [];
if(! empty($errorInfo["descrizione"]["it"]) && $errorInfo["codice"]) {
$list[] = "<strong>{$errorInfo["codice"]}</strong> - {$errorInfo["descrizione"]["it"]}";
}
}
}
if(! empty($list)) {
$list = implode("</li><li class='list-group-item bg-transparent'>", $list);
$message = "<strong>Attenzione</strong> si sono verificati i seguenti errori:<ul class='list-group'><li class='list-group-item bg-transparent'>{$list}</li></ul>";
}
return false;
}
global $pdo;
$stm = $pdo->prepare(<<<SQL
INSERT INTO b_fvoe_documenti (codice_fvoe, id_documento, tipo_documento, oggetto, data_creazione, stato_comprova, stato_utilizzo, data_inserimento, data_emissione, data_fine_validita, numero_protocollo, utente_modifica)
VALUES (:codice_fvoe, :id_documento, :tipo_documento, :oggetto, :data_creazione, :stato_comprova, :stato_utilizzo, :data_inserimento, :data_emissione, :data_fine_validita, :numero_protocollo, :utente_modifica)
ON DUPLICATE KEY UPDATE
data_creazione = :data_creazione,
stato_comprova = :stato_comprova,
stato_utilizzo = :stato_utilizzo,
data_inserimento = :data_inserimento,
data_emissione = :data_emissione,
data_fine_validita = :data_fine_validita,
numero_protocollo = :numero_protocollo,
utente_modifica = :utente_modifica
SQL);
$stm->bindValue(":codice_fvoe", $this->info["codice"]);
$stm->bindValue(":utente_modifica", $_SESSION["utente"]->codice);
// Conferma andata con successo
$pages = $result->totPages;
foreach ($result->result as $document) {
// Recuperiamo le informazioni
$info = $this->getDocument($document->idDocumento);
if(! empty($info->documento->idDocumento)) {
if(! empty($info->documento->idDocumento)) { $stm->bindValue(":id_documento", $info->documento->idDocumento); } else { $stm->bindValue(":id_documento", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->tipo)) { $stm->bindValue(":tipo_documento", $info->documento->tipo->codice); } else { $stm->bindValue(":tipo_documento", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->oggetto)) { $stm->bindValue(":oggetto", $info->documento->oggetto); } else { $stm->bindValue(":oggetto", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->dataCreazione)) { $stm->bindValue(":data_creazione", date(self::$datetimeFormat, strtotime($info->documento->dataCreazione))); } else { $stm->bindValue(":data_creazione", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->statoComprova)) { $stm->bindValue(":stato_comprova", $info->documento->statoComprova->codice); } else { $stm->bindValue(":stato_comprova", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->statoUtilizzo)) { $stm->bindValue(":stato_utilizzo", $info->documento->statoUtilizzo->codice); } else { $stm->bindValue(":stato_utilizzo", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->dataInserimento)) { $stm->bindValue(":data_inserimento", date(self::$datetimeFormat, strtotime($info->documento->dataInserimento))); } else { $stm->bindValue(":data_inserimento", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->dataEmissione)) { $stm->bindValue(":data_emissione", date(self::$datetimeFormat, strtotime($info->documento->dataEmissione))); } else { $stm->bindValue(":data_emissione", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->dataFineValidita)) { $stm->bindValue(":data_fine_validita", date(self::$datetimeFormat, strtotime($info->documento->dataFineValidita))); } else { $stm->bindValue(":data_fine_validita", NULL, PDO::PARAM_NULL); }
if(! empty($info->documento->numeroProtocollo)) { $stm->bindValue(":numero_protocollo", $info->documento->numeroProtocollo); } else { $stm->bindValue(":numero_protocollo", NULL, PDO::PARAM_NULL); }
$stm->execute();
}
}
$page++;
} while ($page <= $pages);
$_SESSION["fvoe-sync"][$this->info["id_richiesta_accesso"]] = true;
$message = "";
return true;
}
/**
* Ottiene il documento dal fascicolo dell'operatore economico di ANAC
*
* @param mixed $filters
* @param mixed $page
* @param mixed $message
* @return object
*/
public function getDocument(string $idDocumento, ?string &$message = "") : ?object
{
global $config;
// Prevalorizziamo $message
$message = __("Errore interno sconosciuto");
// Verifichiamo che i servizi siano disponibili
if (! $this->getServiceStatusBool(true)) {
$message = __("Impossibile completare la richiesta: i server ANAC non sono raggiungibili. Riprova tra qualche minuto.");
return null;
}
// Creiamo la richiesta per l'ottenimento del documento
$request = [
"chiaveAccesso" => simple_decrypt($this->info["chiave_accesso"], $config["simple_encrypt"]["chiave_fvoe"]),
"idDocumento" => $idDocumento
];
// Effettuiamo la richiesta
$apiMessage = "";
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]);
$result_str = $this->apiCall("fvoe", "get-document", $request, $claims, [], $apiMessage);
$result = self::manageANACResponse($result_str, $message);
if($result === null) {
$message = empty($apiMessage) ? $message : $apiMessage;
return false;
}
// Verifichiamo la risposta
// Se non ci viene fornita una risposta con successo
if ($result->status !== 200) {
// Verificare la risposta
if(! empty($result->errori)) {
$dictionary = NuovaPiattaformaAppalti::getErrorsDictionary();
foreach ($result->errori as $errore) {
$errorInfo = $dictionary[$errore->codice ?? null] ?? [];
if(! empty($errorInfo["descrizione"]["it"]) && $errorInfo["codice"]) {
$message = "{$errorInfo["codice"]} - {$errorInfo["descrizione"]["it"]}";
}
}
} elseif(! empty($result->title)) {
$message = "{$message} {$result->title}";
}
return null;
}
// Conferma andata con successo
$message = "";
return $result;
}
/**
* Ottieni l'anagrafica dell'operatore economico
*
* @param string $message
* @return ?array
*/
public function getInfoOperatoreEconomico(?string &$message = "") : ?array
{
global $config;
// Prevalorizziamo $message
$message = __("Errore interno sconosciuto");
// Verifichiamo che i servizi siano disponibili
if (! $this->getServiceStatusBool(true)) {
$message = __("Impossibile completare la richiesta: i server ANAC non sono raggiungibili. Riprova tra qualche minuto.");
return null;
}
// Creiamo la richiesta di accesso al Fascicolo
$request = ["codiceFiscale" => $this->info["codice_fiscale"]];
// Effettuiamo la richiesta
$apiMessage = "";
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]);
$result_str = $this->apiCall("fvoe", "get-oe-data", $request, $claims, [], $apiMessage);
$result = self::manageANACResponse($result_str, $message);
if($result === null) {
$message = empty($apiMessage) ? $message : $apiMessage;
return false;
}
$message = __("Errore in fase di invio della richiesta.");
dump($result);
// Verifichiamo la risposta
// Se non ci viene fornita una risposta con successo
if ($result->status !== 200) {
// Verificare la risposta
if(! empty($result->errori)) {
$dictionary = NuovaPiattaformaAppalti::getErrorsDictionary();
foreach ($result->errori as $errore) {
$errorInfo = $dictionary[$errore->codice ?? null] ?? [];
if(! empty($errorInfo["descrizione"]["it"]) && $errorInfo["codice"]) {
$message = "{$errorInfo["codice"]} {$errorInfo["descrizione"]["it"]}";
}
}
} elseif(! empty($result->title)) {
$message = "{$message} {$result->title}";
}
return null;
}
// Conferma andata con successo
$message = "";
return null;
}
/**
* Get the value of fascicolo
*
* @return array
*/
public function getFascicolo(): array {
return $this->fascicolo;
}
/**
* Get the value of lotto
*
* @return array
*/
public function getLotto(): array {
return $this->lotto;
}
/**
* Get the value of operatoreEconomico
*
* @return array
*/
public function getOperatoreEconomico(): array {
return $this->operatoreEconomico;
}
/**
* Fetch last operation
*
* @param mixed $codice_documento
* @param mixed $codice_partecipante
* @param mixed $codice_lotto
* @param mixed $operazione
* @param mixed $esito
* @param mixed $multiple
* @return array
*/
public static function fetchLastOperation(?int $codice_documento = null, ?string $codice_partecipante = null, ?int $codice_lotto = null, ?string $operazione = "", $esito = null, ?bool $multiple = false) : ?array
{
global $pdo;
$bind = $where = [];
$where["codice_documento"] = "(codice_documento IS NULL OR codice_documento = '')";
if(! empty($codice_documento)) {
$where["codice_documento"] = "codice_documento = :codice_documento";
$bind[":codice_documento"] = $codice_documento;
}
if(! empty($codice_partecipante)) {
$where["codice_partecipante"] = "codice_partecipante = :codice_partecipante";
$bind[":codice_partecipante"] = $codice_partecipante;
}
if(! empty($codice_lotto)) {
$where["codice_lotto"] = "codice_lotto = :codice_lotto";
$bind[":codice_lotto"] = $codice_lotto;
}
if(! empty($operazione)) {
$where["operazione"] = "operazione = :operazione";
$bind[":operazione"] = $operazione;
}
$where["esito"] = "(esito IS NULL OR esito = '' OR esito = 0)";
if((! empty($esito)) && in_array($esito, ['OK', 'KO'])) {
$where["esito"] = "esito = :esito";
$bind[":esito"] = $esito;
} elseif ($esito === false) {
unset($where["esito"], $bind[":esito"]);
}
$where = implode(" AND ", $where);
$sql = "SELECT * FROM b_fvoe_operazioni WHERE ({$where}) ORDER BY `timestamp` DESC";
if(!$multiple) { $sql = "{$sql} LIMIT 0,1"; }
$result = $pdo->go($sql, $bind);
if ($result->rowCount() > 0) {
$operations = $result->fetchAll(PDO::FETCH_ASSOC);
return $multiple ? $operations : $operations[0];
}
return null;
}
}