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.
881 righe
32 KiB
881 righe
32 KiB
<?php |
|
|
|
use GPBMetadata\Google\Type\Datetime; |
|
use Symfony\Component\Routing\Exception\InvalidParameterException; |
|
|
|
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"; |
|
|
|
class FVOEDocument { |
|
|
|
use API, Deleghe, NpaLogger, NuovaPiattaformaAppaltiRenderTrait; |
|
|
|
public $codice; |
|
public $codice_fvoe; |
|
public $id_documento; |
|
public $tipo_documento; |
|
public $oggetto; |
|
public $stato; |
|
public $data_creazione; |
|
public $stato_comprova; |
|
public $stato_utilizzo; |
|
public $stato_richiesta; |
|
public $data_inserimento; |
|
public $data_emissione; |
|
public $data_fine_validita; |
|
public $numero_protocollo; |
|
public $utente_modifica; |
|
public $timestamp_creazione; |
|
public $timestamp; |
|
|
|
private FVOE $fvoe; |
|
private array $fascicolo; |
|
private static PDOStatement $stm; |
|
private static PDOStatement $stmDocumento; |
|
private static PDOStatement $stmRequestData; |
|
private static PDOStatement $stmPendingDocument; |
|
private static stdClass $utilizzo; |
|
private static stdClass $stati_richiesta; |
|
private static stdClass $comprova; |
|
private static stdClass $stati; |
|
private static array $tipologia_documenti; |
|
private static string $path_modelli_dati_aggiuntivi; |
|
|
|
/** |
|
* Query initialization |
|
* |
|
* @var bool |
|
*/ |
|
private static bool $queryInitialized = false; |
|
|
|
/** |
|
* Contiene la configurazione corrente delle API |
|
* |
|
* @var array |
|
*/ |
|
private $api_config = []; |
|
|
|
public const STATI = [ |
|
|
|
0 => [ |
|
"id" => 0, |
|
"color" => "var(--danger)", |
|
"icon" => "fas fa-times-circle", |
|
"title" => "Documento non disponibile" |
|
], |
|
|
|
1 => [ |
|
"id" => 1, |
|
"color" => "var(--primary)", |
|
"icon" => "fas fa-check-circle", |
|
"title" => "Documento disponibile" |
|
], |
|
|
|
2 => [ |
|
"id" => 2, |
|
"color" => "var(--warning)", |
|
"icon" => "fas fa-check-circle", |
|
"title" => "Documento scaduto" |
|
] |
|
|
|
]; |
|
|
|
/** |
|
* Getter |
|
* |
|
* @param mixed $name |
|
* @return void |
|
*/ |
|
public function __get($name) |
|
{ |
|
if ($name === 'info') { |
|
return get_object_vars($this); |
|
} |
|
|
|
if ($name === 'scheda' || $name == 'form') { |
|
return null; |
|
} |
|
|
|
// Se la proprietà richiesta non è 'info', gestisci come errore o restituisci null |
|
trigger_error("Proprietà non definita: {$name}", E_USER_NOTICE); |
|
return null; |
|
} |
|
|
|
private function __construct() |
|
{ |
|
self::setup(); |
|
|
|
$this->api_config = require dirname(__DIR__, 2) . "/inc/configurazione.php"; |
|
|
|
$this->stato = self::$stati->{0}; |
|
$this->stato_utilizzo = self::$utilizzo->{$this->stato_utilizzo ?? "001"}; |
|
$this->stato_comprova = self::$comprova->{$this->stato_comprova ?? "001"}; |
|
$this->stato_richiesta = ! empty($this->stato_richiesta) ? self::$stati_richiesta->{$this->stato_richiesta} : (object) ["descrizione" => (object) ["it" => "/"]]; |
|
|
|
if(! empty($this->codice)) { |
|
|
|
if(! empty($this->data_inserimento)) { |
|
$this->stato = self::$stati->{1}; |
|
} |
|
|
|
if(! empty($this->data_fine_validita) && strtotime($this->data_fine_validita) < strtotime('now')) { |
|
$this->stato = self::$stati->{2}; |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/** |
|
* Inizializza le varibili statiche |
|
* |
|
* @return void |
|
*/ |
|
private static function setup() : void |
|
{ |
|
// Inizializzo gli stati |
|
self::$stati = (object) json_decode(json_encode(self::STATI)); |
|
|
|
// Inizlializzo le query |
|
global $pdo; |
|
if (!self::$queryInitialized) { |
|
self::$stm = $pdo->prepare("SELECT * FROM b_fvoe_documenti WHERE `tipo_documento` = :tipo_documento AND `codice_fvoe` = :codice_fvoe AND (`data_inserimento` IS NOT NULL OR `data_inserimento` <> '') ORDER BY `data_fine_validita` DESC LIMIT 0,1"); |
|
self::$stmDocumento = $pdo->prepare("SELECT * FROM b_fvoe_documenti WHERE `tipo_documento` = :tipo_documento AND `codice_fvoe` = :codice_fvoe AND (`data_inserimento` IS NULL OR `data_inserimento` = '') ORDER BY `timestamp_creazione` DESC LIMIT 0,1"); |
|
self::$stmRequestData = $pdo->prepare("SELECT `richiesta` FROM `b_fvoe_operazioni` WHERE (`richiesta` IS NOT NULL OR `richiesta` <> '') AND `tipo_documento` = :tipo_documento AND `codice_fvoe` = :codice_fvoe ORDER BY `timestamp` DESC LIMIT 0,1"); |
|
self::$stmPendingDocument = $pdo->prepare("SELECT * FROM b_fvoe_documenti WHERE `tipo_documento` = :tipo_documento AND `codice_fvoe` = :codice_fvoe AND (`id_documento` IS NULL OR `id_documento` = '') ORDER BY `codice` DESC LIMIT 0,1"); |
|
self::$queryInitialized = true; |
|
} |
|
|
|
// Iniziallizzo la stato delle richieste di documento |
|
if(empty(self::$stati_richiesta)) { |
|
$stato_richiesta = jsonToArray(__DIR__ . DIRECTORY_SEPARATOR . "json" . DIRECTORY_SEPARATOR . "stato_richiesta_documento.json"); |
|
$stato_richiesta = array_column($stato_richiesta, null, "codice"); |
|
self::$stati_richiesta = json_decode(json_encode($stato_richiesta)); |
|
} |
|
|
|
// Iniziallizzo la tipologia di utilizzo del documento |
|
if(empty(self::$utilizzo)) { |
|
$utilizzo = jsonToArray(__DIR__ . DIRECTORY_SEPARATOR . "json" . DIRECTORY_SEPARATOR . "stato_utilizzo.json"); |
|
$utilizzo = array_column($utilizzo, null, "codice"); |
|
self::$utilizzo = json_decode(json_encode($utilizzo)); |
|
} |
|
|
|
// Iniziallizzo la comprova del documento |
|
if(empty(self::$comprova)) { |
|
$comprova = jsonToArray(__DIR__ . DIRECTORY_SEPARATOR . "json" . DIRECTORY_SEPARATOR . "comprova_documento.json"); |
|
$comprova = array_column($comprova, null, "codice"); |
|
self::$comprova = json_decode(json_encode($comprova)); |
|
} |
|
|
|
// Inizializzo le tipoligie di documento |
|
if(empty(self::$tipologia_documenti)) { |
|
self::$tipologia_documenti = jsonToArray(__DIR__ . "/json/tipologia_documenti.json"); |
|
self::$tipologia_documenti = array_column(self::$tipologia_documenti, null, "codice"); |
|
} |
|
|
|
// Inizializzo il path dei modelli di dati da richiedere |
|
if(empty(self::$path_modelli_dati_aggiuntivi)) { |
|
self::$path_modelli_dati_aggiuntivi = dirname(__DIR__, 2) . '/versions/' . NuovaPiattaformaAppalti::LATEST_SDK_VERSION . '/fvoe'; |
|
} |
|
|
|
} |
|
|
|
/** |
|
* Inizializza la classe |
|
* |
|
* @param mixed $tipo_documento |
|
* @return self |
|
*/ |
|
public static function init(string $tipo_documento, int $codice_fvoe) : self |
|
{ |
|
self::setup(); |
|
if(empty(self::$tipologia_documenti[$tipo_documento])) { |
|
throw new InvalidArgumentException("Tipologia di documento non valida", 1); |
|
} |
|
|
|
$document = new self(); |
|
$document->tipo_documento = $tipo_documento; |
|
$document->codice_fvoe = $codice_fvoe; |
|
$document->oggetto = self::$tipologia_documenti[$tipo_documento]["descrizione"]["it"]; |
|
$document->stato_richiesta = "001"; |
|
return $document; |
|
} |
|
|
|
/** |
|
* Get pending document record |
|
* |
|
* @return FVOEDocument |
|
*/ |
|
public function getPendingDocument() : FVOEDocument { |
|
|
|
if($this->documentsCollection()->areThereDocumentsPendingRelease() && $this->documentsCollection()->haveRequestsBeenMade()) { |
|
|
|
self::$stmPendingDocument->execute([":tipo_documento" => $this->tipo_documento, ":codice_fvoe" => $this->codice_fvoe]); |
|
if(self::$stmPendingDocument->rowCount() > 0) { |
|
|
|
self::$stmPendingDocument->setFetchMode(PDO::FETCH_CLASS, 'FVOEDocument'); |
|
return self::$stmPendingDocument->fetch(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/** |
|
* Verifica se una specifica classe documentale richiede dati aggiuntivi |
|
* |
|
* @param mixed $tipo_documento |
|
* @return bool |
|
*/ |
|
public static function hasFormRequest(?string $tipo_documento) : bool |
|
{ |
|
self::setup(); |
|
return ! empty(self::$tipologia_documenti[$tipo_documento]["modelloDati"]) && |
|
file_exists(self::$path_modelli_dati_aggiuntivi . '/' . self::$tipologia_documenti[$tipo_documento]["modelloDati"] . '.json'); |
|
} |
|
|
|
/** |
|
* Ottieni il form per la richiesta della classe documentale |
|
* |
|
* @param mixed $tipo_documento |
|
* @return array |
|
*/ |
|
public static function getFormRequest(string $tipo_documento) : ?array { |
|
self::setup(); |
|
if(self::hasFormRequest($tipo_documento)) { |
|
return jsonToArray(self::$path_modelli_dati_aggiuntivi . '/' . self::$tipologia_documenti[$tipo_documento]["modelloDati"] . '.json'); |
|
} |
|
return null; |
|
} |
|
|
|
/** |
|
* Make repeatable object for ajax request. |
|
* |
|
* @param Array $settings |
|
* @return String |
|
*/ |
|
public function makeRepeatableObject(array $settings): String |
|
{ |
|
$settings["codice"] = $this->codice; |
|
$settings["tipo_documento"] = $this->tipo_documento; |
|
$settings["codice_fvoe"] = $this->codice_fvoe; |
|
return base64_encode(gzdeflate(json_encode($settings))); |
|
} |
|
|
|
private function fixCustomFields(array &$data) { |
|
foreach ($data as $key => &$element) { |
|
if(is_array($element)) { |
|
if (array_keys(array_merge($element)) === range(0, count($element) - 1)) { |
|
$element = array_values($element); |
|
} |
|
if(!empty($element['Giorno']) && !empty($element['Mese']) && !empty($element['Anno'])) { |
|
$element["DataDiNascitaCustomField"] = "{$element['Giorno']}/{$element['Mese']}/{$element['Anno']}"; |
|
} |
|
self::fixCustomFields($element); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Get data already transmitted for the current document type |
|
* |
|
* @return array |
|
*/ |
|
public function getCardData(): array { |
|
self::$stmRequestData->execute([":tipo_documento" => $this->tipo_documento, ":codice_fvoe" => $this->codice_fvoe]); |
|
if(self::$stmRequestData->rowCount() == 1) { |
|
$data = self::$stmRequestData->fetch(PDO::FETCH_COLUMN, 0); |
|
$data = unserialize($data); |
|
self::fixCustomFields($data); |
|
return $data; |
|
} |
|
return []; |
|
} |
|
|
|
/** |
|
* Stampa il form per una specifica classe documentale |
|
* |
|
* @param mixed $tipo_documento |
|
* @return void |
|
*/ |
|
public function printDocumentRequestForm(?string $tipo_documento = null) : void { |
|
|
|
if(empty($tipo_documento)) { $tipo_documento = $this->tipo_documento; } |
|
$form = FVOEDocument::getFormRequest($tipo_documento); |
|
if(! empty($form["content"])) { |
|
$this->printSection($form["content"]); |
|
?> |
|
<style> |
|
@media (min-width: 1200px) { |
|
.col-xl-6 { |
|
flex: 1 0 50%; |
|
max-width: 100%; |
|
} |
|
} |
|
/* Workaround for excessive padding */ |
|
.form-group.col-sm-12 { |
|
padding: 0 !important; |
|
} |
|
/* Workaround for tab-pane row */ |
|
.tab-pane .row .active { |
|
display: flex !important; |
|
} |
|
.tab-content > .active.row { |
|
display: flex !important; |
|
} |
|
.btn-xs { |
|
padding: 0 0.4rem; |
|
font-size: 0.8rem; |
|
} |
|
#master-fieldset > .col-12 { |
|
padding-left: 0 !important; |
|
padding-right: 0 !important; |
|
} |
|
</style> |
|
<script type="text/javascript"> |
|
if (typeof window.npa === "undefined") { |
|
const npa = class { |
|
ready() { |
|
f_ready(); |
|
} |
|
bindEvents() { |
|
const self = this; |
|
self.groupRepeatables(); |
|
} |
|
add2Form(target, data) { |
|
const self = this; |
|
let repeatable_target = target; |
|
let container = document.getElementById(repeatable_target); |
|
let iterations = Number(container.childElementCount); |
|
if (container.dataset.hasTabs) { |
|
iterations = Number(container.dataset.iterations); |
|
} |
|
$.ajax({ |
|
type: "POST", |
|
url: "ajax/add2Form.php", |
|
data: { |
|
data: data, |
|
index: iterations + 1, |
|
}, |
|
dataType: "html", |
|
beforeSend: function() { |
|
$("#wait_div").show(); |
|
} |
|
}) |
|
.fail(function(response) { |
|
swal(js_dict["error-retry"]); |
|
}) |
|
.done(function(response) { |
|
let newChild = document.createElement("template"); |
|
newChild.innerHTML = response.trim(); |
|
newChild = container.appendChild(newChild.content.firstChild); |
|
self.ready(); |
|
self.groupRepeatables(); |
|
}) |
|
.always(function() { |
|
$("#wait_div").slideUp('fast'); |
|
}); |
|
} |
|
groupRepeatables() { |
|
const self = this; |
|
document.querySelectorAll(".repeatable_container").forEach(function(el) { |
|
let i = 0; |
|
let tabs = null; |
|
let tabHeaders = null; |
|
let hasTabs = el.dataset.hasTabs; |
|
let selectedBind = ""; |
|
let toSelect = null; |
|
// Aggiunta o rimozione |
|
if (hasTabs) { |
|
// Otteniamo la tab correntemente selezionata |
|
selectedBind = el.querySelector(".nav-link.active").dataset.bindtarget; |
|
// Otteniamo, puliamo e rimuoviamo i vecchi header |
|
tabHeaders = el.removeChild(document.getElementById(el.dataset.tabHeadersId)); |
|
tabHeaders.innerHTML = ""; |
|
// Otteniamo e rimuoviamo le vechie tab |
|
tabs = el.removeChild(document.getElementById(el.dataset.tabsId)); |
|
// I vecchi elementi in tab vengono trasposti dentro il repeatable nell'ordine corretto |
|
let tempContainer = []; |
|
let index = 0; |
|
tabs.childNodes.forEach(function(oldChild) { |
|
if (oldChild.nodeType !== Node.ELEMENT_NODE) |
|
return; |
|
tempContainer.push(oldChild); |
|
}); |
|
// Iteriamo i figli nuovi e verifichiamo che ce ne |
|
// sia solo uno nuovo. |
|
el.childNodes.forEach(function(newChild) { |
|
if (newChild.id) { |
|
if (toSelect === null) { |
|
if (newChild.id) { |
|
toSelect = newChild; |
|
} |
|
} else { |
|
// Ne abbiamo più di uno, non selezioneremo nulla |
|
toSelect = false; |
|
} |
|
} |
|
}); |
|
tempContainer.forEach(function(oldChild) { |
|
el.insertBefore(oldChild, el.children[index++]); |
|
}); |
|
// In questo modo abbiamo vecchi figli e poi i nuovi figli e possiamo far ricreare header e tutto |
|
} else { |
|
// Creiamo l'header |
|
tabHeaders = document.createElement("ul"); |
|
tabHeaders.classList.add("nav"); |
|
tabHeaders.classList.add("nav-tabs"); |
|
tabHeaders.classList.add("npa-tabs"); |
|
tabHeaders.classList.add("px-4"); |
|
tabHeaders.setAttribute("role", "tablist"); |
|
tabHeaders.id = self.generateRandomID(); |
|
// Creiamo il contenitore di tabs |
|
tabs = document.createElement("div"); |
|
tabs.classList.add("tab-content"); |
|
tabs.id = self.generateRandomID(); |
|
// Assegnamo id casuali per poterli riferire dopo |
|
el.dataset.hasTabs = true; |
|
el.dataset.tabHeadersId = tabHeaders.id; |
|
el.dataset.tabsId = tabs.id; |
|
i = 0; |
|
} |
|
let straightToTabs = []; |
|
let iteration = 0; |
|
el.childNodes.forEach(function(child) { |
|
if (child.nodeType !== Node.ELEMENT_NODE) { |
|
return; |
|
} |
|
// Header della tab |
|
let tabLi = document.createElement("li"); |
|
tabLi.classList.add("nav-item"); |
|
tabLi.setAttribute("role", "presentation"); |
|
let tabButton = document.createElement("a"); |
|
tabButton.classList.add("nav-link"); |
|
tabButton.classList.add("h-100"); |
|
tabButton.classList.add("ignore-lock"); |
|
tabButton.dataset.toggle = "tab"; |
|
tabButton.dataset.target = `#${child.id}`; |
|
tabButton.style.minWidth = "90px"; |
|
tabButton.style.textAlign = "left"; |
|
tabLi.appendChild(tabButton); |
|
tabHeaders.appendChild(tabLi); |
|
if (Number(child.dataset.index) > Number(iteration)) { |
|
iteration = Number(child.dataset.index); |
|
} |
|
// Creo un ID univoco per associare facilmente tab button e tab |
|
if (child.dataset.bind) { // Riportiamo quello esistente se già c'è |
|
// Nessuna azione necessaria |
|
} else { |
|
child.dataset.bind = self.generateRandomID(); |
|
} |
|
tabButton.dataset.bindtarget = child.dataset.bind; |
|
let tabText = document.createElement("span"); |
|
tabText.classList.add("nav-link-text"); |
|
tabButton.appendChild(tabText); |
|
tabText.innerText = i + 1; |
|
let found = []; |
|
for (let key of ["denominazione", "lotIdentifier", "cig"]) { |
|
const el = child.querySelector(`input[data-reference$='${key}']`); |
|
if (el && el.value) { |
|
found.push(el); |
|
} |
|
} |
|
if (found.length > 0) { |
|
if (found.length === 1) { |
|
found = found[0]; |
|
} else { |
|
found = self.findClosest(child, found); |
|
} |
|
tabText.innerText = found.value; |
|
} |
|
// Tab in se |
|
child.classList.remove("col-12"); |
|
child.classList.add("tab-pane"); |
|
child.classList.add("fade"); |
|
child.classList.add("row"); |
|
straightToTabs.push(child); |
|
// Cerchiamo di recuperare il tasto di eliminazione |
|
if (i > 0) { |
|
let deleteButton = child.querySelector(".npa-delete-button"); |
|
if (deleteButton) { |
|
deleteButton.style.display = "inline"; |
|
deleteButton.parentNode.style.display = "none"; |
|
tabButton.appendChild(deleteButton.cloneNode(true)); |
|
deleteButton.style.display = "none"; |
|
} |
|
} |
|
i++; |
|
}); |
|
tabHeaders.style.display = "flex"; |
|
tabHeaders.classList.add("mb-3"); |
|
straightToTabs.forEach(function(child) { |
|
tabs.appendChild(child); |
|
}); |
|
el.dataset.iterations = iteration; |
|
el.appendChild(tabHeaders); |
|
el.appendChild(tabs); |
|
// Se abbiamo un solo elemento non mostriamo le tab |
|
if (i == 1) { |
|
tabHeaders.style.display = "none"; |
|
} |
|
// Una volta creati andiamo a caccia dell'attivo |
|
let toBeActive = el.querySelector(`.nav-link[data-bindtarget]`) |
|
// Cerchiamo di ripristinare quello che era già selezionato ove possibile |
|
if (selectedBind.length > 0) { |
|
let selectedActive = el.querySelector(`.nav-link[data-bindtarget="${selectedBind}"]`); |
|
if (selectedActive) { |
|
toBeActive = selectedActive; |
|
} |
|
} |
|
// Settiamo attive sia tab button che child |
|
if (toBeActive) { |
|
// Però se abbiamo invece da selezionare uno nuovo |
|
// perchè è quello appena selezionato |
|
if (toSelect) { |
|
// toBeActive viene deselezionato |
|
toBeActive.classList.remove("active"); |
|
// Cerchiamo la sua tab |
|
const child = document.querySelector(`[data-bind="${toBeActive.dataset.bindtarget}"]`); |
|
if (child) { |
|
child.classList.remove("show") |
|
child.classList.remove("active"); |
|
} |
|
// e quindi toSelect diventa l'effettivo toBeActive |
|
toBeActive = document.querySelector(`[data-bindtarget="${toSelect.dataset.bind}"]`); |
|
} |
|
toBeActive.classList.add("active"); |
|
// Cerchiamo la sua tab |
|
const child = document.querySelector(`[data-bind="${toBeActive.dataset.bindtarget}"]`); |
|
if (child) { |
|
child.classList.add("show") |
|
child.classList.add("active"); |
|
} |
|
|
|
} |
|
|
|
}); |
|
} |
|
generateRandomID() { |
|
var S4 = function() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); }; |
|
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); |
|
} |
|
} |
|
window.npa = document.npa = new npa(); |
|
} |
|
npa.bindEvents(); |
|
</script> |
|
<? |
|
} |
|
|
|
} |
|
|
|
/** |
|
* Set form request data before send |
|
* |
|
* @param array &$data |
|
* @param array $types |
|
* @return void |
|
*/ |
|
private static function setDocumentRequestFormData(array &$data, array $types) { |
|
foreach ($types as $key => $settings) { |
|
if (isset($data[$key])) { |
|
if(is_array($data[$key])) { |
|
// Gestisco le ripetizioni |
|
if(isset($data[$key][0])) { |
|
foreach ($data[$key] as $index => &$subvalues) { |
|
self::setDocumentRequestFormData($subvalues, $settings); |
|
} |
|
} else { |
|
self::setDocumentRequestFormData($data[$key], $settings); |
|
} |
|
} else { |
|
if($key == "CF") { |
|
if(isset($data["DatiNascita"]["CodiceCatastoStato"]) && $data["DatiNascita"]["CodiceCatastoStato"] == "Z000") { |
|
$data["DatiNascita"]["CodiceCatastoComuneItaliano"] = codice_catasto_from_cf($data[$key]); |
|
} |
|
} |
|
if($key == "CF_Soggetto") { |
|
$data["LuogoNascita_Soggetto"] = codice_catasto_from_cf($data[$key]); |
|
} |
|
if($key == "DataDiNascitaCustomField") { |
|
$date = date2mysql($data[$key]); |
|
$date = \DateTime::createFromFormat('Y-m-d', $date); |
|
$data["Giorno"] = $date->format('d'); |
|
$data["Mese"] = $date->format('m'); |
|
$data["Anno"] = $date->format('Y'); |
|
unset($data["DataDiNascitaCustomField"]); |
|
} |
|
if($key == "DataNascita_Soggetto") { |
|
$date = date2mysql($data[$key]); |
|
$date = \DateTime::createFromFormat('Y-m-d', $date); |
|
$data[$key] = $date->format('Y-m-d\T00:00:00+02:00'); |
|
} |
|
switch ($settings['format']) { |
|
case 'datetime': |
|
case 'date-time': |
|
$date = datetime2mysql($data[$key]); |
|
$date = \DateTime::createFromFormat('Y-m-d H:i', $date); |
|
if (! is_bool($date)) { |
|
$data[$key] = $date->format(\DateTime::ATOM); |
|
} |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Richiedi un documento a un ente certificato |
|
* |
|
* @param string $tipologia |
|
* @param ?array $data |
|
* @return bool |
|
*/ |
|
public function request(?array $data = [], ?string &$message = "") : bool |
|
{ |
|
global $config; |
|
|
|
// Prevalorizziamo $message |
|
$message = __("Errore interno sconosciuto"); |
|
|
|
// Verifichiamo che sia settata una tipologia di documento |
|
if(empty($this->tipo_documento) || empty($this->codice_fvoe)) { |
|
$message = __("Impossibile completare la richiesta: è necessario selezionare una tipologia di documento e un fascicolo OE."); |
|
return false; |
|
} |
|
|
|
// 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; |
|
} |
|
|
|
// Verifica se la richiesta può essere inviata |
|
self::$stm->execute([":tipo_documento" => $this->tipo_documento, ":codice_fvoe" => $this->codice_fvoe]); |
|
if(self::$stm->rowCount() > 0) { |
|
self::$stm->setFetchMode(PDO::FETCH_CLASS, 'FVOEDocument'); |
|
$document = self::$stm->fetch(); |
|
if(strtotime($document->data_fine_validita) > strtotime("+ 1 month")) { |
|
$message = __("Impossibile completare la richiesta: il documento non è in scadenza o scaduto."); |
|
return false; |
|
} |
|
} |
|
|
|
$this->fvoe = FVOE::init($this->codice_fvoe, FVOEInizializationType::CODICE_FVOE); |
|
$this->fascicolo = $this->fvoe->fascicolo; |
|
|
|
$documento = new Salva(); |
|
$documento->debug = false; |
|
$documento->nome_tabella = "b_fvoe_documenti"; |
|
$documento->operazione = "INSERT"; |
|
$documento->expect = ["codice_fvoe", "tipo_documento", "oggetto", "stato_richiesta"]; |
|
$documento->oggetto = [ |
|
"codice_fvoe" => $this->codice_fvoe, |
|
"tipo_documento" => $this->tipo_documento, |
|
"oggetto" => $this->oggetto, |
|
"stato_richiesta" => $this->stato_richiesta |
|
]; |
|
|
|
self::$stmDocumento->execute([":tipo_documento" => $this->tipo_documento, ":codice_fvoe" => $this->codice_fvoe]); |
|
if(self::$stmDocumento->rowCount() > 0) { |
|
self::$stmDocumento->setFetchMode(PDO::FETCH_CLASS, 'FVOEDocument'); |
|
$doc = self::$stmDocumento->fetch(); |
|
|
|
$documento->operazione = "UPDATE"; |
|
$documento->expect[] = "codice"; |
|
$documento->oggetto["codice"] = $doc->codice; |
|
} |
|
|
|
$this->codice = $documento->oggetto["codice"] = $documento->save(); |
|
|
|
$operazione = new Salva(); |
|
$operazione->debug = false; |
|
$operazione->nome_tabella = "b_fvoe_operazioni"; |
|
$operazione->operazione = "INSERT"; |
|
$operazione->expect = ["codice_documento", "codice_partecipante", "codice_lotto", "operazione", "codice_fvoe", "tipo_documento"]; |
|
$operazione->oggetto = [ |
|
"codice_fvoe" => $this->codice_fvoe, |
|
"codice_documento" => $this->codice, |
|
"codice_partecipante" => $this->fvoe->info["uuid_partecipante"], |
|
"tipo_documento" => $this->tipo_documento, |
|
"codice_lotto" => $this->fvoe->info["codice_lotto_npa"], |
|
"operazione" => "RICHIESTA-DOCUMENTO" |
|
]; |
|
|
|
date_default_timezone_set('Europe/Rome'); |
|
|
|
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]); |
|
|
|
// Andiamo a verificare che ci sia un'operazione di richiesta documento in attesa |
|
$richiesta_documento = FVOE::fetchLastOperation($this->codice, null, null, "RICHIESTA-DOCUMENTO", null, false); |
|
|
|
// Se c'è |
|
if (! empty($richiesta_documento)) { |
|
|
|
// Popoliamo il messaggio di errore |
|
$message = __("Errore durante la richiesta del documento"); |
|
|
|
$operazione->operazione = "UPDATE"; |
|
$operazione->expect = ["codice", "esito", "risultato"]; |
|
$operazione->oggetto = $richiesta_documento; |
|
|
|
// Andiamo a chiedere al server lo stato della richiesta di accesso |
|
$request = [ |
|
"idRichiesta" => $richiesta_documento["id_richiesta"] |
|
]; |
|
|
|
$apiMessage = ""; |
|
$result_str = $this->apiCall("fvoe", "check-document-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->result)) { |
|
|
|
global $config; |
|
$message = null; |
|
|
|
foreach ($result->result as $document_request) { |
|
|
|
if($document_request->idRichiesta == $richiesta_documento["id_richiesta"]) { |
|
|
|
$documento->operazione = "UPDATE"; |
|
$documento->expect = ["codice", "stato_richiesta", "id_documento"]; |
|
$documento->oggetto = [ |
|
"codice" => $this->codice, |
|
"stato_richiesta" => $document_request->stato->codice, |
|
"id_documento" => $document_request->idDocumento ?? null, |
|
]; |
|
$documento->save(); |
|
|
|
} |
|
|
|
} |
|
|
|
$operazione->oggetto["esito"] = "OK"; |
|
$operazione->save(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
$operazione->save(); |
|
return false; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Verifico se è necessario trasmettere dati aggiuntivi |
|
if(! empty(self::$tipologia_documenti[$this->tipo_documento]["modelloDati"]) && empty($data)) { |
|
$message = __("Impossibile completare la richiesta: il documento richiede dati aggiuntivi non presenti nel form."); |
|
return false; |
|
} |
|
|
|
// Creiamo la richiesta di accesso al documento |
|
$request = [ |
|
"chiaveAccesso" => simple_decrypt($this->fvoe->info["chiave_accesso"], $config["simple_encrypt"]["chiave_fvoe"]), |
|
// "codiceFiscaleSoggetti" => "", |
|
"tipoDocumento" => json_encode([ |
|
// "idTipologica" => "tipoDocumento", |
|
"codice" => $this->tipo_documento |
|
]), |
|
// "datiRichiesta" => "" |
|
]; |
|
|
|
if(! empty(self::$tipologia_documenti[$this->tipo_documento]["modelloDati"])) { |
|
|
|
$form = self::getFormRequest($this->tipo_documento); |
|
$types = $this->getFormInputsTypes($form["content"]); |
|
self::setDocumentRequestFormData($data, $types); |
|
|
|
$request["datiRichiesta"] = json_encode($data); |
|
// $request["datiRichiesta"]["type"] = str_replace('_', '', self::$tipologia_documenti[$this->tipo_documento]["modelloDati"]); |
|
} |
|
|
|
$operazione->expect[] = "richiesta"; |
|
$operazione->oggetto["richiesta"] = serialize($request["datiRichiesta"] ?? null); |
|
|
|
// Effettuiamo la richiesta |
|
$apiMessage = ""; |
|
$claims = $this->getAnacJwsCustomClaims($this->api_config["fvoe"]["endpoint"]); |
|
// $result_str = $this->apiCall("fvoe", "documents-request", $request, $claims, [], $apiMessage); |
|
$result_str = $this->apiCall("fvoe", "request-document", $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->oggetto["esito"] = "KO"; |
|
|
|
$operazione->expect[] = "risultato"; |
|
$operazione->oggetto["risultato"] = serialize($result); |
|
|
|
$operazione->save(); |
|
|
|
$message = __("Errore in fase di richiesta del documento."); |
|
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 false; |
|
|
|
} |
|
|
|
// Conferma andata con successo |
|
$operazione->expect[] = "id_richiesta"; |
|
$operazione->oggetto["id_richiesta"] = $result->idRichiesta; |
|
|
|
if ($operazione->save()) { |
|
|
|
$message = ""; |
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
/** |
|
* get the related FVOEDocumentsCollection |
|
* |
|
* @return FVOEDocumentsCollection |
|
*/ |
|
public function documentsCollection() : FVOEDocumentsCollection { |
|
|
|
return new FVOEDocumentsCollection($this->codice_fvoe, $this->tipo_documento); |
|
|
|
} |
|
|
|
}
|