added note and date to identification parts

This commit is contained in:
Claudio 2025-10-08 17:34:21 +02:00
parent b51936f784
commit a9827e4e81
6 changed files with 1307 additions and 208 deletions

View File

@ -0,0 +1,59 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Risale a root/vendor/
use Dotenv\Dotenv;
// Set JSON header
header('Content-Type: application/json');
// Debug: Log the path where we expect the .env file
$envPath = dirname(__DIR__, 2);
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Expected .env path: ' . $envPath . PHP_EOL, FILE_APPEND);
// Carica il file .env dalla root del progetto
try {
$dotenv = Dotenv::createImmutable($envPath);
$dotenv->load();
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore caricamento .env: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore caricamento configurazione: ' . $e->getMessage()]);
exit(1);
}
// Recupera le variabili d'ambiente
$dbHost = $_ENV['DB_HOST'];
$dbName = $_ENV['DB_DATABASE'];
$dbUser = $_ENV['DB_USERNAME'];
$dbPass = $_ENV['DB_PASSWORD'];
$dbPrefix = $_ENV['DB_PREFIX'];
// Debug: Log database connection details (excluding password)
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . " - DB Connection: host=$dbHost, dbname=$dbName, user=$dbUser, prefix=$dbPrefix" . PHP_EOL, FILE_APPEND);
// Connessione al database MySQL
try {
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore connessione DB: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore connessione al database: ' . $e->getMessage()]);
exit(1);
}
try {
// Query per recuperare i valori distinti di MacroMatrice, escludendo quelli che iniziano con '*' e ordinandoli
$query = "SELECT DISTINCT MacroMatrice FROM {$dbPrefix}matrici WHERE MacroMatrice IS NOT NULL AND MacroMatrice NOT LIKE '*%' ORDER BY MacroMatrice ASC";
$stmt = $pdo->prepare($query);
$stmt->execute();
$macroMatrici = $stmt->fetchAll(PDO::FETCH_COLUMN);
// Debug: Log del numero di MacroMatrice recuperate
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Retrieved ' . count($macroMatrici) . ' MacroMatrice from database' . PHP_EOL, FILE_APPEND);
// Restituisci risposta JSON
echo json_encode(['success' => true, 'value' => $macroMatrici]);
} catch (PDOException $e) {
// Log errore e restituisci risposta di errore
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore nel recupero delle MacroMatrice: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore nel recupero delle MacroMatrice: ' . $e->getMessage()]);
exit(1);
}

View File

@ -40,19 +40,19 @@ try {
} }
try { try {
// Query to fetch matrices, excluding those starting with '*' and sorting by NomeMatrice // Query per recuperare le matrici, includendo MacroMatrice, escludendo quelle che iniziano con '*' e ordinandole
$query = "SELECT IdMatrice, NomeMatrice FROM {$dbPrefix}matrici WHERE NomeMatrice NOT LIKE '*%' ORDER BY NomeMatrice ASC"; $query = "SELECT IdMatrice, NomeMatrice, MacroMatrice FROM {$dbPrefix}matrici WHERE NomeMatrice NOT LIKE '*%' ORDER BY NomeMatrice ASC";
$stmt = $pdo->prepare($query); $stmt = $pdo->prepare($query);
$stmt->execute(); $stmt->execute();
$matrici = $stmt->fetchAll(PDO::FETCH_ASSOC); $matrici = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Debug: Log the number of matrices retrieved // Debug: Log del numero di matrici recuperate
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Retrieved ' . count($matrici) . ' matrices from database' . PHP_EOL, FILE_APPEND); file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Retrieved ' . count($matrici) . ' matrices from database' . PHP_EOL, FILE_APPEND);
// Return JSON response // Restituisci risposta JSON
echo json_encode(['success' => true, 'value' => $matrici]); echo json_encode(['success' => true, 'value' => $matrici]);
} catch (PDOException $e) { } catch (PDOException $e) {
// Log error and return error response // Log errore e restituisci risposta di errore
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore nel recupero delle matrici: ' . $e->getMessage() . PHP_EOL, FILE_APPEND); file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore nel recupero delle matrici: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore nel recupero delle matrici: ' . $e->getMessage()]); echo json_encode(['success' => false, 'message' => 'Errore nel recupero delle matrici: ' . $e->getMessage()]);
exit(1); exit(1);

