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.
 
 
 
 
 

659 righe
25 KiB

<?php
use GuzzleHttp\HandlerStack;
use function PHPUnit\Framework\isJson;
/**
* TedEsenderApiManager
*/
trait TedEsenderApiManager
{
/**
* TedEsender Endpoint URL
*
* @var String
*/
private $endpoint;
/**
* Request Header
*
* @var Array
*/
private $header = [];
/**
* Select the environment
*
* @return string
*/
private function environment() : string
{
// Workaround verifica in produzione
return "beta";
// Codice normale
global $config;
if ($config["developEnv"]) {
return "beta";
}
return "prod";
}
private function loadTranslations() : array {
$version = $this->engine->info["sdk_version"];
$translations = json_decode(file_get_contents(__DIR__ . "/../eforms/{$version}/translations/it.json"), true);
return $translations;
}
/**
* Send the notice validation
*
* @return void
*/
public function noticeValidation() : void
{
global $config;
$notice = $this->toXML();
$params = json_encode([
"notice" => base64_encode($notice),
"language" => "en",
"validationMode" => "static",
"eFormsSdkVersion" => "eforms-sdk-" . $this->getNoticeSDKVersion(),
]);
$this->header = [];
$this->header[1] = "X-API-Key: {$config["tedesender"]["apikey"]}";
$this->header[2] = "Content-Type: application/json";
$this->header[3] = "accept: application/xml";
$this->curl = curl_init("{$config["tedesender"]["endpoints"]["validation"][$this->environment()]}/v1/notices/validation");
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params);
$this->response = curl_exec($this->curl);
$this->translations = $this->loadTranslations();
$errors = [];
$decoded = json_decode($this->response, 1);
if (json_last_error() === JSON_ERROR_NONE) {
$xml_lines = @preg_split("/\r\n|\n|\r/", @$this->toXML());
if(! empty($decoded["message"])) {
$messages = substr($decoded["message"], strpos($decoded["message"], "["));
if(isJson($messages)) {
$messages = json_decode($messages, 1);
if (is_array($messages)) {
foreach($messages as $message) {
try {
if(!empty($message["line"]) && !empty($xml_lines)) {
$affected_lines = implode("\n", array_splice($xml_lines, max(0, $message["line"] - 5), 10));
preg_match_all("/<!--([\s\S\n]*?)-->/", $affected_lines, $affected_fields, PREG_PATTERN_ORDER);
if(!empty($affected_fields)) {
$message["message"] .= "<hr><span class='badge badge-primary mr-2'>BETA</span>" . __guue("Campi potenzialmente coinvolti:") . " " . implode(" - ", $affected_fields[1]);
}
}
} catch(\Throwable $t) {
// Pass
}
$errors[] = [
"label" => "Linea: {$message["line"]} - {$message["message"]}"
];
}
}
$this->manageErrors($errors);
$this->setStato("BOZZA");
if (empty($this->errors)) {
$_SESSION["guue_verified_" . $this->codice] = True;
$this->setStato("DA TRASMETTERE");
}
return;
}
}
$errors[] = [
"label" => __guue('Struttura XML non valida')
];
} else {
if(empty($this->response)) {
$error["label"] = "Risposta inattesa dai server di validazione GUUE. Riprova più tardi.";
$errors[] = $error;
} else {
$xml = xmlToArray(simplexml_load_string($this->response));
if (!empty($xml["schematron-output"]["svrl:failed-assert"])) {
if (!array_is_list($xml["schematron-output"]["svrl:failed-assert"])) {
$xml["schematron-output"]["svrl:failed-assert"] = [$xml["schematron-output"]["svrl:failed-assert"]];
}
foreach ($xml["schematron-output"]["svrl:failed-assert"] as &$error) {
$error["label"] = $this->translations["rule|text|{$error['@id']}"] ?? $error['@id'];
$errors[] = $error;
}
}
}
}
$this->manageErrors($errors);
if (!empty($errors)) {
$this->setStato("BOZZA");
} else {
$_SESSION["guue_verified_" . $this->codice] = True;
$this->setStato("DA TRASMETTERE");
}
}
public function setStato(string $stato) : void {
global $pdo;
$pdo->go("UPDATE `b_guue` SET stato = :stato WHERE codice = :codice", [":stato" => $stato, ":codice" => $this->codice]);
}
/**
* Stop notice pubblication
*
* @return array
*/
public function stopPubblication() : array
{
global $config;
$this->header = [];
$this->header[0] = "Authorization: Bearer {$config['tedesender']['apikey']}";
$this->header[1] = "accept: application/json";
$this->header[2] = 'Content-Type: application/x-www-form-urlencoded';
$business_id = $this->numero_tecnico;
$this->curl = curl_init("{$config["tedesender"]["endpoints"]["pubblication"][$this->environment()]}/api/v2/notice/notices/{$business_id}/stop-publication-esentool");
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
$this->response = json_decode(curl_exec($this->curl));
$response = [
"error" => false,
"data" => $this->response
];
if(!isset($this->response->id)) {
$response["error"] = true;
}
return $response;
}
public static function getSubmissionID(array $response) : string {
$submission_id = explode("/",$response["validationReportUrl"]);
return $submission_id[count($submission_id) - 2];
}
public function readyForANAC($ready = true) : array {
$stati = $this->getStati();
global $pdo;
if($ready) {
$pdo->go("UPDATE b_guue
SET stato = :stato, data_aggiornamento = NOW(), data_trasmissione = NOW()
WHERE codice = :codice",
[
":codice" => $this->info["codice"],
":stato" => $stati[2]["title"] // Trasmesso
]);
} else {
$pdo->go("UPDATE b_guue
SET stato = :stato, data_aggiornamento = NOW()
WHERE codice = :codice",
[
":codice" => $this->info["codice"],
":stato" => $stati[0]["title"] // Bozza
]);
}
return [
"error" => false,
"data" => []
];
}
/**
* Send the notice to TedSimap
*
* @return array
*/
public function send() : array
{
global $config;
$notice = $this->toXML();
$stati = $this->getStati();
$this->header = [];
$this->header[0] = "Authorization: Bearer {$config['tedesender']['apikey']}";
$this->header[1] = "accept: application/json";
$this->header[2] = "Content-Type: multipart/form-data";
$name = tempnam(sys_get_temp_dir(),"notice");
$file = fopen($name,"w");
file_put_contents($name,$notice);
fclose($file);
$params = [
'metadata' => '{
"noticeAuthorEmail": "'.$_SESSION["utente"]->getInfo()["email"].'",
"noticeAuthorLocale": "it"
}',
"notice" => new \CURLFile(realpath($name), "text/xml", "tmp.xml")
];
$this->curl = curl_init("{$config["tedesender"]["endpoints"]["pubblication"][$this->environment()]}/api/v2/notice/notices/submit");
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params);
curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
$this->response = curl_exec($this->curl);
if(! empty($this->response)) {
$this->response = json_decode($this->response, TRUE);
if(! empty($this->response["success"]) && $this->response["success"]) {
$matches = [];
preg_match_all("/notices[\/](.*)[\/]validation[-]report/m", $this->response["validationReportUrl"], $matches);
$this->numero_tecnico = $matches[1][0];
$this->manageErrors([]);
global $pdo;
$pdo->go("UPDATE b_guue
SET risposta = :risposta, stato = :stato, numero_tecnico = :numero_tecnico, data_aggiornamento = NOW(), data_trasmissione = NOW()
WHERE codice = :codice",
[
":codice" => $this->info["codice"],
":risposta" => base64_encode(json_encode($this->response)),
":numero_tecnico" => TedEsender::getSubmissionID($this->response),
":stato" => $stati[2]["title"]
]);
return [
"error" => false,
"data" => $this->response
];
} else if (isset($this->response["success"]) && !$this->response["success"]){
$this->header = [];
$this->header[0] = "Authorization: Bearer {$config['tedesender']['apikey']}";
unset($this->header[1]);
unset($this->header[2]);
$this->curl = curl_init($this->response["validationReportUrl"]);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
$this->response = curl_exec($this->curl);
$xml = xmlToArray(simplexml_load_string($this->response));
if (!empty($xml["schematron-output"])) {
$errors = $xml["schematron-output"]["svrl:failed-assert"];
foreach ($errors as &$error) {
if (isset($error["svrl:text"])) {
$error["label"] = $error["svrl:text"];
} else {
// TODO Gestire questa situazione correttamente
$error["label"] = print_r($error, true);
}
}
$this->manageErrors($errors);
//TODO: non ritorna uno schematron per i form X01 e X02
return [
"error" => true,
"data" => $this->response
];
}
} else {
return [
"error" => true,
"data" => $this->response
];
}
}
}
/**
* Get the notice json copy
*
* @return void
*/
public function json()
{
$json = json_encode($this->info["valori"] ?? [],JSON_INVALID_UTF8_IGNORE);
$length = strlen($json);
header('Content-Description: File Transfer');
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment; filename=\"{$this->info["codice"]}-{$this->info["form"]}.json\"");
header("Expires: 0");
header("Cache-Control: must-revalidate");
header("Pragma: public");
header("Content-Length: {$length}");
echo $json;
}
/**
* Get the notice pdf copy - LEGACY esender version
*
* @return void
*/
public function pdf_legacy() : void
{
$notice = $this->info["xml"];
// A quanto pare a volte è già b64
$b64decoded = base64_decode($notice, true);
if($b64decoded !== false) $notice = $b64decoded;
$b64notice = base64_encode($notice);
$post = http_build_query([
"coverPage" => false,
"notice" => $b64notice,
"format" => "PDF",
"language" => "IT",
]);
$this->curl = curl_init("https://esentool.ted.europa.eu/api/qualification/v1.0/notice/render");
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $post);
curl_setopt($this->curl, CURLOPT_USERPWD, "TEDC6:cm827gw6");
$this->response = curl_exec($this->curl);
$decoded = json_decode($this->response);
if(!valid_json($this->response, $decoded) || empty($decoded->result)) {
$pdf = null;
header('HTTP/1.0 404 File not found');
?><h1>File not found!</h1><?
?><a href="/backend/guue"><?= __guue("Ritorna") ?></a><?
die();
} else {
$pdf = base64_decode($decoded->result);
$length = strlen($pdf);
header('Content-Description: File Transfer');
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment; filename=\"{$this->info["codice"]}-{$this->info["form"]}.pdf\"");
header("Expires: 0");
header("Cache-Control: must-revalidate");
header("Pragma: public");
header("Content-Length: {$length}");
echo ($pdf);
}
}
/**
* Get the notice pdf copy
*
* @return void
*/
public function pdf() : void
{
global $config;
$notice = $this->info["xml"];
$b64notice = base64_encode($notice);
$post = "{\n \"file\": \"{$b64notice}\",\n \"language\": \"it\",\n \"format\": \"PDF\",\n \"textToHighlight\": \"string\",\n \"summary\": false\n}";
$this->curl = curl_init("{$config["tedesender"]["endpoints"]["visualization"][$this->environment()]}/api/v2/notices/render");
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->curl, CURLOPT_POST, 1);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $post);
$this->headers = [];
$this->headers[] = 'Accept: text/html';
$this->headers[] = "X-Api-Key: {$config["tedesender"]["apikey"]}";
$this->headers[] = 'Content-Type: application/json';
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->headers);
$this->response = curl_exec($this->curl);
$decoded = json_decode($this->response);
if (json_last_error() === JSON_ERROR_NONE) {
$pdf = null;
header('HTTP/1.0 404 File not found');
?><h1>File not found!</h1><?
?><a href="/backend/guue"><?= __guue("Ritorna") ?></a><?
die();
} else {
$pdf = $this->response;
$length = strlen($pdf);
header('Content-Description: File Transfer');
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment; filename=\"{$this->info["codice"]}-{$this->info["form"]}.pdf\"");
header("Expires: 0");
header("Cache-Control: must-revalidate");
header("Pragma: public");
header("Content-Length: {$length}");
echo ($pdf);
}
}
/**
* Sync all Notices
*
* @param myPDO $pdo
* @param String $settings_path
* @param String $xml_path
* @param bool $debug
*
* @return void
*/
public static function sync(myPDO $pdo, String $settings_path, String $xml_path, bool $debug = false, ?int $codice = 0) : void {
$settings = file_get_contents($settings_path);
$settings = json_decode($settings, TRUE);
$where = "";
$params = [];
if (!empty($codice)) {
$where = " AND codice = :codice";
$params = [":codice" => $codice];
}
$forms = $pdo->go("SELECT version, codice, form, info FROM b_guue WHERE stato IN ('TRASMESSO','IN PUBBLICAZIONE') AND numero_tecnico != '' AND numero_tecnico IS NOT NULL {$where} ORDER BY codice DESC", $params)->fetchAll(PDO::FETCH_OBJ);
$_SERVER["HTTP_USER_AGENT"] = "StudioAmica/Queue";
foreach ($forms as $form) {
if($form->version === "eForms") {
$ted = new TedEsender($form->form, $form->codice, $settings, $xml_path, true);
$ted->debug = $debug;
$ted->syncNoticeEforms();
}
}
}
/**
* Sync notice from TedSimap for eForms version
*/
public function syncNoticeEforms()
{
$statuses = [
"DRAFT" => "BOZZA",
"SUBMITTED" => "TRASMESSO",
"STOPPED" => "BLOCCATO",
"PUBLISHED" => "PUBBLICATO",
"PUBLISHING" => "IN PUBBLICAZIONE",
"DELETED" => "CANCELLATO",
"NOT_PUBLISHED" => "NON PUBBLICATO",
"ARCHIVED" => "ARCHIVIATO",
"VALIDATION_FAILED" => "VALIDAZIONE FALLITA"
];
if (!empty($this->info["numero_tecnico"])) {
global $config;
$this->header = [];
$this->header[0] = "Authorization: Bearer {$config['tedesender']['apikey']}";
$this->header[1] = "accept: application/json";
$uri = "{$config["tedesender"]["endpoints"]["pubblication"][$this->environment()]}/api/v2/notice/notices/search-esentool";
$uri .= "?page=0&size=1&sortProperty=versionId&sortDirection=DESC";
$uri .= "&id=".substr($this->info['numero_tecnico'],0,-3);
$this->curl = curl_init($uri);
curl_setopt($this->curl, CURLOPT_POST, 0);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
$this->response = curl_exec($this->curl);
$response = json_decode($this->response);
if ($response !== false && !empty($response->totalSize)) {
$stato = $statuses[$response->content[0]->status];
global $pdo;
$pdo->go("UPDATE b_guue SET stato = :stato WHERE codice = :codice",[":stato" => $stato, ":codice" => $this->info["codice"]]);
}
curl_close($this->curl);
$this->header = [];
}
}
/**
* Sync Notice from TedSimap for eSender version
*
* @param String $id
* @return void
*/
public function syncNoticeEsender()
{
if(! empty($this->info["numero_tecnico"])) {
$this->curl = curl_init("{$this->endpoint}/notice/{$this->info["numero_tecnico"]}");
curl_setopt($this->curl, CURLOPT_POST, 0);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->header);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
$this->response = curl_exec($this->curl);
if (! curl_errno($this->curl)) {
if(! empty($this->response)) {
$this->response = json_decode($this->response, 1);
if(! empty($this->response["submission_id"])) {
$this->info["stato"] = "TRASMESSO";
$unset_number = false;
switch ($this->response["status"]) {
case 'IN_PROGRESS':
$this->info["stato"] = "IN PUBBLICAZIONE";
break;
case 'PUBLISHED':
$this->info["stato"] = "PUBBLICATO";
if(! empty($this->response["publication_info"]["no_doc_ojs"])) {
$this->info["numero_ojs"] = $this->response["publication_info"]["no_doc_ojs"];
}
if(! empty($this->response["publication_info"]["publication_date"])) {
$this->info["data_pubblicazione"] = date('Y-m-d h:i:s', strtotime($this->response["publication_info"]["publication_date"]));
}
break;
case 'NOT_PUBLISHED':
$this->info["stato"] = "NON PUBBLICATO";
break;
case 'VALIDATION_ACCEPTED':
if(! empty($this->response["validation_rules_report"]["items"])) {
$this->info["stato"] = "RIFIUTATO";
$this->info["errori"] = [];
foreach ($this->response["validation_rules_report"]["items"] as $v) {{
if(! $v["valid"] && in_array($v["severity"], ["WARNING"])) {
#TODO: viene salvato come errore ma in realta dovrebbe essere creata una column a parte
$this->info["errori"][] = "{$v["message"]}<br>{$v["details"]}";
}
}}
if(! empty($this->info["errori"])) {
$this->info["errori"] = base64_encode(json_encode($this->info["errori"]));
}
}
break;
case 'RECEPTION_ERROR':
case 'QUALIFICATION_ERROR':
$this->info["stato"] = "RIFIUTATO";
$this->info["errori"] = [];
if(! empty($this->response["technical_validation_report"]["items"])) {
foreach ($this->response["technical_validation_report"]["items"] as $v) {
if(! $v["valid"] && in_array($v["severity"], ["ERROR", "CRITICAL"])) {
$this->info["errori"][] = "{$v["message"]}<br>{$v["report_details"]}";
}
}
}
if(! empty($this->response["validation_rules_report"]["items"])) {
foreach ($this->response["validation_rules_report"]["items"] as $v) {
if(! $v["valid"] && in_array($v["severity"], ["ERROR", "CRITICAL"])) {
$this->info["errori"][] = "{$v["message"]}<br>{$v["details"]}";
}
}
}
if(! empty($this->info["errori"])) {
$this->info["errori"] = base64_encode(json_encode($this->info["errori"]));
}
break;
default:
break;
}
$parameters = [
":codice" => $this->info["codice"],
":stato" => $this->info["stato"],
":errori" => $this->info["errori"],
];
$this->pdo->go("UPDATE b_guue SET stato = :stato, errori = :errori WHERE codice = :codice", $parameters);
}
}
}
curl_close($this->curl);
unset($this->header[3]);
}
}
}