diff --git a/public/userarea/delete_matrice_attachment.php b/public/userarea/delete_matrice_attachment.php
new file mode 100644
index 0000000..4150ade
--- /dev/null
+++ b/public/userarea/delete_matrice_attachment.php
@@ -0,0 +1,61 @@
+ false,
+ 'message' => ''
+];
+
+try {
+ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ throw new Exception('Metodo non consentito');
+ }
+
+ if (!isset($_POST['id']) || !is_numeric($_POST['id'])) {
+ throw new Exception('ID allegato non valido');
+ }
+
+ $id = (int)$_POST['id'];
+
+ $db = DBHandlerSelect::getInstance();
+ $pdo = $db->getConnection();
+
+ $stmt = $pdo->prepare("SELECT id, file_path FROM matrice_attachments WHERE id = :id LIMIT 1");
+ $stmt->execute([':id' => $id]);
+ $attachment = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$attachment) {
+ throw new Exception('Allegato non trovato');
+ }
+
+ $filePathRelative = ltrim((string)$attachment['file_path'], '/\\');
+ $filePathAbsolute = __DIR__ . '/' . $filePathRelative;
+
+ $pdo->beginTransaction();
+
+ $deleteStmt = $pdo->prepare("DELETE FROM matrice_attachments WHERE id = :id");
+ $deleteStmt->execute([':id' => $id]);
+
+ if ($deleteStmt->rowCount() <= 0) {
+ throw new Exception('Impossibile eliminare il record allegato');
+ }
+
+ if (!empty($filePathRelative) && file_exists($filePathAbsolute) && is_file($filePathAbsolute)) {
+ @unlink($filePathAbsolute);
+ }
+
+ $pdo->commit();
+
+ $response['success'] = true;
+ $response['message'] = 'Allegato eliminato correttamente';
+} catch (Throwable $e) {
+ if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+ $response['message'] = $e->getMessage();
+}
+
+echo json_encode($response, JSON_UNESCAPED_UNICODE);
+exit;
diff --git a/public/userarea/delete_packaging_stock_lot.php b/public/userarea/delete_packaging_stock_lot.php
new file mode 100644
index 0000000..633b043
--- /dev/null
+++ b/public/userarea/delete_packaging_stock_lot.php
@@ -0,0 +1,20 @@
+ false, 'message' => 'Invalid id']);
+ exit;
+}
+
+$db = DBHandlerSelect::getInstance();
+$pdo = $db->getConnection();
+
+try {
+ $stmt = $pdo->prepare("DELETE FROM packaging_stock_lots WHERE id = ?");
+ $stmt->execute([$id]);
+ echo json_encode(['success' => true]);
+} catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => $e->getMessage()]);
+}
diff --git a/public/userarea/get_matrice_attachments.php b/public/userarea/get_matrice_attachments.php
new file mode 100644
index 0000000..7333915
--- /dev/null
+++ b/public/userarea/get_matrice_attachments.php
@@ -0,0 +1,65 @@
+ false,
+ 'attachments' => [],
+ 'message' => ''
+];
+
+try {
+ if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
+ throw new Exception('ID matrice non valido');
+ }
+
+ $idmatrice = (int)$_GET['id'];
+
+ $db = DBHandlerSelect::getInstance();
+ $pdo = $db->getConnection();
+
+ $sql = "SELECT
+ id,
+ matrice_id,
+ file_name,
+ file_path,
+ file_type,
+ description,
+ sort_order,
+ created_at,
+ updated_at
+ FROM matrice_attachments
+ WHERE matrice_id = :matrice_id
+ ORDER BY sort_order ASC, id DESC";
+
+ $stmt = $pdo->prepare($sql);
+ $stmt->execute([':matrice_id' => $idmatrice]);
+
+ $attachments = [];
+
+ while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
+ $relativePath = ltrim((string)$row['file_path'], '/\\');
+
+ $attachments[] = [
+ 'id' => (int)$row['id'],
+ 'matrice_id' => (int)$row['matrice_id'],
+ 'file_name' => $row['file_name'],
+ 'file_path' => $relativePath,
+ 'file_url' => $relativePath,
+ 'file_type' => $row['file_type'],
+ 'description' => $row['description'] ?? '',
+ 'sort_order' => (int)($row['sort_order'] ?? 0),
+ 'created_at' => !empty($row['created_at']) ? date('d/m/Y H:i', strtotime($row['created_at'])) : '',
+ 'updated_at' => !empty($row['updated_at']) ? date('d/m/Y H:i', strtotime($row['updated_at'])) : ''
+ ];
+ }
+
+ $response['success'] = true;
+ $response['attachments'] = $attachments;
+} catch (Throwable $e) {
+ $response['message'] = $e->getMessage();
+}
+
+echo json_encode($response, JSON_UNESCAPED_UNICODE);
+exit;
diff --git a/public/userarea/get_packaging_stock_lots.php b/public/userarea/get_packaging_stock_lots.php
new file mode 100644
index 0000000..033a226
--- /dev/null
+++ b/public/userarea/get_packaging_stock_lots.php
@@ -0,0 +1,30 @@
+ false, 'message' => 'Invalid id']);
+ exit;
+}
+
+$db = DBHandlerSelect::getInstance();
+$pdo = $db->getConnection();
+
+$sql = "SELECT
+ psl.id,
+ psl.idsupplier,
+ s.supplier_name,
+ psl.lot_code,
+ psl.expiry_date,
+ psl.qty
+ FROM packaging_stock_lots psl
+ INNER JOIN suppliers s ON s.idsupplier = psl.idsupplier
+ WHERE psl.idpackaging_item = ?
+ ORDER BY psl.id DESC";
+
+$stmt = $pdo->prepare($sql);
+$stmt->execute([$id]);
+$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+echo json_encode(['success' => true, 'rows' => $rows]);
diff --git a/public/userarea/matrici.php b/public/userarea/matrici.php
index 0d75b61..7cf3ca8 100644
--- a/public/userarea/matrici.php
+++ b/public/userarea/matrici.php
@@ -9,7 +9,7 @@
Gestione Matrici - = htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?>
-
+
@@ -17,7 +17,6 @@
-
@@ -50,6 +49,14 @@
padding: 10px 20px;
}
+ .btn-files {
+ background-color: #0dcaf0;
+ color: #0b2e38;
+ border-radius: 8px;
+ padding: 10px 18px;
+ font-weight: 600;
+ }
+
.table thead {
background-color: #b9ebc7;
text-align: center;
@@ -79,13 +86,16 @@
color: #ff9800;
}
+ .files {
+ color: #0dcaf0;
+ }
+
.thumb-img:hover {
transform: scale(1.05);
transition: 0.2s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
- /* === DataTables search: make it stand out === */
.dataTables_wrapper .dataTables_filter {
position: relative;
margin-bottom: 12px;
@@ -98,25 +108,21 @@
align-items: center;
gap: 10px;
justify-content: flex-end;
- /* search allineato a destra */
}
- /* input vero e proprio */
.dataTables_wrapper .dataTables_filter input {
width: 340px !important;
- /* più grande */
max-width: 100%;
padding: 10px 14px !important;
+ padding-right: 42px !important;
border-radius: 12px !important;
border: 2px solid #198754 !important;
- /* verde evidenza */
background: #fff !important;
box-shadow: 0 6px 18px rgba(25, 135, 84, 0.18);
outline: none !important;
transition: all .15s ease;
}
- /* focus ancora più evidente */
.dataTables_wrapper .dataTables_filter input:focus {
border-color: #146c43 !important;
box-shadow: 0 0 0 0.2rem rgba(25, 135, 84, 0.25), 0 10px 22px rgba(25, 135, 84, 0.22) !important;
@@ -133,15 +139,8 @@
font-size: 16px;
}
- /* spazio a destra per non “toccare” l’icona */
- .dataTables_wrapper .dataTables_filter input {
- padding-right: 42px !important;
- }
-
- /* --- FIX larghezze tabella matrici --- */
#tabellaMatrici {
table-layout: fixed;
- /* rende fisse le larghezze */
width: 100% !important;
}
@@ -150,55 +149,147 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- /* evita che il testo allarghi */
vertical-align: middle;
}
- /* Foto: più stretta */
#tabellaMatrici th:nth-child(1),
#tabellaMatrici td:nth-child(1) {
width: 90px;
max-width: 90px;
}
- /* Nome: più largo */
#tabellaMatrici th:nth-child(2),
#tabellaMatrici td:nth-child(2) {
- width: 320px;
- max-width: 320px;
+ width: 280px;
+ max-width: 280px;
}
- /* Cliente: più largo */
#tabellaMatrici th:nth-child(3),
#tabellaMatrici td:nth-child(3) {
- width: 320px;
- max-width: 320px;
+ width: 260px;
+ max-width: 260px;
}
- /* Linee: media */
#tabellaMatrici th:nth-child(4),
#tabellaMatrici td:nth-child(4) {
width: 220px;
max-width: 220px;
}
-
- /* Azioni: fissa */
#tabellaMatrici th:nth-child(5),
#tabellaMatrici td:nth-child(5) {
- width: 170px;
- max-width: 170px;
+ width: 220px;
+ max-width: 220px;
}
- /* Immagine: non “sfora” mai nella cella */
#tabellaMatrici td:nth-child(1) img {
width: 70px;
- /* puoi scendere a 60 */
height: 60px;
object-fit: cover;
}
-
+ .dropzone-attachments {
+ border: 2px dashed #86b7fe;
+ border-radius: 16px;
+ background: #f8fbff;
+ min-height: 150px;
+ padding: 24px;
+ text-align: center;
+ transition: all .2s ease;
+ cursor: pointer;
+ }
+
+ .dropzone-attachments.dragover {
+ background: #eef6ff;
+ border-color: #0d6efd;
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.12);
+ }
+
+ .dropzone-title {
+ font-weight: 700;
+ color: #1f2d3d;
+ font-size: 1.05rem;
+ }
+
+ .dropzone-subtitle {
+ color: #6c757d;
+ margin-top: 6px;
+ font-size: 0.95rem;
+ }
+
+ .attachments-selected-list .attachment-upload-row,
+ .attachments-existing-list .attachment-existing-row {
+ border: 1px solid #e5e7eb;
+ border-radius: 12px;
+ padding: 12px;
+ background: #fff;
+ margin-bottom: 10px;
+ }
+
+ .attachment-file-icon {
+ font-size: 1.3rem;
+ min-width: 28px;
+ text-align: center;
+ }
+
+ .attachment-meta-title {
+ font-weight: 700;
+ color: #1f2d3d;
+ word-break: break-word;
+ }
+
+ .attachment-meta-sub {
+ font-size: 0.88rem;
+ color: #6c757d;
+ }
+
+ .attachment-preview-thumb {
+ width: 54px;
+ height: 54px;
+ border-radius: 10px;
+ object-fit: cover;
+ border: 1px solid #dee2e6;
+ }
+
+ .existing-attachments-wrap {
+ max-height: 500px;
+ overflow-y: auto;
+ padding-right: 4px;
+ }
+
+ .selected-attachments-wrap {
+ max-height: 420px;
+ overflow-y: auto;
+ padding-right: 4px;
+ }
+
+ .badge-type {
+ font-size: 0.78rem;
+ }
+
+ .file-desc-input {
+ font-size: 0.95rem;
+ }
+
+ .modal-xl-custom {
+ max-width: 1380px;
+ width: 95vw;
+ }
+
+ .section-box {
+ background: #f8fafc;
+ border: 1px solid #e9ecef;
+ border-radius: 14px;
+ padding: 16px;
+ }
+
+ .empty-attachments {
+ color: #6c757d;
+ font-style: italic;
+ text-align: center;
+ padding: 18px 8px;
+ }
+
@@ -222,7 +313,6 @@
➕ Aggiungi Matrice
-
@@ -236,7 +326,6 @@
-
getConnection();
@@ -265,11 +354,11 @@
JOIN mescole ms ON ms.id = mm.idmescola
GROUP BY mm.idmatrice
) mg ON mg.idmatrice = m.id
- ORDER BY m.id DESC
+ ORDER BY
+ CASE WHEN TRIM(COALESCE(m.nome, '')) = '' THEN 1 ELSE 0 END,
+ m.nome ASC
");
-
-
function formatDateIT($d)
{
if (!$d || $d == '0000-00-00') return '';
@@ -280,54 +369,45 @@
echo "Nessuna matrice presente ";
} else {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
-
$dataIT = formatDateIT($row['data_produzione']);
- // gestione foto
$foto = $row['photo'] ?? '';
$pathFoto = "photos/matrici/" . $foto;
$placeholder = "assets/images/no-photo.png";
if ($foto && file_exists($pathFoto)) {
- $thumb = $pathFoto;
+ $thumb = $pathFoto;
$hasPhoto = true;
} else {
- $thumb = $placeholder;
+ $thumb = $placeholder;
$hasPhoto = false;
}
echo "";
- // colonna FOTO
- // colonna FOTO (robusta: NP appare solo se l'immagine non si carica)
- $imgSrc = $hasPhoto ? $thumb : ''; // se non c'è foto, src vuoto → trigger onerror
+ $imgSrc = $hasPhoto ? $thumb : '';
echo "
-
- NP
- ";
+
+ NP
+ ";
-
- // colonna NOME (con tooltip)
echo ""
. htmlspecialchars($row['nome'])
. " ";
- // colonna CLIENTE (con tooltip)
echo ""
. htmlspecialchars($row['cliente'])
. " ";
-
- // colonna LINEE
$lineeTxt = $row['linee_associate'] ?? '—';
$mescoleTxt = $row['mescole_associate'] ?? '';
$mescoleCount = (int)($row['mescole_count'] ?? 0);
@@ -335,12 +415,12 @@
$btnMescole = '';
if ($mescoleCount > 0) {
$btnMescole = "
-
- ";
+ class='btn btn-sm btn-outline-secondary ms-2 show-mescole'
+ data-nome='" . htmlspecialchars($row['nome'], ENT_QUOTES) . "'
+ data-mescole='" . htmlspecialchars($mescoleTxt, ENT_QUOTES) . "'
+ data-bs-toggle='tooltip' data-bs-title='Vedi mescole associate'>
+
+ ";
}
echo ""
@@ -348,8 +428,6 @@
. $btnMescole
. " ";
-
- // colonna AZIONI
echo "
-
- ";
+
+
+
+ ";
echo " ";
}
}
-
-
?>
-
+
@@ -439,6 +520,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Nuovi allegati
+
Trascina file oppure selezionali manualmente
+
+
📎 Seleziona file
+
+
+
+
Trascina qui PDF, immagini, HEIC, WEBP, DOC, DOCX
+
Oppure clicca per aprire la selezione file
+
+
+
+
+
+
Nessun nuovo file selezionato
+
+
+
+ Svuota selezione
+ ⬆️ Carica file
+
+
+
+
+
+
+
+
+
File già presenti
+
Apri, controlla o elimina allegati già caricati
+
+
⟳ Aggiorna
+
+
+
+
+
+
+
+
+
+ Formati previsti: PDF, JPG, JPEG, PNG, GIF, BMP, WEBP, HEIC, HEIF, DOC, DOCX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-