View File

@ -14,9 +14,9 @@ if (!$iddatadb) {
} }
try { try {
$stmt = $pdo->prepare("SELECT id, iddatadb, part_number, part_description FROM identification_parts WHERE iddatadb = :iddatadb ORDER BY part_number ASC"); $stmt = $pdo->prepare("SELECT id, iddatadb, part_number, part_description, idmatrice, note, dateexpiry FROM identification_parts WHERE iddatadb = :iddatadb ORDER BY part_number ASC");
$stmt->execute([':iddatadb' => $iddatadb]); $stmt->execute([':iddatadb' => $iddatadb]);
$parts = $stmt->fetchAll(); $parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['success' => true, 'parts' => $parts]); echo json_encode(['success' => true, 'parts' => $parts]);
} catch (PDOException $e) { } catch (PDOException $e) {

View File

@ -8,34 +8,61 @@
<div class="modal-body"> <div class="modal-body">
<div class="row"> <div class="row">
<div class="col-md-9"> <div class="col-md-9">
<!-- Prima riga: Elenco Parti, Mix, 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;">
<h6 style="margin: 0;">Elenco Parti</h6> <h6 style="margin: 0;">Elenco Parti</h6>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<input type="checkbox" id="showMixParts" name="showMixParts" style="margin-right: 5px;">
<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-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 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>
</div> </div>
</div> </div>
<!-- Seconda riga: +, M, Matrice globale, Propaga --> <!-- Seconda riga: +, M, MacroMatrice, Matrice globale, Propaga -->
<div style="display: flex; align-items: center; margin-bottom: 10px;"> <div style="display: flex; align-items: center; margin-bottom: 10px;">
<button type="button" class="btn btn-success btn-sm add-row-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 5px;"><i class="fas fa-plus fa-xs"></i></button> <button type="button" class="btn btn-success btn-sm add-row-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 5px;"><i class="fas fa-plus fa-xs"></i></button>
<button type="button" class="btn btn-primary btn-sm add-mix-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 10px;">M</button> <button type="button" class="btn btn-primary btn-sm add-mix-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 10px;">M</button>
<select id="macro-matrice-filter" class="form-control form-control-sm ms-2" style="width: 200px !important; min-width: 200px !important; margin-right: 10px;">
<option value="">Tutte le MacroMatrici</option>
</select>
<select id="global-matrice" class="form-control form-control-sm" style="width: 350px !important; margin-right: 10px;"></select> <select id="global-matrice" class="form-control form-control-sm" style="width: 350px !important; margin-right: 10px;"></select>
<button type="button" class="btn btn-primary btn-sm propagate-all-btn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-arrow-right fa-xs"></i> Propaga a tutte</button> <button type="button" class="btn btn-primary btn-sm propagate-all-btn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-arrow-right fa-xs"></i> Propaga a tutte</button>
</div> </div>
<table class="table table-striped table-sm" id="partsTable"> <table class="table table-striped table-sm" id="partsTable">
<thead> <thead>
<tr> <tr>
<th>Num. Parte</th> <th style="width: 80px;">Numero</th>
<th>Descrizione Parte</th> <th>Descrizione</th>
<th>Matrice</th> <th style="width: 200px;">Matrice</th>
<th>Azioni</th> <th style="width: 150px;">
<input type="date" class="form-control form-control-sm propagate-date-input" style="width: 130px; margin-left: 5px; display: inline-block;" title="Propaga data a tutte le parti">
</th>
<th style="width: 200px;">
<button type="button" class="btn btn-light btn-sm propagate-note-btn" style="padding: 0.2rem 0.4rem; font-size: 0.9rem; margin-left: 5px;" title="Propaga nota a tutte le parti">
<i class="fas fa-sticky-note"></i>
</button>
Azioni
</th>
</tr> </tr>
</thead> </thead>
<tbody id="partsTableBody"> <tbody id="partsTableBody">
<!-- Righe generate dinamicamente --> <tr data-part-id="new">
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione"></td>
<td>
<div style="display: flex; align-items: center;">
<button type="button" class="btn btn-primary btn-sm propagate-matrice-btn" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 3px;"><i class="fas fa-arrow-right fa-xs"></i></button>
<select class="part-matrice form-control form-control-sm" style="width: 150px;"></select>
</div>
</td>
<td><input type="date" class="form-control form-control-sm part-dateexpiry" style="width: 130px;"></td>
<td>
<button type="button" class="btn btn-light btn-sm note-btn" style="padding: 0.2rem 0.4rem; font-size: 0.9rem;" title="Aggiungi/Modifica nota"><i class="fas fa-sticky-note"></i></button>
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -59,6 +86,62 @@
</div> </div>
</div> </div>
<!-- Modale per la nota -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="noteModalLabel">Nota per Parte</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<textarea class="form-control part-note" rows="5" placeholder="Inserisci una nota"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
<button type="button" class="btn btn-primary btn-sm save-note-btn">Salva</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="commonNoteModal" tabindex="-1" aria-labelledby="commonNoteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="commonNoteModalLabel">Nota comune per tutte le parti</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<textarea class="form-control part-note" rows="4" placeholder="Inserisci nota comune"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
<button type="button" class="btn btn-primary save-common-note-btn">Salva</button>
</div>
</div>
</div>
</div>
<!-- Modale di conferma per l'eliminazione -->
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="confirmDeleteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmDeleteModalLabel">Conferma Eliminazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Sei sicuro di voler eliminare questa parte?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
<button type="button" class="btn btn-danger btn-sm" id="confirmDeleteBtn">Elimina</button>
</div>
</div>
</div>
</div>
<style> <style>
#partsModal { #partsModal {
z-index: 1060 !important; z-index: 1060 !important;
@ -104,20 +187,25 @@
} }
#global-matrice, #global-matrice,
.part-matrice { .part-matrice,
#macro-matrice-filter {
width: 100% !important; width: 100% !important;
min-width: 100% !important; min-width: 100% !important;
} }
.select2-container--default #global-matrice { .select2-container--default #global-matrice {
width: 350px !important; width: 350px !important;
/* Aumentato per dropdown più lungo */
min-width: 350px !important; min-width: 350px !important;
} }
.select2-container--default #macro-matrice-filter {
width: 200px !important;
min-width: 200px !important;
}
.select2-container--default .part-matrice { .select2-container--default .part-matrice {
width: 100% !important; width: 150px !important;
min-width: 100% !important; min-width: 150px !important;
} }
.select2-container--default .select2-selection--single { .select2-container--default .select2-selection--single {
@ -152,4 +240,75 @@
padding: 0.1rem 0.3rem !important; padding: 0.1rem 0.3rem !important;
font-size: 0.8rem !important; font-size: 0.8rem !important;
} }
.save-status,
.save-loading {
margin-left: 5px;
}
#confirmDeleteModal {
z-index: 1070 !important;
}
#confirmDeleteModal .modal-backdrop {
z-index: 1065 !important;
}
.note-btn {
padding: 0.2rem 0.4rem !important;
/* Aumentato leggermente il padding per un pulsante più grande */
font-size: 0.9rem !important;
/* Aumentato il font-size per un'icona più grande */
}
.note-btn.has-note {
color: #dc3545 !important;
/* Rosso quando la nota è presente */
}
#noteModal {
z-index: 1090 !important;
}
#noteModal .modal-backdrop {
z-index: 1085 !important;
}
#noteModal .modal-dialog {
position: relative;
z-index: 1090 !important;
}
#noteModal textarea {
resize: vertical;
}
.propagate-date-btn {
padding: 0.2rem 0.4rem !important;
font-size: 0.9rem !important;
}
.propagate-note-btn {
padding: 0.2rem 0.4rem !important;
font-size: 0.9rem !important;
}
#commonNoteModal {
z-index: 1095 !important;
/* Sopra #noteModal (1090) */
}
#commonNoteModal .modal-backdrop {
z-index: 1090 !important;
/* Sopra il backdrop di #noteModal (1085) */
}
#commonNoteModal .modal-dialog {
position: relative;
z-index: 1095 !important;
}
#commonNoteModal textarea {
resize: vertical;
}
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@ -15,50 +15,64 @@ if (!$iddatadb || empty($parts)) {
exit; exit;
} }
$part = $parts[0]; try {
$partId = $part['id'] ?? null; $pdo->beginTransaction();
$partNumber = $part['part_number'] ?? null; $results = [];
$partDescription = $part['part_description'] ?? '';
$mix = $part['mix'] ?? 'N';
$idmatrice = $part['idmatrice'] ?? null; // Nuovo campo idmatrice
if ($partDescription) { foreach ($parts as $part) {
try { $partId = $part['id'] ?? null;
if ($partId) { $partNumber = $part['part_number'] ?? null;
// UPDATE se la parte esiste $partDescription = $part['part_description'] ?? '';
$stmt = $pdo->prepare("UPDATE identification_parts $mix = $part['mix'] ?? 'N';
SET part_number = :part_number, $idmatrice = $part['idmatrice'] ?? null;
part_description = :part_description, $note = $part['note'] ?? null;
mix = :mix, $dateexpiry = $part['dateexpiry'] ?? null;
idmatrice = :idmatrice,
updated_at = NOW() if ($partDescription || $note || $dateexpiry) {
WHERE id = :id"); if ($partId) {
$stmt->execute([ // UPDATE se la parte esiste
':id' => $partId, $stmt = $pdo->prepare("UPDATE identification_parts
':part_number' => $partNumber, SET part_number = :part_number,
':part_description' => $partDescription, part_description = :part_description,
':mix' => $mix, mix = :mix,
':idmatrice' => $idmatrice // Può essere NULL idmatrice = :idmatrice,
]); note = :note,
echo json_encode(['success' => true, 'part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo']); dateexpiry = :dateexpiry,
} else { updated_at = NOW()
// INSERT per nuova parte WHERE id = :id");
$stmt = $pdo->prepare("INSERT INTO identification_parts $stmt->execute([
(iddatadb, part_number, part_description, mix, idmatrice, created_at, updated_at) ':id' => $partId,
VALUES (:iddatadb, :part_number, :part_description, :mix, :idmatrice, NOW(), NOW())"); ':part_number' => $partNumber,
$stmt->execute([ ':part_description' => $partDescription,
':iddatadb' => $iddatadb, ':mix' => $mix,
':part_number' => $partNumber, ':idmatrice' => $idmatrice,
':part_description' => $partDescription, ':note' => $note,
':mix' => $mix, ':dateexpiry' => $dateexpiry,
':idmatrice' => $idmatrice // Può essere NULL ]);
]); $results[] = ['part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo'];
$newId = $pdo->lastInsertId(); } else {
echo json_encode(['success' => true, 'part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo']); // INSERT per nuova parte
$stmt = $pdo->prepare("INSERT INTO identification_parts
(iddatadb, part_number, part_description, mix, idmatrice, note, dateexpiry, created_at, updated_at)
VALUES (:iddatadb, :part_number, :part_description, :mix, :idmatrice, :note, :dateexpiry, NOW(), NOW())");
$stmt->execute([
':iddatadb' => $iddatadb,
':part_number' => $partNumber,
':part_description' => $partDescription,
':mix' => $mix,
':idmatrice' => $idmatrice,
':note' => $note,
':dateexpiry' => $dateexpiry,
]);
$newId = $pdo->lastInsertId();
$results[] = ['part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo'];
}
} }
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
} }
} else {
echo json_encode(['success' => false, 'message' => 'Descrizione mancante']); $pdo->commit();
echo json_encode(['success' => true, 'results' => $results]);
} catch (PDOException $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
} }