Merge branch 'main' into feature/milestone3
# Conflicts: # public/userarea/import_insert.php # public/userarea/mapping_template_xls_scheme2.php # public/userarea/process_import_xls2.php
This commit is contained in:
commit
9775a12d4a
253
public/userarea/analysisModal.js
Normal file
253
public/userarea/analysisModal.js
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
let analysisMatriciMap = {};
|
||||||
|
|
||||||
|
function loadAnalysisMatrixNames() {
|
||||||
|
return $.ajax({
|
||||||
|
url: "get_matrici_db.php",
|
||||||
|
method: "GET",
|
||||||
|
dataType: "json",
|
||||||
|
})
|
||||||
|
.done(function (data) {
|
||||||
|
analysisMatriciMap = {};
|
||||||
|
|
||||||
|
(data.value || []).forEach(function (matrice) {
|
||||||
|
analysisMatriciMap[String(matrice.IdMatrice)] =
|
||||||
|
matrice.NomeMatrice || "#" + matrice.IdMatrice;
|
||||||
|
});
|
||||||
|
|
||||||
|
applyAnalysisMatrixNames();
|
||||||
|
})
|
||||||
|
.fail(function () {
|
||||||
|
analysisMatriciMap = {};
|
||||||
|
applyAnalysisMatrixNames();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyAnalysisMatrixNames() {
|
||||||
|
const modal = document.getElementById("analysisModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-matrix-item").forEach((item) => {
|
||||||
|
const matrixId = item.getAttribute("data-matrix-id");
|
||||||
|
const nameEl = item.querySelector(".analysis-matrix-name");
|
||||||
|
|
||||||
|
let matrixName = "No Matrix";
|
||||||
|
if (matrixId && matrixId !== "NO_MATRIX") {
|
||||||
|
matrixName =
|
||||||
|
analysisMatriciMap[String(matrixId)] || "#" + matrixId;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setAttribute("data-matrix-name", matrixName);
|
||||||
|
|
||||||
|
if (nameEl) {
|
||||||
|
nameEl.textContent = matrixName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-part-matrix-name").forEach((el) => {
|
||||||
|
const matrixId = el.getAttribute("data-matrix-id");
|
||||||
|
|
||||||
|
if (!matrixId || matrixId === "NO_MATRIX") {
|
||||||
|
el.textContent = "No Matrix";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.textContent =
|
||||||
|
analysisMatriciMap[String(matrixId)] || "#" + matrixId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelectedPartsInfo() {
|
||||||
|
const modal = document.getElementById("analysisModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
const checked = modal.querySelectorAll(
|
||||||
|
".analysis-part-checkbox:checked",
|
||||||
|
);
|
||||||
|
const ids = Array.from(checked).map((el) => el.value);
|
||||||
|
|
||||||
|
const countEl = modal.querySelector("#analysisSelectedPartsCount");
|
||||||
|
const idsEl = modal.querySelector("#analysisSelectedPartsIds");
|
||||||
|
|
||||||
|
if (countEl) {
|
||||||
|
countEl.textContent = `${ids.length} selected`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idsEl) {
|
||||||
|
idsEl.textContent = ids.length ? ids.join(", ") : "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-part-item").forEach((item) => {
|
||||||
|
const checkbox = item.querySelector(".analysis-part-checkbox");
|
||||||
|
if (checkbox && checkbox.checked) {
|
||||||
|
item.classList.add("part-checked");
|
||||||
|
} else {
|
||||||
|
item.classList.remove("part-checked");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPartsByMatrix(matrixId, matrixLabel) {
|
||||||
|
const modal = document.getElementById("analysisModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
const partItems = modal.querySelectorAll(".analysis-part-item");
|
||||||
|
const matrixLabelEl = modal.querySelector("#analysisCurrentMatrix");
|
||||||
|
|
||||||
|
partItems.forEach((item) => {
|
||||||
|
const itemMatrixId = item.getAttribute("data-matrix-id");
|
||||||
|
const checkbox = item.querySelector(".analysis-part-checkbox");
|
||||||
|
|
||||||
|
item.classList.remove("matrix-active");
|
||||||
|
|
||||||
|
if (itemMatrixId === String(matrixId)) {
|
||||||
|
item.classList.add("matrix-active");
|
||||||
|
if (checkbox) checkbox.checked = true;
|
||||||
|
} else {
|
||||||
|
if (checkbox) checkbox.checked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matrixLabelEl) {
|
||||||
|
matrixLabelEl.textContent = matrixLabel || "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSelectedPartsInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAnalysisSelection() {
|
||||||
|
const modal = document.getElementById("analysisModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-matrix-item").forEach((item) => {
|
||||||
|
item.classList.remove("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-part-item").forEach((item) => {
|
||||||
|
item.classList.remove("matrix-active", "part-checked");
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-part-checkbox").forEach((cb) => {
|
||||||
|
cb.checked = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const matrixLabelEl = modal.querySelector("#analysisCurrentMatrix");
|
||||||
|
if (matrixLabelEl) matrixLabelEl.textContent = "-";
|
||||||
|
|
||||||
|
updateSelectedPartsInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initAnalysisModal() {
|
||||||
|
const modal = document.getElementById("analysisModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-matrix-item").forEach((btn) => {
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
modal
|
||||||
|
.querySelectorAll(".analysis-matrix-item")
|
||||||
|
.forEach((x) => x.classList.remove("active"));
|
||||||
|
this.classList.add("active");
|
||||||
|
|
||||||
|
const matrixId = this.getAttribute("data-matrix-id");
|
||||||
|
const matrixLabel =
|
||||||
|
this.getAttribute("data-matrix-name") ||
|
||||||
|
this.textContent.trim();
|
||||||
|
|
||||||
|
selectPartsByMatrix(matrixId, matrixLabel);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.querySelectorAll(".analysis-part-checkbox").forEach((cb) => {
|
||||||
|
cb.addEventListener("change", function () {
|
||||||
|
updateSelectedPartsInfo();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const clearBtn = modal.querySelector("#analysisClearSelectionBtn");
|
||||||
|
if (clearBtn) {
|
||||||
|
clearBtn.addEventListener("click", function () {
|
||||||
|
clearAnalysisSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstActiveMatrix = modal.querySelector(
|
||||||
|
".analysis-matrix-item.active",
|
||||||
|
);
|
||||||
|
if (firstActiveMatrix) {
|
||||||
|
const matrixId = firstActiveMatrix.getAttribute("data-matrix-id");
|
||||||
|
const matrixLabel =
|
||||||
|
firstActiveMatrix.getAttribute("data-matrix-name") ||
|
||||||
|
firstActiveMatrix.textContent.trim();
|
||||||
|
|
||||||
|
selectPartsByMatrix(matrixId, matrixLabel);
|
||||||
|
} else {
|
||||||
|
updateSelectedPartsInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPEN ANALYSIS MODAL FROM PARTS MODAL BUTTON
|
||||||
|
$(document).on("click", ".open-analysis-modal-btn", function () {
|
||||||
|
const partsModal = document.getElementById("partsModal");
|
||||||
|
const iddatadb = $("#partsModal").data("iddatadb");
|
||||||
|
|
||||||
|
if (!iddatadb) {
|
||||||
|
console.error("iddatadb not found on #partsModal");
|
||||||
|
alert("iddatadb not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "modal_analysis.php",
|
||||||
|
method: "GET",
|
||||||
|
data: { iddatadb: iddatadb },
|
||||||
|
success: function (response) {
|
||||||
|
$("#analysisModalContainer").html(response);
|
||||||
|
|
||||||
|
const modalElement = document.getElementById("analysisModal");
|
||||||
|
if (!modalElement) {
|
||||||
|
console.error("Analysis modal not found: #analysisModal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let modal = bootstrap.Modal.getInstance(modalElement);
|
||||||
|
if (!modal) {
|
||||||
|
modal = new bootstrap.Modal(modalElement, {
|
||||||
|
backdrop: true,
|
||||||
|
keyboard: true,
|
||||||
|
focus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAnalysisMatrixNames().always(function () {
|
||||||
|
initAnalysisModal();
|
||||||
|
modal.show();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.error("Error loading analysis modal:", error);
|
||||||
|
alert("Error loading analysis modal: " + error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// CLEANUP ON CLOSE
|
||||||
|
$(document).on("hidden.bs.modal", "#analysisModal", function () {
|
||||||
|
const modalElement = document.getElementById("analysisModal");
|
||||||
|
if (modalElement) {
|
||||||
|
const modal = bootstrap.Modal.getInstance(modalElement);
|
||||||
|
if (modal) modal.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#analysisModalContainer").empty();
|
||||||
|
|
||||||
|
// keep parts modal alive, but remove extra backdrop leftovers
|
||||||
|
$(".modal-backdrop").last().remove();
|
||||||
|
|
||||||
|
if ($("#partsModal").hasClass("show")) {
|
||||||
|
$("body").addClass("modal-open");
|
||||||
|
} else {
|
||||||
|
$("body").removeClass("modal-open").css("padding-right", "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
File diff suppressed because one or more lines are too long
@ -1,26 +1,27 @@
|
|||||||
<?php include('include/headscript.php');
|
<?php include('include/headscript.php');
|
||||||
|
|
||||||
// Controlla se è stato passato un ID valido
|
// Check if a valid ID was provided
|
||||||
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Invalid ID"));
|
header("Location: templates_dashboard.php?status=error&message=" . urlencode("Invalid ID"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = intval($_GET['id']); // Sanifica l'ID
|
$id = intval($_GET['id']);
|
||||||
|
|
||||||
// Recupera il template dal database
|
// Retrieve template from database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
$stmt = $pdo->prepare("SELECT * FROM excel_templates WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT * FROM excel_templates WHERE id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$template) {
|
if (!$template) {
|
||||||
header("Location: template_dashboard.php?status=error&message=" . urlencode("Template not found"));
|
header("Location: templates_dashboard.php?status=error&message=" . urlencode("Template not found"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera tutte le routine dal database
|
// Retrieve all routines
|
||||||
$stmt = $pdo->prepare("SELECT * FROM routine");
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@ -34,7 +35,6 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<!-- Include jQuery prima di Select2 -->
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<title>Edit Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Edit Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
@ -44,19 +44,22 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
|
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">Update XLS Template</h5>
|
<h5 class="mb-0">Update Template</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-2">Edit the following form in order to update the selected import XLS template</p>
|
<p class="mb-2">Edit the following form in order to update the selected import template</p>
|
||||||
<p class="mb-2">Mandatory Fields</p>
|
<p class="mb-2">Mandatory Fields</p>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Source Type</li>
|
||||||
<li>Schema</li>
|
<li>Schema and Client</li>
|
||||||
|
<li>Row Header and Column Header only for XLS templates</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -69,34 +72,44 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<form id="editTemplateForm" method="POST">
|
<form id="editTemplateForm" method="POST">
|
||||||
<input type="hidden" name="id" value="<?php echo $template['id']; ?>">
|
<input type="hidden" name="id" value="<?php echo (int)$template['id']; ?>">
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="name" class="form-control" value="<?php echo htmlspecialchars($template['name']); ?>" required>
|
<input type="text" name="name" class="form-control" value="<?php echo htmlspecialchars($template['name'] ?? ''); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Source Type *</label>
|
||||||
|
<select name="source_type" id="sourceType" class="form-control" required>
|
||||||
|
<option value="XLS" <?php echo (($template['source_type'] ?? 'XLS') === 'XLS') ? 'selected' : ''; ?>>XLS</option>
|
||||||
|
<option value="API" <?php echo (($template['source_type'] ?? 'XLS') === 'API') ? 'selected' : ''; ?>>API</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Choose the source used by this template</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="headerRowWrapper">
|
||||||
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="number" name="header_row" class="form-control" value="<?php echo $template['header_row']; ?>" required>
|
<input type="number" name="header_row" id="headerRow" class="form-control" value="<?php echo htmlspecialchars($template['header_row'] ?? ''); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3" id="startColumnWrapper">
|
||||||
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?>*</label>
|
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="start_column" class="form-control" value="<?php echo htmlspecialchars($template['start_column']); ?>" required>
|
<input type="text" name="start_column" id="startColumn" class="form-control" value="<?php echo htmlspecialchars($template['start_column'] ?? ''); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></label>
|
<label class="form-label"><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></label>
|
||||||
<textarea name="description" class="form-control"><?php echo htmlspecialchars($template['description']); ?></textarea>
|
<textarea name="description" class="form-control"><?php echo htmlspecialchars($template['description'] ?? ''); ?></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($desttable, ENT_QUOTES, 'UTF-8'); ?>*</label>
|
<label class="form-label"><?= htmlspecialchars($desttable, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="target_table" class="form-control" value="<?php echo htmlspecialchars($template['target_table']); ?>" readonly required>
|
<input type="text" name="target_table" class="form-control" value="<?php echo htmlspecialchars($template['target_table'] ?? 'datadb'); ?>" readonly required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -110,12 +123,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Background Color</label>
|
<label class="form-label">Button Background Color</label>
|
||||||
<input type="color" name="button_bg_color" class="form-control" value="<?php echo htmlspecialchars($template['button_bg_color'] ?? '#007bff'); ?>">
|
<input type="color" name="button_bg_color" class="form-control form-control-color" value="<?php echo htmlspecialchars($template['button_bg_color'] ?? '#007bff'); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Text Color</label>
|
<label class="form-label">Button Text Color</label>
|
||||||
<input type="color" name="button_text_color" class="form-control" value="<?php echo htmlspecialchars($template['button_text_color'] ?? '#ffffff'); ?>">
|
<input type="color" name="button_text_color" class="form-control form-control-color" value="<?php echo htmlspecialchars($template['button_text_color'] ?? '#ffffff'); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -128,7 +141,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<select name="client_id" id="clientSelect" class="form-control" required>
|
<select name="client_id" id="clientSelect" class="form-control" required>
|
||||||
<option value="">Select a client...</option>
|
<option value="">Select a client...</option>
|
||||||
</select>
|
</select>
|
||||||
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Loading clients...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -136,7 +149,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
||||||
<option value="">Select a schema...</option>
|
<option value="">Select a schema...</option>
|
||||||
</select>
|
</select>
|
||||||
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Caricamento schemi in corso...</span>
|
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Loading schemas...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -144,11 +157,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<select name="idroutine" id="routineSelect" class="form-control">
|
<select name="idroutine" id="routineSelect" class="form-control">
|
||||||
<option value="">Select a routine...</option>
|
<option value="">Select a routine...</option>
|
||||||
<?php foreach ($routines as $routine): ?>
|
<?php foreach ($routines as $routine): ?>
|
||||||
<option value="<?php echo $routine['idroutine']; ?>" <?php echo ($template['idroutine'] ?? '') == $routine['idroutine'] ? 'selected' : ''; ?>>
|
<option value="<?php echo $routine['idroutine']; ?>" <?php echo (($template['idroutine'] ?? '') == $routine['idroutine']) ? 'selected' : ''; ?>>
|
||||||
<?php echo htmlspecialchars($routine['name']); ?>
|
<?php echo htmlspecialchars($routine['name']); ?>
|
||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div id="routineDetails" class="mt-2" style="display: none;">
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<h6>Routine Details</h6>
|
<h6>Routine Details</h6>
|
||||||
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
||||||
@ -166,8 +180,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
@ -175,9 +191,8 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
// Verifica che jQuery sia caricato
|
|
||||||
if (typeof jQuery === 'undefined') {
|
if (typeof jQuery === 'undefined') {
|
||||||
alert("Errore: jQuery non è caricato. Contatta l'amministratore.");
|
alert("Error: jQuery is not loaded.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,12 +207,15 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const routineAction2 = document.getElementById("routineAction2");
|
const routineAction2 = document.getElementById("routineAction2");
|
||||||
const routineAction3 = document.getElementById("routineAction3");
|
const routineAction3 = document.getElementById("routineAction3");
|
||||||
|
|
||||||
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
const sourceType = document.getElementById("sourceType");
|
||||||
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
const headerRowWrapper = document.getElementById("headerRowWrapper");
|
||||||
return;
|
const startColumnWrapper = document.getElementById("startColumnWrapper");
|
||||||
}
|
const headerRow = document.getElementById("headerRow");
|
||||||
|
const startColumn = document.getElementById("startColumn");
|
||||||
|
|
||||||
|
const selectedClientId = <?php echo json_encode((int)($template['idclient'] ?? 0)); ?>;
|
||||||
|
const selectedSchemaId = <?php echo json_encode((int)($template['idschema'] ?? 0)); ?>;
|
||||||
|
|
||||||
// Inizializza Select2
|
|
||||||
$('#clientSelect').select2({
|
$('#clientSelect').select2({
|
||||||
placeholder: "Search for a client...",
|
placeholder: "Search for a client...",
|
||||||
allowClear: true
|
allowClear: true
|
||||||
@ -213,108 +231,164 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
allowClear: true
|
allowClear: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Carica i clienti
|
function updateSourceFields() {
|
||||||
|
const selectedSource = sourceType.value;
|
||||||
|
|
||||||
|
if (selectedSource === 'API') {
|
||||||
|
headerRowWrapper.style.opacity = '0.6';
|
||||||
|
startColumnWrapper.style.opacity = '0.6';
|
||||||
|
|
||||||
|
headerRow.required = false;
|
||||||
|
startColumn.required = false;
|
||||||
|
|
||||||
|
headerRow.disabled = true;
|
||||||
|
startColumn.disabled = true;
|
||||||
|
} else {
|
||||||
|
headerRowWrapper.style.opacity = '1';
|
||||||
|
startColumnWrapper.style.opacity = '1';
|
||||||
|
|
||||||
|
headerRow.required = true;
|
||||||
|
startColumn.required = true;
|
||||||
|
|
||||||
|
headerRow.disabled = false;
|
||||||
|
startColumn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceType.addEventListener('change', updateSourceFields);
|
||||||
|
updateSourceFields();
|
||||||
|
|
||||||
async function loadClients() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Loading clients...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `HTTP error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("clientSelect");
|
const select = document.getElementById("clientSelect");
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
|
||||||
data.value.forEach(client => {
|
data.value.forEach(client => {
|
||||||
const nome = client.Nominativo || "Nome non disponibile";
|
const nome = client.Nominativo || "Name not available";
|
||||||
const id = client.IdCliente || "ID non disponibile";
|
const id = client.IdCliente || "";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
if (parseInt(id) === parseInt(<?php echo json_encode($template['idclient'] ?? 0); ?>)) {
|
|
||||||
|
if (parseInt(id) === parseInt(selectedClientId)) {
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
clientLoadingStatus.textContent = "Clienti caricati.";
|
clientLoadingStatus.textContent = "Clients loaded.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Loading error.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Impossibile caricare i clienti: " + error.message,
|
text: "Unable to load clients: " + error.message,
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
|
setTimeout(() => clientLoadingStatus.style.display = 'none', 1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carica gli schemi
|
|
||||||
async function loadSchemas() {
|
async function loadSchemas() {
|
||||||
try {
|
try {
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
schemaLoadingStatus.textContent = 'Loading schemas...';
|
||||||
|
|
||||||
const response = await fetch("get_schemi.php", {
|
const response = await fetch("get_schemi.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `HTTP error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("schemaSelect");
|
const select = document.getElementById("schemaSelect");
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
data.value.forEach(schema => {
|
|
||||||
const nome = schema.Nome || "Nome non disponibile";
|
const sortedSchemas = [...data.value].sort((a, b) => {
|
||||||
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
const nomeA = (a.Nome || "").trim().toLowerCase();
|
||||||
|
const nomeB = (b.Nome || "").trim().toLowerCase();
|
||||||
|
return nomeA.localeCompare(nomeB, 'it', {
|
||||||
|
sensitivity: 'base'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
sortedSchemas.forEach(schema => {
|
||||||
|
const nome = schema.Nome || "Name not available";
|
||||||
|
const id = schema.IdSchemaCustomFields || "";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
if (parseInt(id) === parseInt(<?php echo json_encode($template['idschema'] ?? 0); ?>)) {
|
|
||||||
|
if (parseInt(id) === parseInt(selectedSchemaId)) {
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
schemaLoadingStatus.textContent = "Schemas loaded.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
schemaLoadingStatus.textContent = "Loading error.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Impossibile caricare gli schemi: " + error.message,
|
text: "Unable to load schemas: " + error.message,
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => schemaLoadingStatus.style.display = 'none', 2000);
|
setTimeout(() => schemaLoadingStatus.style.display = 'none', 1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carica i dati
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
await loadClients();
|
await loadClients();
|
||||||
await loadSchemas();
|
await loadSchemas();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Errore nel caricamento dei dati: " + error.message,
|
text: "Error while loading data: " + error.message,
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
|
|
||||||
// Routine dettagli
|
|
||||||
const routines = <?php echo json_encode($routines); ?>;
|
const routines = <?php echo json_encode($routines); ?>;
|
||||||
|
|
||||||
function updateRoutineDetails() {
|
function updateRoutineDetails() {
|
||||||
const selectedId = routineSelect.value;
|
const selectedId = routineSelect.value;
|
||||||
routineDetails.style.display = selectedId ? 'block' : 'none';
|
routineDetails.style.display = selectedId ? 'block' : 'none';
|
||||||
|
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
const routine = routines.find(r => r.idroutine == selectedId);
|
const routine = routines.find(r => r.idroutine == selectedId);
|
||||||
|
|
||||||
if (routine) {
|
if (routine) {
|
||||||
routineName.textContent = routine.name || 'N/A';
|
routineName.textContent = routine.name || 'N/A';
|
||||||
routineDescription.textContent = routine.description || 'N/A';
|
routineDescription.textContent = routine.description || 'N/A';
|
||||||
@ -336,10 +410,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
routineAction3.textContent = '';
|
routineAction3.textContent = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routineSelect.addEventListener('change', updateRoutineDetails);
|
|
||||||
updateRoutineDetails(); // Inizializza dettagli se una routine è preselezionata
|
|
||||||
|
|
||||||
// Submit del form
|
routineSelect.addEventListener('change', updateRoutineDetails);
|
||||||
|
updateRoutineDetails();
|
||||||
|
|
||||||
form.addEventListener("submit", function(e) {
|
form.addEventListener("submit", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -351,8 +425,8 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
if (!clientId) {
|
if (!clientId) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Per favore seleziona un cliente.",
|
text: "Please select a client.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
@ -373,8 +447,8 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
if (!schemaId) {
|
if (!schemaId) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Per favore seleziona uno schema.",
|
text: "Please select a schema.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
@ -387,10 +461,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("idschema", schemaId);
|
formData.append("idschema", schemaId);
|
||||||
formData.append("schemaname", schemaName);
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
// Aggiungi idroutine
|
|
||||||
const routineId = routineSelect.value;
|
const routineId = routineSelect.value;
|
||||||
formData.append("idroutine", routineId);
|
formData.append("idroutine", routineId);
|
||||||
|
|
||||||
@ -402,8 +476,8 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Successo!",
|
title: "Success!",
|
||||||
text: "Template aggiornato con successo!",
|
text: "Template updated successfully!",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
@ -411,17 +485,17 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: data.message,
|
text: data.message,
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(() => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Error!",
|
||||||
text: "Si è verificato un errore imprevisto.",
|
text: "An unexpected error occurred.",
|
||||||
icon: "error",
|
icon: "error",
|
||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
|
|||||||
@ -318,3 +318,13 @@
|
|||||||
2026-03-19 09:50:34 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
2026-03-19 09:50:34 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
||||||
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
||||||
|
2026-03-26 10:57:18 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:41 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:56 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:58:11 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
|||||||
@ -107,9 +107,10 @@ try {
|
|||||||
|
|
||||||
// 🔹 STEP 3: Fetch Parts (including idmatrice and part id for custom fields)
|
// 🔹 STEP 3: Fetch Parts (including idmatrice and part id for custom fields)
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT id AS part_id, part_number, part_description, material, color, mix, idmatrice, dateexpiry
|
SELECT id AS part_id, part_number, part_description, material, color, mix, idmatrice, dateexpiry
|
||||||
FROM identification_parts
|
FROM identification_parts
|
||||||
WHERE iddatadb = :iddatadb
|
WHERE iddatadb = :iddatadb
|
||||||
|
ORDER BY CAST(part_number AS UNSIGNED) ASC, part_number ASC
|
||||||
");
|
");
|
||||||
$stmt->execute(['iddatadb' => $iddatadb]);
|
$stmt->execute(['iddatadb' => $iddatadb]);
|
||||||
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@ -512,7 +513,13 @@ try {
|
|||||||
// 🔹 STEP 9.5: Importazione da CommessaWeb a Commessa (commentato come richiesto)
|
// 🔹 STEP 9.5: Importazione da CommessaWeb a Commessa (commentato come richiesto)
|
||||||
// Supplier call: POST api/odata/CommessaWeb(XXX)/ImportaCommessa
|
// Supplier call: POST api/odata/CommessaWeb(XXX)/ImportaCommessa
|
||||||
|
|
||||||
$importPayload = ["IdUtente" => 285]; // user-id
|
$importUserId = (!empty($lims_global_user_id) && is_numeric($lims_global_user_id))
|
||||||
|
? (int) $lims_global_user_id
|
||||||
|
: 285;
|
||||||
|
|
||||||
|
$importPayload = [
|
||||||
|
"IdUtente" => $importUserId
|
||||||
|
];
|
||||||
$importResult = $api->post("CommessaWeb({$commessaId})/ImportaCommessa", $importPayload);
|
$importResult = $api->post("CommessaWeb({$commessaId})/ImportaCommessa", $importPayload);
|
||||||
|
|
||||||
$importPayloadLog = json_encode($importPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
$importPayloadLog = json_encode($importPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
|
|||||||
50
public/userarea/get_analisi.php
Normal file
50
public/userarea/get_analisi.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Endpoint per recuperare le Analisi
|
||||||
|
$endpoint = 'Analisi';
|
||||||
|
|
||||||
|
// Opzioni OData
|
||||||
|
$options = [
|
||||||
|
// Restituisce solo i campi principali utili
|
||||||
|
'$select' => 'IdAnalisi,Codice,NomeAnalisi,ClientiAbilitati,MatriciAbilitate,IsGenerico,Tipo,ParentKey,SelezionabileSuWeb',
|
||||||
|
|
||||||
|
// Solo analisi effettivamente selezionabili sul web
|
||||||
|
'$filter' => 'SelezionabileSuWeb eq true',
|
||||||
|
|
||||||
|
// Ordinamento alfabetico per nome analisi
|
||||||
|
'$orderby' => 'NomeAnalisi asc'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Debug: salva URL usato
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_analisi_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
// Salva il JSON in locale
|
||||||
|
file_put_contents(__DIR__ . '/analisi_response.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||||
|
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/analisi_error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
68
public/userarea/get_analisi_by_cliente_matrice.php
Normal file
68
public/userarea/get_analisi_by_cliente_matrice.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$idCliente = isset($_GET['id_cliente']) ? (int)$_GET['id_cliente'] : 0;
|
||||||
|
$idMatrice = isset($_GET['id_matrice']) ? (int)$_GET['id_matrice'] : 0;
|
||||||
|
$debug = isset($_GET['debug']) ? (int)$_GET['debug'] : 0;
|
||||||
|
|
||||||
|
if ($idCliente <= 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Missing or invalid id_cliente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
if ($idMatrice > 0) {
|
||||||
|
$expandExpr = "AnalisiAbilitate(\$filter=Matrice/IdMatrice eq $idMatrice)";
|
||||||
|
} else {
|
||||||
|
$expandExpr = "AnalisiAbilitate";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode only the $expand expression because it contains spaces, slash and parentheses
|
||||||
|
$expandEncoded = rawurlencode($expandExpr);
|
||||||
|
$endpoint = "Cliente($idCliente)?\$expand={$expandEncoded}";
|
||||||
|
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$full_url = $base_url . $endpoint;
|
||||||
|
|
||||||
|
file_put_contents(__DIR__ . '/last_url_analisi.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
$data = $api->get($endpoint, []);
|
||||||
|
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/analisi_by_cliente_matrice_response.json',
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($debug === 1) {
|
||||||
|
echo json_encode([
|
||||||
|
'endpoint' => $endpoint,
|
||||||
|
'full_url' => $full_url,
|
||||||
|
'raw_response' => $data
|
||||||
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$analisi = $data['AnalisiAbilitate'] ?? [];
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'value' => $analisi,
|
||||||
|
'count' => is_array($analisi) ? count($analisi) : 0
|
||||||
|
], JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log_analisi.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
56
public/userarea/get_analisi_by_matrice.php
Normal file
56
public/userarea/get_analisi_by_matrice.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$idMatrice = isset($_GET['id_matrice']) ? (int)$_GET['id_matrice'] : 0;
|
||||||
|
|
||||||
|
if ($idMatrice <= 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Missing or invalid id_matrice']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OData hypothesis:
|
||||||
|
* - Expand enabled matrices
|
||||||
|
* - Return only selectable analyses
|
||||||
|
* - Include generic analyses OR analyses enabled for the given matrix
|
||||||
|
*
|
||||||
|
* This endpoint must be verified against the real VisualLims API metadata.
|
||||||
|
*/
|
||||||
|
$filter = rawurlencode("SelezionabileSuWeb eq true and (IsGenerico eq true or MatriciAbilitate/any(m:m/IdMatrice eq $idMatrice))");
|
||||||
|
$expand = rawurlencode("MatriciAbilitate");
|
||||||
|
$endpoint = "Analisi?\$top=10";
|
||||||
|
|
||||||
|
// Debug URL
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$full_url = $base_url . $endpoint;
|
||||||
|
file_put_contents(__DIR__ . '/last_url_analisi.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
$data = $api->get($endpoint, []);
|
||||||
|
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/analisi_by_matrice_response.json',
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
$analisi = $data['value'] ?? [];
|
||||||
|
|
||||||
|
echo json_encode(['value' => $analisi], JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log_analisi.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
103
public/userarea/get_clienti_raw.php
Normal file
103
public/userarea/get_clienti_raw.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// Disable PHP error display
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
|
||||||
|
|
||||||
|
// In simulate mode: return fake clients built from idclient values already in datadb.
|
||||||
|
if (($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true') {
|
||||||
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->query("
|
||||||
|
SELECT DISTINCT idclient
|
||||||
|
FROM datadb
|
||||||
|
WHERE idclient IS NOT NULL
|
||||||
|
AND idclient > 0
|
||||||
|
ORDER BY idclient ASC
|
||||||
|
");
|
||||||
|
|
||||||
|
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
$fakeClients = array_map(fn($id) => [
|
||||||
|
'IdCliente' => (int) $id,
|
||||||
|
'Nominativo' => "Cliente Simulato {$id}",
|
||||||
|
'CodiceCliente' => "SIM_{$id}",
|
||||||
|
], $ids);
|
||||||
|
|
||||||
|
echo json_encode(['value' => $fakeClients], JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint senza filtri: recupera tutto
|
||||||
|
$endpoint = 'Cliente?$top=50';
|
||||||
|
|
||||||
|
// Funzione per eseguire la chiamata con retry
|
||||||
|
function makeApiRequest($api, $endpoint, $maxRetries = 3)
|
||||||
|
{
|
||||||
|
for ($retry = 0; $retry < $maxRetries; $retry++) {
|
||||||
|
try {
|
||||||
|
$data = $api->get($endpoint);
|
||||||
|
|
||||||
|
// Save response for debug
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/clienti_response.json',
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errorMessage = $e->getMessage();
|
||||||
|
|
||||||
|
// Retry only for specific auth/token related issue
|
||||||
|
if (
|
||||||
|
strpos($errorMessage, 'HTTP 400') !== false &&
|
||||||
|
strpos($errorMessage, 'Cannot persist the object') !== false
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (method_exists($api, 'refreshToken')) {
|
||||||
|
$api->refreshToken();
|
||||||
|
error_log("Tentativo {$retry}: refresh token eseguito per endpoint {$endpoint}");
|
||||||
|
} else {
|
||||||
|
throw new Exception('Il metodo refreshToken() non esiste in VisualLimsApiClient');
|
||||||
|
}
|
||||||
|
} catch (Exception $refreshEx) {
|
||||||
|
error_log("Errore durante il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
throw new Exception("Impossibile eseguire il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(500000); // 500ms
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Massimo numero di tentativi raggiunto per {$endpoint}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Esegui la chiamata
|
||||||
|
$data = makeApiRequest($api, $endpoint);
|
||||||
|
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
|
||||||
|
$errorResponse = [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
];
|
||||||
|
|
||||||
|
error_log("Errore in get_clienti.php: " . json_encode($errorResponse, JSON_UNESCAPED_UNICODE));
|
||||||
|
echo json_encode($errorResponse, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
@ -1168,6 +1168,16 @@ function fixedDefaultValue(array $f): string
|
|||||||
$key = $f['fixed_field_key'];
|
$key = $f['fixed_field_key'];
|
||||||
$label = $slugMapping[$key] ?? $key;
|
$label = $slugMapping[$key] ?? $key;
|
||||||
|
|
||||||
|
if ($key === 'ClienteFornitore') {
|
||||||
|
$label = 'Fornitore';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($key === 'ClienteAnalisi') {
|
||||||
|
$label = 'Buyer';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 180px; position: relative;'>"
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 180px; position: relative;'>"
|
||||||
. htmlspecialchars($label) .
|
. htmlspecialchars($label) .
|
||||||
"<div class='resizer'></div></div>";
|
"<div class='resizer'></div></div>";
|
||||||
@ -1416,6 +1426,7 @@ function fixedDefaultValue(array $f): string
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div id="partsModalContainer"></div>
|
<div id="partsModalContainer"></div>
|
||||||
|
<div id="analysisModalContainer"></div>
|
||||||
<div id="annotationsModalContainer"></div>
|
<div id="annotationsModalContainer"></div>
|
||||||
<?php include 'photos_functions.php'; ?>
|
<?php include 'photos_functions.php'; ?>
|
||||||
</div>
|
</div>
|
||||||
@ -1434,6 +1445,7 @@ function fixedDefaultValue(array $f): string
|
|||||||
<script src="photos.js"></script>
|
<script src="photos.js"></script>
|
||||||
<script src="annotationsModal.js"></script>
|
<script src="annotationsModal.js"></script>
|
||||||
<script src="partsTable.js"></script>
|
<script src="partsTable.js"></script>
|
||||||
|
<script src="analysisModal.js"></script>
|
||||||
<script src="tracking.js"></script>
|
<script src="tracking.js"></script>
|
||||||
<script src="export_to_lims.js"></script>
|
<script src="export_to_lims.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -158,4 +158,4 @@ $_SESSION['inserted_ids'] = $insertedIds;
|
|||||||
|
|
||||||
header("Location: imported.php?id=" . urlencode($template_id) . "&importref=" . urlencode($importReferenceCode));
|
header("Location: imported.php?id=" . urlencode($template_id) . "&importref=" . urlencode($importReferenceCode));
|
||||||
exit;
|
exit;
|
||||||
?>
|
?>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?php include('include/headscript.php');
|
<?php include('include/headscript.php');
|
||||||
|
|
||||||
// Recupera tutte le routine dal database
|
// Retrieve all routines from database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
$stmt = $pdo->prepare("SELECT * FROM routine");
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
@ -18,26 +18,29 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<title>Insert XLS Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Insert Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
|
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">Insert new XLS Template</h5>
|
<h5 class="mb-0">Insert New Template</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-2">Fill the following form in order to create a new import XLS template</p>
|
<p class="mb-2">Fill the following form in order to create a new import template</p>
|
||||||
<p class="mb-2">Mandatory Fields</p>
|
<p class="mb-2">Mandatory Fields</p>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Source Type</li>
|
||||||
<li>Schema and client</li>
|
<li>Schema and Client</li>
|
||||||
|
<li>Row Header and Column Header only for XLS templates</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -50,22 +53,33 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<form id="insertTemplateForm" method="POST">
|
<form id="insertTemplateForm" method="POST">
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="name" class="form-control" required>
|
<input type="text" name="name" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label">Source Type *</label>
|
||||||
<input type="number" name="header_row" class="form-control" required>
|
<select name="source_type" id="sourceType" class="form-control" required>
|
||||||
|
<option value="XLS" selected>XLS</option>
|
||||||
|
<option value="API">API</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Choose the source used by this template</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3" id="headerRowWrapper">
|
||||||
|
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
|
<input type="number" name="header_row" id="headerRow" class="form-control" value="1" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="startColumnWrapper">
|
||||||
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="start_column" class="form-control" required>
|
<input type="text" name="start_column" id="startColumn" class="form-control" value="A" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -86,12 +100,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Background Color</label>
|
<label class="form-label">Button Background Color</label>
|
||||||
<input type="color" name="button_bg_color" class="form-control" value="#007bff">
|
<input type="color" name="button_bg_color" class="form-control form-control-color" value="#007bff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Text Color</label>
|
<label class="form-label">Button Text Color</label>
|
||||||
<input type="color" name="button_text_color" class="form-control" value="#ffffff">
|
<input type="color" name="button_text_color" class="form-control form-control-color" value="#ffffff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -125,6 +139,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div id="routineDetails" class="mt-2" style="display: none;">
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<h6>Routine Details</h6>
|
<h6>Routine Details</h6>
|
||||||
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
||||||
@ -142,8 +157,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
@ -167,6 +184,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const routineAction2 = document.getElementById("routineAction2");
|
const routineAction2 = document.getElementById("routineAction2");
|
||||||
const routineAction3 = document.getElementById("routineAction3");
|
const routineAction3 = document.getElementById("routineAction3");
|
||||||
|
|
||||||
|
const sourceType = document.getElementById("sourceType");
|
||||||
|
const headerRowWrapper = document.getElementById("headerRowWrapper");
|
||||||
|
const startColumnWrapper = document.getElementById("startColumnWrapper");
|
||||||
|
const headerRow = document.getElementById("headerRow");
|
||||||
|
const startColumn = document.getElementById("startColumn");
|
||||||
|
|
||||||
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
||||||
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
||||||
return;
|
return;
|
||||||
@ -187,30 +210,66 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
allowClear: true
|
allowClear: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateSourceFields() {
|
||||||
|
const selectedSource = sourceType.value;
|
||||||
|
|
||||||
|
if (selectedSource === 'API') {
|
||||||
|
headerRowWrapper.style.opacity = '0.6';
|
||||||
|
startColumnWrapper.style.opacity = '0.6';
|
||||||
|
|
||||||
|
headerRow.required = false;
|
||||||
|
startColumn.required = false;
|
||||||
|
|
||||||
|
headerRow.disabled = true;
|
||||||
|
startColumn.disabled = true;
|
||||||
|
} else {
|
||||||
|
headerRowWrapper.style.opacity = '1';
|
||||||
|
startColumnWrapper.style.opacity = '1';
|
||||||
|
|
||||||
|
headerRow.required = true;
|
||||||
|
startColumn.required = true;
|
||||||
|
|
||||||
|
headerRow.disabled = false;
|
||||||
|
startColumn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceType.addEventListener('change', updateSourceFields);
|
||||||
|
updateSourceFields();
|
||||||
|
|
||||||
async function loadClients() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("clientSelect");
|
const select = document.getElementById("clientSelect");
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
|
||||||
data.value.forEach(client => {
|
data.value.forEach(client => {
|
||||||
const nome = client.Nominativo || "Nome non disponibile";
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
const id = client.IdCliente || "ID non disponibile";
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
clientLoadingStatus.textContent = "Clienti caricati.";
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare i clienti: " + error.message,
|
text: "Impossibile caricare i clienti: " + error.message,
|
||||||
@ -226,26 +285,43 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
try {
|
try {
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_schemi.php", {
|
const response = await fetch("get_schemi.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("schemaSelect");
|
const select = document.getElementById("schemaSelect");
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
data.value.forEach(schema => {
|
|
||||||
|
const sortedSchemas = [...data.value].sort((a, b) => {
|
||||||
|
const nomeA = (a.Nome || "").trim().toLowerCase();
|
||||||
|
const nomeB = (b.Nome || "").trim().toLowerCase();
|
||||||
|
return nomeA.localeCompare(nomeB, 'it', {
|
||||||
|
sensitivity: 'base'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
sortedSchemas.forEach(schema => {
|
||||||
const nome = schema.Nome || "Nome non disponibile";
|
const nome = schema.Nome || "Nome non disponibile";
|
||||||
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
schemaLoadingStatus.textContent = "Schemi caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare gli schemi: " + error.message,
|
text: "Impossibile caricare gli schemi: " + error.message,
|
||||||
@ -270,6 +346,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
|
|
||||||
const routines = <?php echo json_encode($routines); ?>;
|
const routines = <?php echo json_encode($routines); ?>;
|
||||||
@ -277,8 +354,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
function updateRoutineDetails() {
|
function updateRoutineDetails() {
|
||||||
const selectedId = routineSelect.value;
|
const selectedId = routineSelect.value;
|
||||||
routineDetails.style.display = selectedId ? 'block' : 'none';
|
routineDetails.style.display = selectedId ? 'block' : 'none';
|
||||||
|
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
const routine = routines.find(r => r.idroutine == selectedId);
|
const routine = routines.find(r => r.idroutine == selectedId);
|
||||||
|
|
||||||
if (routine) {
|
if (routine) {
|
||||||
routineName.textContent = routine.name || 'N/A';
|
routineName.textContent = routine.name || 'N/A';
|
||||||
routineDescription.textContent = routine.description || 'N/A';
|
routineDescription.textContent = routine.description || 'N/A';
|
||||||
@ -300,6 +379,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
routineAction3.textContent = '';
|
routineAction3.textContent = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routineSelect.addEventListener('change', updateRoutineDetails);
|
routineSelect.addEventListener('change', updateRoutineDetails);
|
||||||
updateRoutineDetails();
|
updateRoutineDetails();
|
||||||
|
|
||||||
@ -350,6 +430,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("idschema", schemaId);
|
formData.append("idschema", schemaId);
|
||||||
formData.append("schemaname", schemaName);
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
|
|||||||
@ -163,6 +163,12 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xls-columns option.used-option {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
color: #856404;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make Title column narrower + ellipsis */
|
/* Make Title column narrower + ellipsis */
|
||||||
#schemaFieldsTable td.title-col {
|
#schemaFieldsTable td.title-col {
|
||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
@ -749,30 +755,33 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
|
|
||||||
function updateXlsDropdowns() {
|
function updateXlsDropdowns() {
|
||||||
let usedColumns = Array.from(document.querySelectorAll('select.xls-columns'))
|
let usedColumns = Array.from(document.querySelectorAll('select.xls-columns'))
|
||||||
.filter(select => select.style.display === 'block' && select.value)
|
.map(select => select.value || select.dataset.currentXls || '')
|
||||||
.map(select => select.value)
|
.filter(Boolean)
|
||||||
.concat(usedColumnsFromDB);
|
.concat(usedColumnsFromDB);
|
||||||
|
|
||||||
|
let uniqueUsedColumns = [...new Set(usedColumns)];
|
||||||
|
|
||||||
document.querySelectorAll('select.xls-columns').forEach(select => {
|
document.querySelectorAll('select.xls-columns').forEach(select => {
|
||||||
let currentValue = select.value || select.dataset.currentXls || '';
|
let currentValue = select.value || select.dataset.currentXls || '';
|
||||||
|
|
||||||
let options = availableXlsColumns
|
let options = availableXlsColumns
|
||||||
.map((col, origIdx) => ({ col, origIdx }))
|
.map((col, origIdx) => ({ col, origIdx }))
|
||||||
.filter(({ col }) => !usedColumns.includes(col) || col === currentValue)
|
|
||||||
.map(({ col, origIdx }) => {
|
.map(({ col, origIdx }) => {
|
||||||
const clean = col.replace(/[\r\n\t]+/g, ' ').trim();
|
const clean = col.replace(/[\r\n\t]+/g, ' ').trim();
|
||||||
const isEmpty = clean === '';
|
const isEmpty = clean === '';
|
||||||
const colNum = origIdx + 1;
|
const colNum = origIdx + 1;
|
||||||
const val = isEmpty ? `__empty_${colNum}__` : clean;
|
const val = isEmpty ? `__empty_${colNum}__` : clean;
|
||||||
const label = isEmpty ? `(empty column ${colNum})` : clean;
|
const isUsed = uniqueUsedColumns.includes(col) && col !== currentValue;
|
||||||
|
const label = isEmpty
|
||||||
|
? `(empty column ${colNum})`
|
||||||
|
: (isUsed ? `⚠ ${clean} (already used)` : clean);
|
||||||
const isSelected = (isEmpty ? val === currentValue : col === currentValue) ? 'selected' : '';
|
const isSelected = (isEmpty ? val === currentValue : col === currentValue) ? 'selected' : '';
|
||||||
return `<option value="${val}" ${isSelected}>${label}</option>`;
|
return `<option value="${val}" class="${isUsed ? 'used-option' : ''}" ${isSelected}>${label}</option>`;
|
||||||
})
|
})
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
select.innerHTML = '<option value="">Select XLS Column</option>' + options;
|
select.innerHTML = '<option value="">Select XLS Column</option>' + options;
|
||||||
select.dataset.currentXls = currentValue;
|
select.dataset.currentXls = currentValue;
|
||||||
if (currentValue && !options.includes(currentValue)) {
|
|
||||||
select.value = '';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,33 +1228,6 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
checkbox.checked = !prevChecked;
|
checkbox.checked = !prevChecked;
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
} else if (event.target.classList.contains('visible-parts-checkbox')) {
|
|
||||||
const checkbox = event.target;
|
|
||||||
const mappingId = checkbox.dataset.mappingId;
|
|
||||||
const value = checkbox.checked ? 1 : 0;
|
|
||||||
|
|
||||||
fetch('update_visible_parts.php', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
template_id: <?php echo $id; ?>,
|
|
||||||
mapping_id: mappingId,
|
|
||||||
value: value
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (!data.success) {
|
|
||||||
console.error("❌ Error updating is_visible_parts:", data.message);
|
|
||||||
checkbox.checked = !checkbox.checked;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error("❌ Fetch error:", error);
|
|
||||||
checkbox.checked = !checkbox.checked;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -1285,7 +1267,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
mappedColumn = document.createElement('span');
|
mappedColumn = document.createElement('span');
|
||||||
mappedColumn.className = 'mapped-column';
|
mappedColumn.className = 'mapped-column';
|
||||||
mappedColumn.style.marginLeft = '5px';
|
mappedColumn.style.marginLeft = '5px';
|
||||||
tr.querySelector('td:nth-child(5)').appendChild(mappedColumn);
|
tr.querySelector('td:nth-child(6)').appendChild(mappedColumn);
|
||||||
}
|
}
|
||||||
if (!removeBtn) {
|
if (!removeBtn) {
|
||||||
removeBtn = document.createElement('button');
|
removeBtn = document.createElement('button');
|
||||||
@ -1293,7 +1275,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
removeBtn.textContent = 'X';
|
removeBtn.textContent = 'X';
|
||||||
removeBtn.style.marginLeft = '5px';
|
removeBtn.style.marginLeft = '5px';
|
||||||
removeBtn.setAttribute('data-id', mappingId);
|
removeBtn.setAttribute('data-id', mappingId);
|
||||||
tr.querySelector('td:nth-child(5)').appendChild(removeBtn);
|
tr.querySelector('td:nth-child(6)').appendChild(removeBtn);
|
||||||
|
|
||||||
removeBtn.addEventListener('click', function(e) {
|
removeBtn.addEventListener('click', function(e) {
|
||||||
let tr = e.target.closest('tr');
|
let tr = e.target.closest('tr');
|
||||||
|
|||||||
304
public/userarea/modal_analysis.php
Normal file
304
public/userarea/modal_analysis.php
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$iddatadb = isset($_GET['iddatadb']) ? (int)$_GET['iddatadb'] : 0;
|
||||||
|
|
||||||
|
if ($iddatadb <= 0) {
|
||||||
|
?>
|
||||||
|
<div class="modal fade" id="analysisModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-fullscreen">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Analysis</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-danger mb-0">Invalid iddatadb</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT
|
||||||
|
p.id,
|
||||||
|
p.iddatadb,
|
||||||
|
p.part_number,
|
||||||
|
p.part_description,
|
||||||
|
p.material,
|
||||||
|
p.color,
|
||||||
|
p.mix,
|
||||||
|
p.idmatrice,
|
||||||
|
p.note,
|
||||||
|
p.dateexpiry,
|
||||||
|
a.NomeMatriceTraduzione
|
||||||
|
FROM identification_parts p
|
||||||
|
LEFT JOIN auth_matrici a ON a.IdMatrice = p.idmatrice
|
||||||
|
WHERE p.iddatadb = ?
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN p.part_number IS NULL THEN 999999 ELSE p.part_number END ASC,
|
||||||
|
p.id ASC
|
||||||
|
");
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build matrix groups from parts.
|
||||||
|
* No join for now: we use idmatrice only.
|
||||||
|
*/
|
||||||
|
$matrixGroups = [];
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$matrixKey = (!empty($part['idmatrice'])) ? (string)$part['idmatrice'] : 'NO_MATRIX';
|
||||||
|
|
||||||
|
if (!isset($matrixGroups[$matrixKey])) {
|
||||||
|
$matrixGroups[$matrixKey] = [
|
||||||
|
'idmatrice' => $part['idmatrice'],
|
||||||
|
'NomeMatriceTraduzione' => $part['NomeMatriceTraduzione'] ?? '',
|
||||||
|
'parts_count' => 0,
|
||||||
|
'parts' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$matrixGroups[$matrixKey]['parts_count']++;
|
||||||
|
$matrixGroups[$matrixKey]['parts'][] = $part['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$matrixGroups = array_values($matrixGroups);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="modal fade" id="analysisModal" tabindex="-1" aria-labelledby="analysisModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" style="max-width: 96vw; width: 96vw; margin: 1.5vh auto;">
|
||||||
|
<div class="modal-content analysis-modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div>
|
||||||
|
<h5 class="modal-title mb-0" id="analysisModalLabel">Analysis - TRF <?= htmlspecialchars((string)$iddatadb, ENT_QUOTES, 'UTF-8') ?></h5>
|
||||||
|
<small class="text-muted">
|
||||||
|
Parts: <?= count($parts) ?> |
|
||||||
|
Matrices: <?= count($matrixGroups) ?>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body analysis-modal-body">
|
||||||
|
<div class="row g-3 h-100">
|
||||||
|
<!-- MATRICES -->
|
||||||
|
<div class="col-lg-3 col-md-4">
|
||||||
|
<div class="card h-100 shadow-sm">
|
||||||
|
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Matrices</strong>
|
||||||
|
<span class="badge bg-secondary"><?= count($matrixGroups) ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 analysis-scroll-area">
|
||||||
|
<div class="list-group analysis-matrix-list" id="analysisMatrixList">
|
||||||
|
<?php if (empty($matrixGroups)): ?>
|
||||||
|
<div class="text-muted small p-2">No matrices found</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($matrixGroups as $index => $group): ?>
|
||||||
|
<button type="button"
|
||||||
|
class="list-group-item list-group-item-action analysis-matrix-item <?= $index === 0 ? 'active' : '' ?>"
|
||||||
|
data-matrix-id="<?= htmlspecialchars((string)($group['idmatrice'] ?? 'NO_MATRIX'), ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
<div class="fw-semibold">
|
||||||
|
<?= htmlspecialchars(
|
||||||
|
!empty($group['NomeMatriceTraduzione'])
|
||||||
|
? $group['NomeMatriceTraduzione']
|
||||||
|
: (!empty($group['idmatrice']) ? ('Matrix without translation') : 'No Matrix'),
|
||||||
|
ENT_QUOTES,
|
||||||
|
'UTF-8'
|
||||||
|
) ?>
|
||||||
|
</div>
|
||||||
|
<div class="small text-muted">
|
||||||
|
ID: <?= !empty($group['idmatrice']) ? (int)$group['idmatrice'] : '-' ?>
|
||||||
|
</div>
|
||||||
|
<div class="small text-muted">
|
||||||
|
Parts linked: <?= (int)$group['parts_count'] ?>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PARTS -->
|
||||||
|
<div class="col-lg-4 col-md-8">
|
||||||
|
<div class="card h-100 shadow-sm">
|
||||||
|
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Parts</strong>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="analysisClearSelectionBtn">Clear</button>
|
||||||
|
<span class="badge bg-primary" id="analysisSelectedPartsCount">0 selected</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-2 analysis-scroll-area">
|
||||||
|
<div class="list-group analysis-parts-list" id="analysisPartsList">
|
||||||
|
<?php if (empty($parts)): ?>
|
||||||
|
<div class="text-muted small p-2">No parts found</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($parts as $part): ?>
|
||||||
|
<?php
|
||||||
|
$matrixId = !empty($part['idmatrice']) ? (string)$part['idmatrice'] : 'NO_MATRIX';
|
||||||
|
$partLabel = trim(($part['part_number'] !== null ? ('Part ' . $part['part_number']) : 'Part') . ' - ' . ($part['part_description'] ?? ''));
|
||||||
|
?>
|
||||||
|
<div class="list-group-item analysis-part-item"
|
||||||
|
data-part-id="<?= (int)$part['id'] ?>"
|
||||||
|
data-matrix-id="<?= htmlspecialchars($matrixId, ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
<div class="d-flex align-items-start gap-2">
|
||||||
|
<input type="checkbox"
|
||||||
|
class="form-check-input mt-1 analysis-part-checkbox"
|
||||||
|
value="<?= (int)$part['id'] ?>">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<div class="fw-semibold">
|
||||||
|
<?= htmlspecialchars($partLabel, ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small text-muted mt-1">
|
||||||
|
Matrix:
|
||||||
|
<strong>
|
||||||
|
<?= htmlspecialchars(
|
||||||
|
!empty($part['NomeMatriceTraduzione'])
|
||||||
|
? $part['NomeMatriceTraduzione']
|
||||||
|
: (!empty($part['idmatrice']) ? 'Matrix without translation' : 'No Matrix'),
|
||||||
|
ENT_QUOTES,
|
||||||
|
'UTF-8'
|
||||||
|
) ?>
|
||||||
|
</strong>
|
||||||
|
<?php if (!empty($part['idmatrice'])): ?>
|
||||||
|
<span class="small text-muted">(ID: <?= (int)$part['idmatrice'] ?>)</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($part['mix']) && strtoupper($part['mix']) === 'Y'): ?>
|
||||||
|
| <span class="badge bg-warning text-dark">Mix</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($part['material']) || !empty($part['color'])): ?>
|
||||||
|
<div class="small text-muted">
|
||||||
|
<?php if (!empty($part['material'])): ?>
|
||||||
|
Material: <?= htmlspecialchars($part['material'], ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($part['material']) && !empty($part['color'])): ?>
|
||||||
|
|
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($part['color'])): ?>
|
||||||
|
Color: <?= htmlspecialchars($part['color'], ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($part['note'])): ?>
|
||||||
|
<div class="small text-muted mt-1">
|
||||||
|
Note: <?= htmlspecialchars($part['note'], ENT_QUOTES, 'UTF-8') ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ANALYSES PLACEHOLDER -->
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<div class="card h-100 shadow-sm">
|
||||||
|
<div class="card-header py-2">
|
||||||
|
<strong>Analyses</strong>
|
||||||
|
</div>
|
||||||
|
<div class="card-body analysis-scroll-area" id="analysisRightPanel">
|
||||||
|
<div class="alert alert-info mb-3">
|
||||||
|
This area will contain analyses in the next step.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border rounded p-3 bg-light">
|
||||||
|
<div class="mb-2"><strong>Current behavior</strong></div>
|
||||||
|
<ul class="mb-0 ps-3">
|
||||||
|
<li>Click a matrix on the left</li>
|
||||||
|
<li>All parts linked to that matrix become selected</li>
|
||||||
|
<li>Analyses panel will be connected later</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<div class="small text-muted">Selected matrix:</div>
|
||||||
|
<div id="analysisCurrentMatrix" class="fw-semibold">-</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<div class="small text-muted">Selected parts IDs:</div>
|
||||||
|
<div id="analysisSelectedPartsIds" class="fw-semibold">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" id="analysisModalIddatadb" value="<?= (int)$iddatadb ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#analysisModal {
|
||||||
|
z-index: 1080 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#analysisModal .modal-content {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-height: 95vh;
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-modal-content {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-modal-body {
|
||||||
|
height: calc(95vh - 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-scroll-area {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: calc(95vh - 180px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-matrix-item {
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-part-item {
|
||||||
|
border-radius: 8px !important;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-part-item.matrix-active {
|
||||||
|
background-color: #e8f4ff !important;
|
||||||
|
border-color: #86b7fe !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-part-item.part-checked {
|
||||||
|
background-color: #eaf7ea !important;
|
||||||
|
border-color: #7ac77a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#analysisSelectedPartsIds {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -9,15 +9,28 @@
|
|||||||
<div class="row parts-row">
|
<div class="row parts-row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; min-width: 0;">
|
||||||
<h6 style="margin: 0;">Elenco Parti</h6>
|
<h6 style="margin: 0; white-space: nowrap;">Elenco Parti</h6>
|
||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center; min-width: 0; gap: 8px;">
|
||||||
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
<button type="button"
|
||||||
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
class="btn btn-dark btn-sm open-analysis-modal-btn"
|
||||||
<button type="button" class="btn btn-info btn-sm ms-2 d-none" id="quotationeBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Add Quotation</button>
|
id="openAnalysisModalBtn"
|
||||||
<button type="button" class="btn btn-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
<i class="fas fa-eye-slash" style="font-size: 0.8rem;"></i>
|
<i class="fas fa-flask"></i> Analysis
|
||||||
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
</button>
|
||||||
|
|
||||||
|
<select id="global-matrice" class="ms-2" style="width: 250px !important; min-width: 250px !important;">
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="checkbox" id="showMixParts" name="showMixParts" style="margin-right: 5px; margin-left: 10px;">
|
||||||
|
<label for="showMixParts" style="font-size: 0.9rem; margin-right: 10px;">Mix</label>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
|
Rinumera Parti
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
|
<i class="fas fa-microphone"></i> Voce
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,46 +9,76 @@ try {
|
|||||||
throw new Exception("Invalid request method.");
|
throw new Exception("Invalid request method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera e sanifica i dati
|
// Retrieve and sanitize form data
|
||||||
$id = intval($_POST['id']);
|
$id = intval($_POST['id'] ?? 0);
|
||||||
$name = trim($_POST['name']);
|
$name = trim($_POST['name'] ?? '');
|
||||||
$header_row = intval($_POST['header_row']);
|
$source_type = strtoupper(trim($_POST['source_type'] ?? 'XLS'));
|
||||||
$start_column = trim($_POST['start_column']);
|
$header_row = isset($_POST['header_row']) && $_POST['header_row'] !== '' ? intval($_POST['header_row']) : null;
|
||||||
|
$start_column = trim($_POST['start_column'] ?? '');
|
||||||
$description = trim($_POST['description'] ?? '');
|
$description = trim($_POST['description'] ?? '');
|
||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table'] ?? 'datadb');
|
||||||
$idclient = intval($_POST['client_id'] ?? 0); // Usa client_id dal form
|
$idclient = intval($_POST['client_id'] ?? 0);
|
||||||
$clientname = trim($_POST['client_name'] ?? ''); // Usa client_name dal form
|
$clientname = trim($_POST['client_name'] ?? '');
|
||||||
$idschema = intval($_POST['idschema'] ?? 0); // Nuovo campo
|
$idschema = intval($_POST['idschema'] ?? 0);
|
||||||
$schemaname = trim($_POST['schemaname'] ?? ''); // Corretto da schemamaname
|
$schemaname = trim($_POST['schemaname'] ?? '');
|
||||||
$idroutine = isset($_POST['idroutine']) && $_POST['idroutine'] !== '' ? intval($_POST['idroutine']) : null; // Aggiunto idroutine
|
$idroutine = isset($_POST['idroutine']) && $_POST['idroutine'] !== '' ? intval($_POST['idroutine']) : null;
|
||||||
$button_size = trim($_POST['button_size'] ?? 'medium'); // Nuovo campo
|
$button_size = trim($_POST['button_size'] ?? 'medium');
|
||||||
$button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff'); // Nuovo campo
|
$button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff');
|
||||||
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff'); // Nuovo campo
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
||||||
$button_label = trim($_POST['button_label'] ?? 'Click Me'); // Nuovo campo
|
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
if (!in_array($source_type, ['XLS', 'API'], true)) {
|
||||||
if (empty($id) || empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idschema <= 0) {
|
$source_type = 'XLS';
|
||||||
throw new Exception("All fields marked with * are required, including schema.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validazione del idclient
|
// Required fields validation
|
||||||
if ($idclient <= 0) {
|
if ($id <= 0 || $name === '' || $target_table === '' || $idclient <= 0 || $idschema <= 0) {
|
||||||
throw new Exception("Please select a valid client.");
|
throw new Exception("All fields marked with * are required, including client and schema.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connessione al database
|
// XLS-only validation
|
||||||
|
if ($source_type === 'XLS') {
|
||||||
|
if ($header_row === null || $header_row <= 0 || $start_column === '') {
|
||||||
|
throw new Exception("Header Row and Start Column are required for XLS templates.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API templates do not require XLS coordinates
|
||||||
|
if ($source_type === 'API') {
|
||||||
|
$header_row = null;
|
||||||
|
$start_column = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database connection
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Aggiorna il database, includendo i nuovi campi
|
// Update template
|
||||||
$stmt = $pdo->prepare("UPDATE excel_templates
|
$stmt = $pdo->prepare("
|
||||||
SET name = ?, header_row = ?, start_column = ?, description = ?, target_table = ?,
|
UPDATE excel_templates
|
||||||
idclient = ?, clientname = ?, schemaname = ?, idschema = ?, idroutine = ?,
|
SET
|
||||||
button_size = ?, button_bg_color = ?, button_text_color = ?, button_label = ?,
|
name = ?,
|
||||||
updated_at = NOW()
|
source_type = ?,
|
||||||
WHERE id = ?");
|
header_row = ?,
|
||||||
|
start_column = ?,
|
||||||
|
description = ?,
|
||||||
|
target_table = ?,
|
||||||
|
idclient = ?,
|
||||||
|
clientname = ?,
|
||||||
|
schemaname = ?,
|
||||||
|
idschema = ?,
|
||||||
|
idroutine = ?,
|
||||||
|
button_size = ?,
|
||||||
|
button_bg_color = ?,
|
||||||
|
button_text_color = ?,
|
||||||
|
button_label = ?,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = ?
|
||||||
|
");
|
||||||
|
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
|
$source_type,
|
||||||
$header_row,
|
$header_row,
|
||||||
$start_column,
|
$start_column,
|
||||||
$description,
|
$description,
|
||||||
@ -65,12 +95,10 @@ try {
|
|||||||
$id
|
$id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// rowCount potrebbe essere 0 se non ci sono modifiche, quindi consideriamo comunque un successo
|
|
||||||
$response["success"] = true;
|
$response["success"] = true;
|
||||||
$response["message"] = "Template updated successfully!";
|
$response["message"] = "Template updated successfully!";
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$response["message"] = $e->getMessage();
|
$response["message"] = $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restituisce un JSON per il fetch
|
|
||||||
echo json_encode($response);
|
echo json_encode($response);
|
||||||
|
|||||||
@ -154,7 +154,7 @@ try {
|
|||||||
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($physCol);
|
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($physCol);
|
||||||
$cell = $worksheet->getCell($columnLetter . $row);
|
$cell = $worksheet->getCell($columnLetter . $row);
|
||||||
$cellValue = $cell ? $cell->getCalculatedValue() : '';
|
$cellValue = $cell ? $cell->getCalculatedValue() : '';
|
||||||
$rowData[] = $cellValue ?: '';
|
$rowData[] = htmlspecialchars($cellValue ?: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count how many header columns have data in this row
|
// Count how many header columns have data in this row
|
||||||
|
|||||||
@ -9,12 +9,13 @@ try {
|
|||||||
throw new Exception("Invalid request method.");
|
throw new Exception("Invalid request method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera e sanifica i dati
|
// Retrieve and sanitize form data
|
||||||
$name = trim($_POST['name']);
|
$name = trim($_POST['name'] ?? '');
|
||||||
$header_row = intval($_POST['header_row']);
|
$source_type = strtoupper(trim($_POST['source_type'] ?? 'XLS'));
|
||||||
$start_column = trim($_POST['start_column']);
|
$header_row = isset($_POST['header_row']) && $_POST['header_row'] !== '' ? intval($_POST['header_row']) : null;
|
||||||
|
$start_column = trim($_POST['start_column'] ?? '');
|
||||||
$description = trim($_POST['description'] ?? '');
|
$description = trim($_POST['description'] ?? '');
|
||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table'] ?? 'datadb');
|
||||||
$idclient = intval($_POST['client_id'] ?? 0);
|
$idclient = intval($_POST['client_id'] ?? 0);
|
||||||
$clientname = trim($_POST['client_name'] ?? '');
|
$clientname = trim($_POST['client_name'] ?? '');
|
||||||
$idschema = intval($_POST['idschema'] ?? 0);
|
$idschema = intval($_POST['idschema'] ?? 0);
|
||||||
@ -25,24 +26,61 @@ try {
|
|||||||
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
||||||
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
// Normalize source type
|
||||||
if (empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idclient <= 0 || $idschema <= 0) {
|
if (!in_array($source_type, ['XLS', 'API'], true)) {
|
||||||
|
$source_type = 'XLS';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required fields validation
|
||||||
|
if ($name === '' || $target_table === '' || $idclient <= 0 || $idschema <= 0) {
|
||||||
throw new Exception("All fields marked with * are required, including client and schema.");
|
throw new Exception("All fields marked with * are required, including client and schema.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connessione al database
|
// XLS-only validation
|
||||||
|
if ($source_type === 'XLS') {
|
||||||
|
if ($header_row === null || $header_row <= 0 || $start_column === '') {
|
||||||
|
throw new Exception("Header Row and Start Column are required for XLS templates.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API templates do not require XLS coordinates
|
||||||
|
if ($source_type === 'API') {
|
||||||
|
$header_row = null;
|
||||||
|
$start_column = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database connection
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Inserisci il nuovo template
|
// Insert the new template
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
INSERT INTO excel_templates
|
INSERT INTO excel_templates
|
||||||
(name, header_row, start_column, description, target_table, idclient, clientname, idschema, schemaname, idroutine,
|
(
|
||||||
button_size, button_bg_color, button_text_color, button_label, created_at, updated_at)
|
name,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
source_type,
|
||||||
|
header_row,
|
||||||
|
start_column,
|
||||||
|
description,
|
||||||
|
target_table,
|
||||||
|
idclient,
|
||||||
|
clientname,
|
||||||
|
idschema,
|
||||||
|
schemaname,
|
||||||
|
idroutine,
|
||||||
|
button_size,
|
||||||
|
button_bg_color,
|
||||||
|
button_text_color,
|
||||||
|
button_label,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||||
");
|
");
|
||||||
|
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
|
$source_type,
|
||||||
$header_row,
|
$header_row,
|
||||||
$start_column,
|
$start_column,
|
||||||
$description,
|
$description,
|
||||||
|
|||||||
@ -5,102 +5,211 @@ ini_set('error_log', __DIR__ . '/routine_debug.log');
|
|||||||
function applyRoutine(&$excelData, $routineData)
|
function applyRoutine(&$excelData, $routineData)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Log iniziale
|
// Initial log
|
||||||
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
||||||
error_log("Dati routine: " . print_r($routineData, true));
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
error_log("Dati excel_data: " . print_r($excelData, true));
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
// Verifica se excelData è vuoto
|
// Check if excelData is empty
|
||||||
if (empty($excelData)) {
|
if (empty($excelData)) {
|
||||||
throw new Exception("excelData è vuoto o non valido.");
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estrai informazioni dalla routine con valori predefiniti
|
// Extract routine settings with default values
|
||||||
$action1 = trim($routineData['action1'] ?? 'K');
|
$action1 = trim($routineData['action1'] ?? 'K');
|
||||||
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
||||||
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
||||||
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
||||||
$headers = $routineData['xls_headers'] ?? [];
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
// Package-related headers
|
||||||
|
$package_header = 'PACKAGE';
|
||||||
|
$other_test_header = 'Other test from Control Matrix';
|
||||||
|
$only_colorfastness_header = 'Only Colorfastness package';
|
||||||
|
$only_chemical_header = 'Only Chemical package';
|
||||||
|
|
||||||
if (empty($headers)) {
|
if (empty($headers)) {
|
||||||
throw new Exception("Nessun header trovato per la routine Moncler.");
|
throw new Exception("Nessun header trovato per la routine Moncler.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If headers arrive as JSON string, decode them
|
||||||
|
if (!is_array($headers) && is_string($headers)) {
|
||||||
|
$decoded_headers = json_decode($headers, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded_headers)) {
|
||||||
|
$headers = $decoded_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($headers) || empty($headers)) {
|
||||||
|
throw new Exception("Gli header della routine non sono validi.");
|
||||||
|
}
|
||||||
|
|
||||||
error_log("Header ricevuti: " . print_r($headers, true));
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
// Normalizza gli header (solo trim)
|
// Normalize headers
|
||||||
$normalized_headers = array_map('trim', $headers);
|
$normalized_headers = array_map(function ($header) {
|
||||||
|
return trim((string)$header);
|
||||||
|
}, $headers);
|
||||||
|
|
||||||
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
||||||
|
|
||||||
// Trova gli indici delle colonne
|
// Find package-related column indexes
|
||||||
$action1_index = array_search($action1, $normalized_headers);
|
$package_index = array_search($package_header, $normalized_headers, true);
|
||||||
$action2_index = array_search($action2, $normalized_headers);
|
$other_test_index = array_search($other_test_header, $normalized_headers, true);
|
||||||
$action3_index = array_search($action3, $normalized_headers);
|
$only_colorfastness_index = array_search($only_colorfastness_header, $normalized_headers, true);
|
||||||
$action4_index = array_search($action4, $normalized_headers);
|
$only_chemical_index = array_search($only_chemical_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
if ($package_index === false) {
|
||||||
|
throw new Exception("Colonna PACKAGE non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Indici package - PACKAGE: " . var_export($package_index, true) .
|
||||||
|
", Other test from Control Matrix: " . var_export($other_test_index, true) .
|
||||||
|
", Only Colorfastness package: " . var_export($only_colorfastness_index, true) .
|
||||||
|
", Only Chemical package: " . var_export($only_chemical_index, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PART 1
|
||||||
|
* Aggregate rows by action1 and split action2 into action3 + action4
|
||||||
|
* If it fails, continue with PART 2 only
|
||||||
|
*/
|
||||||
|
$part1_applied = false;
|
||||||
|
|
||||||
|
$action1_index = array_search($action1, $normalized_headers, true);
|
||||||
|
$action2_index = array_search($action2, $normalized_headers, true);
|
||||||
|
$action3_index = array_search($action3, $normalized_headers, true);
|
||||||
|
$action4_index = array_search($action4, $normalized_headers, true);
|
||||||
|
|
||||||
if ($action1_index === false || $action2_index === false || $action3_index === false || $action4_index === false) {
|
if ($action1_index === false || $action2_index === false || $action3_index === false || $action4_index === false) {
|
||||||
throw new Exception("Colonne non trovate - action1: '$action1' (index: " . var_export($action1_index, true) . "), action2: '$action2' (index: " . var_export($action2_index, true) . "), action3: '$action3' (index: " . var_export($action3_index, true) . "), action4: '$action4' (index: " . var_export($action4_index, true) . ")");
|
error_log(
|
||||||
|
"Unable to apply routine part 1. Package merge logic has been applied only. " .
|
||||||
|
"Missing columns - action1: '$action1' (index: " . var_export($action1_index, true) . ")" .
|
||||||
|
", action2: '$action2' (index: " . var_export($action2_index, true) . ")" .
|
||||||
|
", action3: '$action3' (index: " . var_export($action3_index, true) . ")" .
|
||||||
|
", action4: '$action4' (index: " . var_export($action4_index, true) . ")"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
error_log("Indici colonne part 1 - action1: $action1_index, action2: $action2_index, action3: $action3_index, action4: $action4_index");
|
||||||
|
|
||||||
|
$grouped_data = [];
|
||||||
|
|
||||||
|
foreach ($excelData as $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' per excelrow " . ($row['excelrow'] ?? 'N/A'));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $row['data'][$action1_index] ?? '';
|
||||||
|
$key = trim((string)$key);
|
||||||
|
$key = $key === '' ? '_empty_' : $key;
|
||||||
|
|
||||||
|
if (!isset($grouped_data[$key])) {
|
||||||
|
$grouped_data[$key] = [
|
||||||
|
'data' => $row['data'],
|
||||||
|
'excelrow' => [($row['excelrow'] ?? '')],
|
||||||
|
'style_codes' => [],
|
||||||
|
'style_descriptions' => []
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$grouped_data[$key]['excelrow'][] = ($row['excelrow'] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split STYLE CODE + STYLE DESCRIPTION
|
||||||
|
$action2_value = trim((string)($row['data'][$action2_index] ?? ''));
|
||||||
|
|
||||||
|
if ($action2_value !== '') {
|
||||||
|
$parts = explode(' - ', $action2_value, 2);
|
||||||
|
$style_code = trim((string)($parts[0] ?? ''));
|
||||||
|
$style_description = trim((string)($parts[1] ?? ''));
|
||||||
|
|
||||||
|
if ($style_code !== '') {
|
||||||
|
$grouped_data[$key]['style_codes'][] = $style_code;
|
||||||
|
}
|
||||||
|
if ($style_description !== '') {
|
||||||
|
$grouped_data[$key]['style_descriptions'][] = $style_description;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("Valore vuoto in action2 per excelrow " . ($row['excelrow'] ?? 'N/A'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_excel_data = [];
|
||||||
|
|
||||||
|
foreach ($grouped_data as $key => $group) {
|
||||||
|
$row_data = $group['data'];
|
||||||
|
|
||||||
|
// Update STYLE CODE and STYLE DESCRIPTION with aggregated unique values
|
||||||
|
$row_data[$action3_index] = implode(' - ', array_unique($group['style_codes']));
|
||||||
|
$row_data[$action4_index] = implode(' - ', array_unique($group['style_descriptions']));
|
||||||
|
|
||||||
|
// Concatenate excelrow values with "+"
|
||||||
|
$excelrow_clean = array_filter($group['excelrow'], function ($value) {
|
||||||
|
return $value !== null && $value !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$excelrow_value = count($excelrow_clean) > 1
|
||||||
|
? implode('+', $excelrow_clean)
|
||||||
|
: (reset($excelrow_clean) ?: '');
|
||||||
|
|
||||||
|
$new_excel_data[] = [
|
||||||
|
'data' => $row_data,
|
||||||
|
'excelrow' => $excelrow_value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$excelData = $new_excel_data;
|
||||||
|
$part1_applied = true;
|
||||||
|
|
||||||
|
error_log("Routine part 1 completata - Righe aggregate: " . count($new_excel_data));
|
||||||
|
error_log("Excelrow aggregati part 1: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("Indici colonne - action1: $action1_index, action2: $action2_index, action3: $action3_index, action4: $action4_index");
|
/**
|
||||||
|
* PART 2
|
||||||
// Raggruppa le righe per il valore in action1 (colonna K)
|
* Merge package-related columns into PACKAGE
|
||||||
$grouped_data = [];
|
* Always applied if PACKAGE exists
|
||||||
foreach ($excelData as $row) {
|
*/
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
if (!isset($row['data']) || !is_array($row['data'])) {
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
error_log("Riga non valida, manca 'data' per excelrow {$row['excelrow']}");
|
error_log("Riga non valida nella part 2, manca 'data' all'indice $index");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$key = $row['data'][$action1_index] ?? '';
|
|
||||||
$key = empty($key) ? '_empty_' : $key;
|
$package_values = [];
|
||||||
if (!isset($grouped_data[$key])) {
|
|
||||||
$grouped_data[$key] = [
|
$value_package = trim((string)($row['data'][$package_index] ?? ''));
|
||||||
'data' => $row['data'],
|
$value_other_test = $other_test_index !== false ? trim((string)($row['data'][$other_test_index] ?? '')) : '';
|
||||||
'excelrow' => [$row['excelrow']],
|
$value_only_colorfastness = $only_colorfastness_index !== false ? trim((string)($row['data'][$only_colorfastness_index] ?? '')) : '';
|
||||||
'style_codes' => [],
|
$value_only_chemical = $only_chemical_index !== false ? trim((string)($row['data'][$only_chemical_index] ?? '')) : '';
|
||||||
'style_descriptions' => []
|
|
||||||
];
|
if ($value_package !== '') {
|
||||||
} else {
|
$package_values[] = $value_package;
|
||||||
$grouped_data[$key]['excelrow'][] = $row['excelrow'];
|
}
|
||||||
|
if ($value_other_test !== '') {
|
||||||
|
$package_values[] = $value_other_test;
|
||||||
|
}
|
||||||
|
if ($value_only_colorfastness !== '') {
|
||||||
|
$package_values[] = $value_only_colorfastness;
|
||||||
|
}
|
||||||
|
if ($value_only_chemical !== '') {
|
||||||
|
$package_values[] = $value_only_chemical;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separa il valore in action2 (STYLE CODE + STYLE DESCRIPTION)
|
$package_values = array_unique($package_values);
|
||||||
$action2_value = $row['data'][$action2_index] ?? '';
|
|
||||||
if (!empty($action2_value)) {
|
$excelData[$index]['data'][$package_index] = implode(' - ', $package_values);
|
||||||
$parts = explode(' - ', trim($action2_value));
|
|
||||||
$style_code = $parts[0] ?? '';
|
|
||||||
$style_description = $parts[1] ?? '';
|
|
||||||
if (!empty($style_code)) {
|
|
||||||
$grouped_data[$key]['style_codes'][] = $style_code;
|
|
||||||
}
|
|
||||||
if (!empty($style_description)) {
|
|
||||||
$grouped_data[$key]['style_descriptions'][] = $style_description;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_log("Valore vuoto in action2 per excelrow {$row['excelrow']}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea il nuovo array excel_data aggregato
|
error_log("Routine part 2 completata - Merge package applicato su " . count($excelData) . " righe");
|
||||||
$new_excel_data = [];
|
|
||||||
foreach ($grouped_data as $key => $group) {
|
if (!$part1_applied) {
|
||||||
$row_data = $group['data'];
|
error_log("Warning finale: routine part 1 non applicata, routine part 2 applicata correttamente");
|
||||||
// Aggiorna action3 (STYLE CODE) e action4 (STYLE DESCRIPTION) con valori aggregati
|
|
||||||
$row_data[$action3_index] = implode(' - ', array_unique($group['style_codes']));
|
|
||||||
$row_data[$action4_index] = implode(' - ', array_unique($group['style_descriptions']));
|
|
||||||
// Concatena gli excelrow con '+' per le righe aggregate
|
|
||||||
$excelrow_value = count($group['excelrow']) > 1 ? implode('+', $group['excelrow']) : $group['excelrow'][0];
|
|
||||||
$new_excel_data[] = [
|
|
||||||
'data' => $row_data,
|
|
||||||
'excelrow' => $excelrow_value
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifica excelData in-place
|
error_log("Routine Moncler completata con successo");
|
||||||
$excelData = $new_excel_data;
|
|
||||||
|
|
||||||
error_log("Routine Moncler completata - Righe aggregate: " . count($new_excel_data));
|
|
||||||
error_log("Excelrow aggregati: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
|
|||||||
327
public/userarea/routines/moncler_new_routine.php
Normal file
327
public/userarea/routines/moncler_new_routine.php
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/routine_debug.log');
|
||||||
|
|
||||||
|
function applyRoutine(&$excelData, $routineData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initial log
|
||||||
|
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
||||||
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
|
// Check if excelData is empty
|
||||||
|
if (empty($excelData)) {
|
||||||
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract routine settings with default values
|
||||||
|
$action1 = trim($routineData['action1'] ?? 'K');
|
||||||
|
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
||||||
|
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
||||||
|
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
||||||
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
// Package-related headers
|
||||||
|
$package_header = 'PACKAGE';
|
||||||
|
$other_test_header = 'Other test from Control Matrix';
|
||||||
|
$only_colorfastness_header = 'Only Colorfastness package';
|
||||||
|
$only_chemical_header = 'Only Chemical package';
|
||||||
|
|
||||||
|
if (empty($headers)) {
|
||||||
|
throw new Exception("Nessun header trovato per la routine Moncler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If headers arrive as JSON string, decode them
|
||||||
|
if (!is_array($headers) && is_string($headers)) {
|
||||||
|
$decoded_headers = json_decode($headers, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded_headers)) {
|
||||||
|
$headers = $decoded_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($headers) || empty($headers)) {
|
||||||
|
throw new Exception("Gli header della routine non sono validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
|
// Normalize headers
|
||||||
|
$normalized_headers = array_map(function ($header) {
|
||||||
|
return trim((string)$header);
|
||||||
|
}, $headers);
|
||||||
|
|
||||||
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
|
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
||||||
|
|
||||||
|
// Find main indexes
|
||||||
|
$action1_index = array_search($action1, $normalized_headers, true);
|
||||||
|
$action2_index = array_search($action2, $normalized_headers, true);
|
||||||
|
$action3_index = array_search($action3, $normalized_headers, true);
|
||||||
|
$action4_index = array_search($action4, $normalized_headers, true);
|
||||||
|
|
||||||
|
// Find package-related column indexes
|
||||||
|
$package_index = array_search($package_header, $normalized_headers, true);
|
||||||
|
$other_test_index = array_search($other_test_header, $normalized_headers, true);
|
||||||
|
$only_colorfastness_index = array_search($only_colorfastness_header, $normalized_headers, true);
|
||||||
|
$only_chemical_index = array_search($only_chemical_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
if ($package_index === false) {
|
||||||
|
throw new Exception("Colonna PACKAGE non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Indici colonne - action1: " . var_export($action1_index, true) .
|
||||||
|
", action2: " . var_export($action2_index, true) .
|
||||||
|
", action3: " . var_export($action3_index, true) .
|
||||||
|
", action4: " . var_export($action4_index, true) .
|
||||||
|
", PACKAGE: " . var_export($package_index, true) .
|
||||||
|
", Other test from Control Matrix: " . var_export($other_test_index, true) .
|
||||||
|
", Only Colorfastness package: " . var_export($only_colorfastness_index, true) .
|
||||||
|
", Only Chemical package: " . var_export($only_chemical_index, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Helper: split a value already joined by " - "
|
||||||
|
$splitJoinedValues = function ($value) {
|
||||||
|
$value = trim((string)$value);
|
||||||
|
if ($value === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = preg_split('/\s*-\s*/', $value);
|
||||||
|
$parts = array_map('trim', $parts);
|
||||||
|
$parts = array_filter($parts, function ($item) {
|
||||||
|
return $item !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
return array_values(array_unique($parts));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper: join unique values with " - "
|
||||||
|
$joinUniqueValues = function (array $values) {
|
||||||
|
$clean = [];
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$value = trim((string)$value);
|
||||||
|
if ($value !== '' && !in_array($value, $clean, true)) {
|
||||||
|
$clean[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode(' - ', $clean);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper: split STYLE CODE + STYLE DESCRIPTION into code + description
|
||||||
|
$splitStyleCombined = function ($value) {
|
||||||
|
$value = trim((string)$value);
|
||||||
|
|
||||||
|
if ($value === '') {
|
||||||
|
return ['', ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept both "CODE - DESC" and "CODE-DESC"
|
||||||
|
$parts = preg_split('/\s*-\s*/', $value, 2);
|
||||||
|
|
||||||
|
$styleCode = trim((string)($parts[0] ?? ''));
|
||||||
|
$styleDescription = trim((string)($parts[1] ?? ''));
|
||||||
|
|
||||||
|
return [$styleCode, $styleDescription];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 0
|
||||||
|
* Normalize STYLE CODE and STYLE DESCRIPTION before grouping by K
|
||||||
|
*
|
||||||
|
* Rules:
|
||||||
|
* - Read STYLE CODE + STYLE DESCRIPTION
|
||||||
|
* - If it contains code/description, fill missing values
|
||||||
|
* - If target field already contains a different value, add it instead of replacing it
|
||||||
|
* - Avoid duplicates
|
||||||
|
*/
|
||||||
|
$step0_applied = false;
|
||||||
|
|
||||||
|
if ($action2_index === false || $action3_index === false || $action4_index === false) {
|
||||||
|
error_log(
|
||||||
|
"Unable to apply routine step 0. Missing columns - action2: '$action2' (index: " . var_export($action2_index, true) . ")" .
|
||||||
|
", action3: '$action3' (index: " . var_export($action3_index, true) . ")" .
|
||||||
|
", action4: '$action4' (index: " . var_export($action4_index, true) . ")"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida nello step 0, manca 'data' all'indice $index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$combinedValue = trim((string)($row['data'][$action2_index] ?? ''));
|
||||||
|
$currentStyleCode = trim((string)($row['data'][$action3_index] ?? ''));
|
||||||
|
$currentStyleDescription = trim((string)($row['data'][$action4_index] ?? ''));
|
||||||
|
|
||||||
|
if ($combinedValue === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$parsedStyleCode, $parsedStyleDescription] = $splitStyleCombined($combinedValue);
|
||||||
|
|
||||||
|
$styleCodeValues = $splitJoinedValues($currentStyleCode);
|
||||||
|
$styleDescriptionValues = $splitJoinedValues($currentStyleDescription);
|
||||||
|
|
||||||
|
if ($parsedStyleCode !== '' && !in_array($parsedStyleCode, $styleCodeValues, true)) {
|
||||||
|
$styleCodeValues[] = $parsedStyleCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parsedStyleDescription !== '' && !in_array($parsedStyleDescription, $styleDescriptionValues, true)) {
|
||||||
|
$styleDescriptionValues[] = $parsedStyleDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
$excelData[$index]['data'][$action3_index] = $joinUniqueValues($styleCodeValues);
|
||||||
|
$excelData[$index]['data'][$action4_index] = $joinUniqueValues($styleDescriptionValues);
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Step 0 - excelrow " . ($row['excelrow'] ?? 'N/A') .
|
||||||
|
" | combined: '" . $combinedValue . "'" .
|
||||||
|
" | style_code_result: '" . $excelData[$index]['data'][$action3_index] . "'" .
|
||||||
|
" | style_description_result: '" . $excelData[$index]['data'][$action4_index] . "'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$step0_applied = true;
|
||||||
|
error_log("Routine step 0 completato - Normalizzazione style applicata su " . count($excelData) . " righe");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 1
|
||||||
|
* Aggregate rows by action1 using normalized STYLE CODE and STYLE DESCRIPTION
|
||||||
|
* If it fails, continue with STEP 2 only
|
||||||
|
*/
|
||||||
|
$step1_applied = false;
|
||||||
|
|
||||||
|
if ($action1_index === false || $action3_index === false || $action4_index === false) {
|
||||||
|
error_log(
|
||||||
|
"Unable to apply routine step 1. Package merge logic has been applied only. " .
|
||||||
|
"Missing columns - action1: '$action1' (index: " . var_export($action1_index, true) . ")" .
|
||||||
|
", action3: '$action3' (index: " . var_export($action3_index, true) . ")" .
|
||||||
|
", action4: '$action4' (index: " . var_export($action4_index, true) . ")"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$grouped_data = [];
|
||||||
|
|
||||||
|
foreach ($excelData as $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' per excelrow " . ($row['excelrow'] ?? 'N/A'));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $row['data'][$action1_index] ?? '';
|
||||||
|
$key = trim((string)$key);
|
||||||
|
$key = $key === '' ? '_empty_' : $key;
|
||||||
|
|
||||||
|
if (!isset($grouped_data[$key])) {
|
||||||
|
$grouped_data[$key] = [
|
||||||
|
'data' => $row['data'],
|
||||||
|
'excelrow' => [($row['excelrow'] ?? '')],
|
||||||
|
'style_codes' => [],
|
||||||
|
'style_descriptions' => []
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$grouped_data[$key]['excelrow'][] = ($row['excelrow'] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect normalized STYLE CODE values
|
||||||
|
$styleCodeValues = $splitJoinedValues($row['data'][$action3_index] ?? '');
|
||||||
|
foreach ($styleCodeValues as $styleCodeValue) {
|
||||||
|
if (!in_array($styleCodeValue, $grouped_data[$key]['style_codes'], true)) {
|
||||||
|
$grouped_data[$key]['style_codes'][] = $styleCodeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect normalized STYLE DESCRIPTION values
|
||||||
|
$styleDescriptionValues = $splitJoinedValues($row['data'][$action4_index] ?? '');
|
||||||
|
foreach ($styleDescriptionValues as $styleDescriptionValue) {
|
||||||
|
if (!in_array($styleDescriptionValue, $grouped_data[$key]['style_descriptions'], true)) {
|
||||||
|
$grouped_data[$key]['style_descriptions'][] = $styleDescriptionValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_excel_data = [];
|
||||||
|
|
||||||
|
foreach ($grouped_data as $key => $group) {
|
||||||
|
$row_data = $group['data'];
|
||||||
|
|
||||||
|
// Update STYLE CODE and STYLE DESCRIPTION with aggregated unique values
|
||||||
|
$row_data[$action3_index] = $joinUniqueValues($group['style_codes']);
|
||||||
|
$row_data[$action4_index] = $joinUniqueValues($group['style_descriptions']);
|
||||||
|
|
||||||
|
// Concatenate excelrow values with "+"
|
||||||
|
$excelrow_clean = array_filter($group['excelrow'], function ($value) {
|
||||||
|
return $value !== null && $value !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$excelrow_value = count($excelrow_clean) > 1
|
||||||
|
? implode('+', $excelrow_clean)
|
||||||
|
: (reset($excelrow_clean) ?: '');
|
||||||
|
|
||||||
|
$new_excel_data[] = [
|
||||||
|
'data' => $row_data,
|
||||||
|
'excelrow' => $excelrow_value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$excelData = $new_excel_data;
|
||||||
|
$step1_applied = true;
|
||||||
|
|
||||||
|
error_log("Routine step 1 completato - Righe aggregate: " . count($new_excel_data));
|
||||||
|
error_log("Excelrow aggregati step 1: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 2
|
||||||
|
* Merge package-related columns into PACKAGE
|
||||||
|
* Always applied if PACKAGE exists
|
||||||
|
*/
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida nello step 2, manca 'data' all'indice $index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$package_values = [];
|
||||||
|
|
||||||
|
$value_package = trim((string)($row['data'][$package_index] ?? ''));
|
||||||
|
$value_other_test = $other_test_index !== false ? trim((string)($row['data'][$other_test_index] ?? '')) : '';
|
||||||
|
$value_only_colorfastness = $only_colorfastness_index !== false ? trim((string)($row['data'][$only_colorfastness_index] ?? '')) : '';
|
||||||
|
$value_only_chemical = $only_chemical_index !== false ? trim((string)($row['data'][$only_chemical_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_package !== '') {
|
||||||
|
$package_values[] = $value_package;
|
||||||
|
}
|
||||||
|
if ($value_other_test !== '') {
|
||||||
|
$package_values[] = $value_other_test;
|
||||||
|
}
|
||||||
|
if ($value_only_colorfastness !== '') {
|
||||||
|
$package_values[] = $value_only_colorfastness;
|
||||||
|
}
|
||||||
|
if ($value_only_chemical !== '') {
|
||||||
|
$package_values[] = $value_only_chemical;
|
||||||
|
}
|
||||||
|
|
||||||
|
$package_values = array_unique($package_values);
|
||||||
|
|
||||||
|
$excelData[$index]['data'][$package_index] = implode(' - ', $package_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Routine step 2 completato - Merge package applicato su " . count($excelData) . " righe");
|
||||||
|
|
||||||
|
if (!$step0_applied) {
|
||||||
|
error_log("Warning finale: routine step 0 non applicata");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$step1_applied) {
|
||||||
|
error_log("Warning finale: routine step 1 non applicata, routine step 2 applicata correttamente");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Routine Moncler completata con successo");
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
212
public/userarea/routines/moncler_supplier_fabric.php
Normal file
212
public/userarea/routines/moncler_supplier_fabric.php
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/routine_debug.log');
|
||||||
|
|
||||||
|
function applyRoutine(&$excelData, $routineData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initial log
|
||||||
|
error_log("Inizio esecuzione nuova routine: " . date('Y-m-d H:i:s'));
|
||||||
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
|
// Check if excelData is empty
|
||||||
|
if (empty($excelData)) {
|
||||||
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get headers from routine data
|
||||||
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
if (empty($headers)) {
|
||||||
|
throw new Exception("Nessun header trovato per la routine.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If headers arrive as JSON string, decode them
|
||||||
|
if (!is_array($headers) && is_string($headers)) {
|
||||||
|
$decoded_headers = json_decode($headers, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded_headers)) {
|
||||||
|
$headers = $decoded_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($headers) || empty($headers)) {
|
||||||
|
throw new Exception("Gli header della routine non sono validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
|
// Normalize headers
|
||||||
|
$normalized_headers = array_map(function ($header) {
|
||||||
|
return trim((string)$header);
|
||||||
|
}, $headers);
|
||||||
|
|
||||||
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define source and target headers
|
||||||
|
*/
|
||||||
|
$parte_moncler_header = 'PARTE MONCLER';
|
||||||
|
$parte_fornitore_header = 'PARTE FORNITORE';
|
||||||
|
|
||||||
|
$descr_parte_moncler_header = 'DESCRIZIONE PARTE MONCLER';
|
||||||
|
$descr_parte_fornitore_header = 'DESCRIZIONE PARTE FORNITORE';
|
||||||
|
|
||||||
|
$colore_moncler_header = 'COLORE MONCLER';
|
||||||
|
$colore_fornitore_header = 'COLORE FORNITORE';
|
||||||
|
|
||||||
|
$composizione_tessile_header = 'COMPOSIZIONE TESSILE';
|
||||||
|
$composizione_totale_header = 'COMPOSIZIONE TOTALE';
|
||||||
|
|
||||||
|
$pacchetti_test_header = 'PACCHETTI TEST';
|
||||||
|
$test_addizionali_header = 'TEST ADDIZIONALI (A5 solo se richiesti dal cliente)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find indexes
|
||||||
|
*/
|
||||||
|
$parte_moncler_index = array_search($parte_moncler_header, $normalized_headers, true);
|
||||||
|
$parte_fornitore_index = array_search($parte_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$descr_parte_moncler_index = array_search($descr_parte_moncler_header, $normalized_headers, true);
|
||||||
|
$descr_parte_fornitore_index = array_search($descr_parte_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$colore_moncler_index = array_search($colore_moncler_header, $normalized_headers, true);
|
||||||
|
$colore_fornitore_index = array_search($colore_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$composizione_tessile_index = array_search($composizione_tessile_header, $normalized_headers, true);
|
||||||
|
$composizione_totale_index = array_search($composizione_totale_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$pacchetti_test_index = array_search($pacchetti_test_header, $normalized_headers, true);
|
||||||
|
$test_addizionali_index = array_search($test_addizionali_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Indici trovati - " .
|
||||||
|
"PARTE MONCLER: " . var_export($parte_moncler_index, true) .
|
||||||
|
", PARTE FORNITORE: " . var_export($parte_fornitore_index, true) .
|
||||||
|
", DESCRIZIONE PARTE MONCLER: " . var_export($descr_parte_moncler_index, true) .
|
||||||
|
", DESCRIZIONE PARTE FORNITORE: " . var_export($descr_parte_fornitore_index, true) .
|
||||||
|
", COLORE MONCLER: " . var_export($colore_moncler_index, true) .
|
||||||
|
", COLORE FORNITORE: " . var_export($colore_fornitore_index, true) .
|
||||||
|
", COMPOSIZIONE TESSILE: " . var_export($composizione_tessile_index, true) .
|
||||||
|
", COMPOSIZIONE TOTALE: " . var_export($composizione_totale_index, true) .
|
||||||
|
", PACCHETTI TEST: " . var_export($pacchetti_test_index, true) .
|
||||||
|
", TEST ADDIZIONALI: " . var_export($test_addizionali_index, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Required target columns must exist
|
||||||
|
if ($parte_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna PARTE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($descr_parte_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna DESCRIZIONE PARTE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($colore_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna COLORE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($composizione_tessile_index === false) {
|
||||||
|
throw new Exception("Colonna COMPOSIZIONE TESSILE non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pacchetti_test_index === false) {
|
||||||
|
throw new Exception("Colonna PACCHETTI TEST non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply merge row by row
|
||||||
|
*/
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' all'indice $index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. PARTE MONCLER + PARTE FORNITORE -> PARTE MONCLER
|
||||||
|
$parte_values = [];
|
||||||
|
|
||||||
|
$value_parte_moncler = trim((string)($row['data'][$parte_moncler_index] ?? ''));
|
||||||
|
$value_parte_fornitore = $parte_fornitore_index !== false ? trim((string)($row['data'][$parte_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_parte_moncler !== '') {
|
||||||
|
$parte_values[] = $value_parte_moncler;
|
||||||
|
}
|
||||||
|
if ($value_parte_fornitore !== '') {
|
||||||
|
$parte_values[] = $value_parte_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parte_values = array_unique($parte_values);
|
||||||
|
$excelData[$index]['data'][$parte_moncler_index] = implode(' - ', $parte_values);
|
||||||
|
|
||||||
|
// 2. DESCRIZIONE PARTE MONCLER + DESCRIZIONE PARTE FORNITORE -> DESCRIZIONE PARTE MONCLER
|
||||||
|
$descr_values = [];
|
||||||
|
|
||||||
|
$value_descr_moncler = trim((string)($row['data'][$descr_parte_moncler_index] ?? ''));
|
||||||
|
$value_descr_fornitore = $descr_parte_fornitore_index !== false ? trim((string)($row['data'][$descr_parte_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_descr_moncler !== '') {
|
||||||
|
$descr_values[] = $value_descr_moncler;
|
||||||
|
}
|
||||||
|
if ($value_descr_fornitore !== '') {
|
||||||
|
$descr_values[] = $value_descr_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$descr_values = array_unique($descr_values);
|
||||||
|
$excelData[$index]['data'][$descr_parte_moncler_index] = implode(' - ', $descr_values);
|
||||||
|
|
||||||
|
// 3. COLORE MONCLER + COLORE FORNITORE -> COLORE MONCLER
|
||||||
|
$colore_values = [];
|
||||||
|
|
||||||
|
$value_colore_moncler = trim((string)($row['data'][$colore_moncler_index] ?? ''));
|
||||||
|
$value_colore_fornitore = $colore_fornitore_index !== false ? trim((string)($row['data'][$colore_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_colore_moncler !== '') {
|
||||||
|
$colore_values[] = $value_colore_moncler;
|
||||||
|
}
|
||||||
|
if ($value_colore_fornitore !== '') {
|
||||||
|
$colore_values[] = $value_colore_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$colore_values = array_unique($colore_values);
|
||||||
|
$excelData[$index]['data'][$colore_moncler_index] = implode(' - ', $colore_values);
|
||||||
|
|
||||||
|
// 4. COMPOSIZIONE TESSILE + COMPOSIZIONE TOTALE -> COMPOSIZIONE TESSILE
|
||||||
|
$composizione_values = [];
|
||||||
|
|
||||||
|
$value_composizione_tessile = trim((string)($row['data'][$composizione_tessile_index] ?? ''));
|
||||||
|
$value_composizione_totale = $composizione_totale_index !== false ? trim((string)($row['data'][$composizione_totale_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_composizione_tessile !== '') {
|
||||||
|
$composizione_values[] = $value_composizione_tessile;
|
||||||
|
}
|
||||||
|
if ($value_composizione_totale !== '') {
|
||||||
|
$composizione_values[] = $value_composizione_totale;
|
||||||
|
}
|
||||||
|
|
||||||
|
$composizione_values = array_unique($composizione_values);
|
||||||
|
$excelData[$index]['data'][$composizione_tessile_index] = implode(' - ', $composizione_values);
|
||||||
|
|
||||||
|
// 5. PACCHETTI TEST + TEST ADDIZIONALI -> PACCHETTI TEST
|
||||||
|
$pacchetti_values = [];
|
||||||
|
|
||||||
|
$value_pacchetti_test = trim((string)($row['data'][$pacchetti_test_index] ?? ''));
|
||||||
|
$value_test_addizionali = $test_addizionali_index !== false ? trim((string)($row['data'][$test_addizionali_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_pacchetti_test !== '') {
|
||||||
|
$pacchetti_values[] = $value_pacchetti_test;
|
||||||
|
}
|
||||||
|
if ($value_test_addizionali !== '') {
|
||||||
|
$pacchetti_values[] = $value_test_addizionali;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pacchetti_values = array_unique($pacchetti_values);
|
||||||
|
$excelData[$index]['data'][$pacchetti_test_index] = implode(' - ', $pacchetti_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Nuova routine completata con successo. Righe elaborate: " . count($excelData));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Eccezione nella nuova routine: " . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,6 +56,56 @@
|
|||||||
input:checked+.slider:before {
|
input:checked+.slider:before {
|
||||||
transform: translateX(14px);
|
transform: translateX(14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-source {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0.30rem 0.55rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-xls {
|
||||||
|
background-color: #e7f1ff;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-api {
|
||||||
|
background-color: #e8fff1;
|
||||||
|
color: #198754;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable th,
|
||||||
|
#xlsTemplatesTable td {
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable td.description-cell,
|
||||||
|
#xlsTemplatesTable td.client-cell,
|
||||||
|
#xlsTemplatesTable td.name-cell,
|
||||||
|
#xlsTemplatesTable td.button-cell {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions .btn {
|
||||||
|
padding: 0.25rem 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-card .card-body {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -65,18 +115,20 @@
|
|||||||
<!--sidebar wrapper -->
|
<!--sidebar wrapper -->
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<!--end sidebar wrapper -->
|
<!--end sidebar wrapper -->
|
||||||
|
|
||||||
<!--start header -->
|
<!--start header -->
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<!--end header -->
|
<!--end header -->
|
||||||
|
|
||||||
<!--start page wrapper -->
|
<!--start page wrapper -->
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<?php include('top_stat_widget.php'); ?>
|
<?php include('top_stat_widget.php'); ?>
|
||||||
|
|
||||||
<div class="card radius-10">
|
<div class="card radius-10 compact-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<h6 class="mb-0">XLS Templates Dashboard</h6>
|
<h6 class="mb-0">Templates Dashboard</h6>
|
||||||
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
||||||
<i class="fas fa-plus"></i> New Template
|
<i class="fas fa-plus"></i> New Template
|
||||||
</a>
|
</a>
|
||||||
@ -85,22 +137,22 @@
|
|||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="xlsTemplatesTable" class="table table-striped table-bordered">
|
<table id="xlsTemplatesTable" class="table table-striped table-bordered table-sm w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
|
||||||
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th>Client Name</th>
|
|
||||||
<th>Button Label</th>
|
|
||||||
<th>Status</th> <!-- Aggiunta colonna Status -->
|
|
||||||
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Row</th>
|
||||||
|
<th>Col</th>
|
||||||
|
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Button</th>
|
||||||
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- DataTables riempirà questa sezione automaticamente -->
|
<!-- DataTables will populate this section automatically -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -110,25 +162,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
<!--end page wrapper -->
|
||||||
|
|
||||||
<!--start overlay-->
|
<!--start overlay-->
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<!--end overlay-->
|
<!--end overlay-->
|
||||||
|
|
||||||
<!--Start Back To Top Button-->
|
<!--Start Back To Top Button-->
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<!--End Back To Top Button-->
|
<!--End Back To Top Button-->
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<!--end wrapper-->
|
<!--end wrapper-->
|
||||||
|
|
||||||
<!-- search modal -->
|
|
||||||
<?php //include('include/searchmodal.php');
|
|
||||||
?>
|
|
||||||
<!-- end search modal -->
|
|
||||||
|
|
||||||
<!--start switcher-->
|
|
||||||
<?php //include('include/themeswitcher.php');
|
|
||||||
?>
|
|
||||||
<!--end switcher-->
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
||||||
@ -139,47 +185,92 @@
|
|||||||
processing: true,
|
processing: true,
|
||||||
serverSide: false,
|
serverSide: false,
|
||||||
ajax: 'load_templates.php',
|
ajax: 'load_templates.php',
|
||||||
|
pageLength: 50,
|
||||||
|
autoWidth: false,
|
||||||
columns: [{
|
columns: [{
|
||||||
data: 'id', // ID del template
|
data: 'id',
|
||||||
title: "ID"
|
orderable: false,
|
||||||
},
|
searchable: false,
|
||||||
{
|
title: "Actions",
|
||||||
data: 'name', // Nome del template
|
className: "table-actions text-center",
|
||||||
title: "Template Name"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: 'header_row', // Riga degli header
|
|
||||||
title: "Header Row"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'start_column', // Colonna di partenza
|
|
||||||
title: "Start Column"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'description', // Descrizione del template
|
|
||||||
title: "Description",
|
|
||||||
defaultContent: 'No description'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: null, // Nuova colonna per Client Name e ID
|
|
||||||
title: "Client Name",
|
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
const clientName = row.clientname || "No client";
|
return `
|
||||||
const clientId = row.idclient || "N/A";
|
<div class="d-flex justify-content-center gap-1">
|
||||||
return `${clientName} (ID: ${clientId})`;
|
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary" title="Edit">
|
||||||
|
<i class="bx bx-edit-alt"></i>
|
||||||
|
</a>
|
||||||
|
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success" title="Mapping">
|
||||||
|
<i class="bx bx-link-alt"></i>
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})" title="Delete">
|
||||||
|
<i class="bx bx-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'button_label', // Nuova colonna per Button Label
|
data: 'name',
|
||||||
title: "Button Label",
|
title: "Template Name",
|
||||||
|
className: "name-cell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'source_type',
|
||||||
|
title: "Type",
|
||||||
|
className: "text-center",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const sourceType = (data || 'XLS').toUpperCase();
|
||||||
|
|
||||||
|
if (type === 'display') {
|
||||||
|
if (sourceType === 'API') {
|
||||||
|
return '<span class="badge-source badge-source-api">API</span>';
|
||||||
|
}
|
||||||
|
return '<span class="badge-source badge-source-xls">XLS</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'header_row',
|
||||||
|
title: "Row",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'start_column',
|
||||||
|
title: "Col",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'description',
|
||||||
|
title: "Description",
|
||||||
|
className: "description-cell",
|
||||||
|
defaultContent: 'No description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
title: "Client",
|
||||||
|
className: "client-cell",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const clientName = row.clientname || "No client";
|
||||||
|
const clientId = row.idclient || "N/A";
|
||||||
|
return `${clientName} <small class="text-muted">(ID: ${clientId})</small>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'button_label',
|
||||||
|
title: "Button",
|
||||||
|
className: "button-cell",
|
||||||
defaultContent: 'Click Me'
|
defaultContent: 'Click Me'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'status', // Stato con Toggle Switch
|
data: 'status',
|
||||||
title: "Status",
|
title: "Status",
|
||||||
orderable: false,
|
orderable: false,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
|
className: "text-center",
|
||||||
render: function(status, type, row) {
|
render: function(status, type, row) {
|
||||||
let checked = (status === "active") ? "checked" : "";
|
let checked = (status === "active") ? "checked" : "";
|
||||||
return `
|
return `
|
||||||
@ -189,31 +280,13 @@
|
|||||||
</label>
|
</label>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'id', // Azioni: Modifica, Mappatura e Eliminazione
|
|
||||||
orderable: false,
|
|
||||||
searchable: false,
|
|
||||||
title: "Actions",
|
|
||||||
render: function(data) {
|
|
||||||
return `
|
|
||||||
<div class="d-flex">
|
|
||||||
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary me-1">
|
|
||||||
<i class="bx bx-edit-alt"></i>
|
|
||||||
</a>
|
|
||||||
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success me-1">
|
|
||||||
<i class="bx bx-link-alt"></i>
|
|
||||||
</a>
|
|
||||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})">
|
|
||||||
<i class="bx bx-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
||||||
lengthMenu: [10, 25, 50, 100],
|
lengthMenu: [10, 25, 50, 100],
|
||||||
|
order: [
|
||||||
|
[1, 'asc']
|
||||||
|
],
|
||||||
language: {
|
language: {
|
||||||
search: "Cerca:",
|
search: "Cerca:",
|
||||||
lengthMenu: "Mostra _MENU_ elementi",
|
lengthMenu: "Mostra _MENU_ elementi",
|
||||||
@ -252,20 +325,21 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: "update_template_status.php",
|
url: "update_template_status.php",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
data: {
|
data: {
|
||||||
id: templateId,
|
id: templateId,
|
||||||
status: newStatus
|
status: newStatus
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
console.log("✅ Status updated successfully.");
|
console.log("Status updated successfully.");
|
||||||
} else {
|
} else {
|
||||||
console.error("❌ Error updating status:", response.message);
|
console.error("Error updating status:", response.message);
|
||||||
alert("Error updating status: " + response.message);
|
alert("Error updating status: " + response.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function(xhr) {
|
||||||
console.error("❌ AJAX error.");
|
console.error("AJAX error:", xhr.responseText);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user