correta associazione macchine-stabilimento
This commit is contained in:
parent
42ad52e344
commit
819cee2bec
3 changed files with 97 additions and 98 deletions
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import type { ArticoloAssegnatoMacchina } from "@/src/types/artMacchineParti";
|
import type { ArticoloAssegnatoMacchina } from "@/src/types/artMacchineParti";
|
||||||
import type { Stabilimento, Magazzino } from "@/src/types/stabilimento";
|
import type { Magazzino } from "@/src/types/stabilimento";
|
||||||
|
|
||||||
interface ArticoliMacchinaModalProps {
|
interface ArticoliMacchinaModalProps {
|
||||||
macchinaId: number;
|
macchinaId: number;
|
||||||
macchinaNome: string;
|
macchinaNome: string;
|
||||||
|
macchinaStabilimentoId: number | null;
|
||||||
articoli: ArticoloAssegnatoMacchina[];
|
articoli: ArticoloAssegnatoMacchina[];
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onArticoloRimosso: () => void;
|
onArticoloRimosso: () => void;
|
||||||
|
|
@ -22,6 +23,7 @@ interface RimuoviModalState {
|
||||||
export default function ArticoliMacchinaModal({
|
export default function ArticoliMacchinaModal({
|
||||||
macchinaId,
|
macchinaId,
|
||||||
macchinaNome,
|
macchinaNome,
|
||||||
|
macchinaStabilimentoId,
|
||||||
articoli,
|
articoli,
|
||||||
onClose,
|
onClose,
|
||||||
onArticoloRimosso,
|
onArticoloRimosso,
|
||||||
|
|
@ -29,33 +31,28 @@ export default function ArticoliMacchinaModal({
|
||||||
const [rimuoviModal, setRimuoviModal] = useState<RimuoviModalState | null>(null);
|
const [rimuoviModal, setRimuoviModal] = useState<RimuoviModalState | null>(null);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [stabilimenti, setStabilimenti] = useState<Stabilimento[]>([]);
|
|
||||||
const [magazzini, setMagazzini] = useState<Magazzino[]>([]);
|
const [magazzini, setMagazzini] = useState<Magazzino[]>([]);
|
||||||
const [selectedStabilimento, setSelectedStabilimento] = useState<number | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchMagazzini() {
|
||||||
|
if (!macchinaStabilimentoId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [stabRes, magRes] = await Promise.all([
|
const res = await fetch("/api/magazzini");
|
||||||
fetch("/api/stabilimenti"),
|
if (res.ok) {
|
||||||
fetch("/api/magazzini"),
|
const data = await res.json();
|
||||||
]);
|
// Filtra solo i magazzini dello stabilimento della macchina
|
||||||
if (stabRes.ok && magRes.ok) {
|
const filtered = data.magazzini.filter(
|
||||||
const stabData = await stabRes.json();
|
(m: Magazzino) => m.id_stabilimento === macchinaStabilimentoId
|
||||||
const magData = await magRes.json();
|
);
|
||||||
setStabilimenti(stabData.stabilimenti);
|
setMagazzini(filtered);
|
||||||
setMagazzini(magData.magazzini);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Errore caricamento stabilimenti/magazzini:", err);
|
console.error("Errore caricamento magazzini:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchMagazzini();
|
||||||
}, []);
|
}, [macchinaStabilimentoId]);
|
||||||
|
|
||||||
const filteredMagazzini = selectedStabilimento
|
|
||||||
? magazzini.filter((m) => m.id_stabilimento === selectedStabilimento)
|
|
||||||
: magazzini;
|
|
||||||
|
|
||||||
const handleRimuoviClick = (articolo: ArticoloAssegnatoMacchina) => {
|
const handleRimuoviClick = (articolo: ArticoloAssegnatoMacchina) => {
|
||||||
setRimuoviModal({
|
setRimuoviModal({
|
||||||
|
|
@ -64,7 +61,6 @@ export default function ArticoliMacchinaModal({
|
||||||
opzione: "carico",
|
opzione: "carico",
|
||||||
idMagazzino: null,
|
idMagazzino: null,
|
||||||
});
|
});
|
||||||
setSelectedStabilimento(null);
|
|
||||||
setError(null);
|
setError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -255,54 +251,39 @@ export default function ArticoliMacchinaModal({
|
||||||
<div className="space-y-3 p-4 rounded-lg bg-teal-900/20 border border-teal-700/30">
|
<div className="space-y-3 p-4 rounded-lg bg-teal-900/20 border border-teal-700/30">
|
||||||
<p className="text-sm font-medium text-teal-300">Seleziona il magazzino di destinazione</p>
|
<p className="text-sm font-medium text-teal-300">Seleziona il magazzino di destinazione</p>
|
||||||
|
|
||||||
<div>
|
{magazzini.length === 0 ? (
|
||||||
<label className="block text-xs text-zinc-400 mb-1">Stabilimento</label>
|
|
||||||
<select
|
|
||||||
value={selectedStabilimento || ""}
|
|
||||||
onChange={(e) => {
|
|
||||||
const stabId = e.target.value ? parseInt(e.target.value) : null;
|
|
||||||
setSelectedStabilimento(stabId);
|
|
||||||
setRimuoviModal({ ...rimuoviModal, idMagazzino: null });
|
|
||||||
}}
|
|
||||||
className="w-full px-3 py-2 bg-zinc-800 border border-zinc-700 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-teal-500"
|
|
||||||
>
|
|
||||||
<option value="">Seleziona stabilimento...</option>
|
|
||||||
{stabilimenti.map((stab) => (
|
|
||||||
<option key={stab.id} value={stab.id}>
|
|
||||||
{stab.descrizione}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-xs text-zinc-400 mb-1">Magazzino</label>
|
|
||||||
<select
|
|
||||||
value={rimuoviModal.idMagazzino || ""}
|
|
||||||
onChange={(e) =>
|
|
||||||
setRimuoviModal({
|
|
||||||
...rimuoviModal,
|
|
||||||
idMagazzino: e.target.value ? parseInt(e.target.value) : null,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
disabled={!selectedStabilimento}
|
|
||||||
className="w-full px-3 py-2 bg-zinc-800 border border-zinc-700 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-teal-500 disabled:opacity-50"
|
|
||||||
>
|
|
||||||
<option value="">
|
|
||||||
{selectedStabilimento ? "Seleziona magazzino..." : "Prima seleziona uno stabilimento"}
|
|
||||||
</option>
|
|
||||||
{filteredMagazzini.map((mag) => (
|
|
||||||
<option key={mag.id} value={mag.id}>
|
|
||||||
{mag.descrizione}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!rimuoviModal.idMagazzino && (
|
|
||||||
<p className="text-xs text-yellow-400">
|
<p className="text-xs text-yellow-400">
|
||||||
Devi selezionare un magazzino per confermare il rientro
|
Nessun magazzino disponibile per lo stabilimento di questa macchina
|
||||||
</p>
|
</p>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<label className="block text-xs text-zinc-400 mb-1">Magazzino</label>
|
||||||
|
<select
|
||||||
|
value={rimuoviModal.idMagazzino || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setRimuoviModal({
|
||||||
|
...rimuoviModal,
|
||||||
|
idMagazzino: e.target.value ? parseInt(e.target.value) : null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="w-full px-3 py-2 bg-zinc-800 border border-zinc-700 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-teal-500"
|
||||||
|
>
|
||||||
|
<option value="">Seleziona magazzino...</option>
|
||||||
|
{magazzini.map((mag) => (
|
||||||
|
<option key={mag.id} value={mag.id}>
|
||||||
|
{mag.descrizione}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!rimuoviModal.idMagazzino && (
|
||||||
|
<p className="text-xs text-yellow-400">
|
||||||
|
Devi selezionare un magazzino per confermare il rientro
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ export default function MacchineTree() {
|
||||||
const [showArticlesModal, setShowArticlesModal] = useState<{
|
const [showArticlesModal, setShowArticlesModal] = useState<{
|
||||||
macchinaId: number;
|
macchinaId: number;
|
||||||
macchinaNome: string;
|
macchinaNome: string;
|
||||||
|
macchinaStabilimentoId: number | null;
|
||||||
articoli: ArticoloAssegnatoMacchina[];
|
articoli: ArticoloAssegnatoMacchina[];
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
|
@ -243,6 +244,7 @@ export default function MacchineTree() {
|
||||||
setShowArticlesModal({
|
setShowArticlesModal({
|
||||||
macchinaId: nodeId,
|
macchinaId: nodeId,
|
||||||
macchinaNome: macchina.nome,
|
macchinaNome: macchina.nome,
|
||||||
|
macchinaStabilimentoId: macchina.id_stabilimento,
|
||||||
articoli: allArticoli,
|
articoli: allArticoli,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -301,14 +303,34 @@ export default function MacchineTree() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredNodes = useMemo(() => {
|
const filteredNodes = useMemo(() => {
|
||||||
if (!selectedStabilimento) return nodes;
|
if (!selectedStabilimento) return [];
|
||||||
return nodes.filter((n) => n.id_stabilimento === selectedStabilimento.id);
|
return nodes.filter((n) => n.id_stabilimento === selectedStabilimento.id);
|
||||||
}, [nodes, selectedStabilimento]);
|
}, [nodes, selectedStabilimento]);
|
||||||
|
|
||||||
const rootNodes = filteredNodes.filter((n) => n.id_padre === null);
|
const rootNodes = filteredNodes.filter((n) => n.id_padre === null);
|
||||||
|
|
||||||
const filteredCount = filteredNodes.length;
|
const filteredCount = filteredNodes.length;
|
||||||
const totalCount = nodes.length;
|
|
||||||
|
// Se non c'è stabilimento selezionato, mostra messaggio
|
||||||
|
if (!selectedStabilimento) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full">
|
||||||
|
<div className="mb-4">
|
||||||
|
<h2 className="text-lg font-semibold text-white">Macchine</h2>
|
||||||
|
<p className="text-xs text-zinc-500">Seleziona uno stabilimento per visualizzare le macchine</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 flex flex-col items-center justify-center text-center p-8 border-2 border-dashed border-zinc-800 rounded-lg">
|
||||||
|
<svg className="w-12 h-12 text-zinc-700 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
|
</svg>
|
||||||
|
<p className="text-zinc-500 text-sm mb-2">Nessuno stabilimento selezionato</p>
|
||||||
|
<p className="text-zinc-600 text-xs">
|
||||||
|
Seleziona uno stabilimento dal menu in alto per visualizzare e gestire le macchine
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
|
|
@ -317,10 +339,7 @@ export default function MacchineTree() {
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-white">Macchine</h2>
|
<h2 className="text-lg font-semibold text-white">Macchine</h2>
|
||||||
<p className="text-xs text-zinc-500">
|
<p className="text-xs text-zinc-500">
|
||||||
{selectedStabilimento
|
{filteredCount} elementi in {selectedStabilimento.descrizione}
|
||||||
? `${filteredCount} di ${totalCount} elementi`
|
|
||||||
: `${totalCount} elementi nell'albero`
|
|
||||||
}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -335,13 +354,6 @@ export default function MacchineTree() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Info selezione corrente */}
|
|
||||||
{selectedStabilimento && (
|
|
||||||
<div className="mb-3 px-3 py-2 rounded-lg bg-blue-900/20 border border-blue-700/30 text-xs text-blue-300">
|
|
||||||
Filtro attivo: {selectedStabilimento.descrizione}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Indicatore clonazione */}
|
{/* Indicatore clonazione */}
|
||||||
{isCloning && (
|
{isCloning && (
|
||||||
<div className="mb-3 px-3 py-2 rounded-lg bg-blue-900/30 border border-blue-700/50 flex items-center gap-2">
|
<div className="mb-3 px-3 py-2 rounded-lg bg-blue-900/30 border border-blue-700/50 flex items-center gap-2">
|
||||||
|
|
@ -391,16 +403,10 @@ export default function MacchineTree() {
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
</svg>
|
</svg>
|
||||||
<p className="text-zinc-500 text-sm mb-2">
|
<p className="text-zinc-500 text-sm mb-2">
|
||||||
{selectedStabilimento
|
Nessuna macchina in "{selectedStabilimento.descrizione}"
|
||||||
? `Nessuna macchina in "${selectedStabilimento.descrizione}"`
|
|
||||||
: "Nessuna macchina presente"
|
|
||||||
}
|
|
||||||
</p>
|
</p>
|
||||||
<p className="text-zinc-600 text-xs mb-4">
|
<p className="text-zinc-600 text-xs mb-4">
|
||||||
{selectedStabilimento
|
Clicca sul pulsante + per aggiungere la prima macchina
|
||||||
? "Seleziona un altro stabilimento o aggiungi una nuova macchina"
|
|
||||||
: "Clicca sul pulsante + per aggiungere la prima macchina"
|
|
||||||
}
|
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={handleAddMachine}
|
onClick={handleAddMachine}
|
||||||
|
|
@ -483,6 +489,7 @@ export default function MacchineTree() {
|
||||||
<ArticoliMacchinaModal
|
<ArticoliMacchinaModal
|
||||||
macchinaId={showArticlesModal.macchinaId}
|
macchinaId={showArticlesModal.macchinaId}
|
||||||
macchinaNome={showArticlesModal.macchinaNome}
|
macchinaNome={showArticlesModal.macchinaNome}
|
||||||
|
macchinaStabilimentoId={showArticlesModal.macchinaStabilimentoId}
|
||||||
articoli={showArticlesModal.articoli}
|
articoli={showArticlesModal.articoli}
|
||||||
onClose={() => setShowArticlesModal(null)}
|
onClose={() => setShowArticlesModal(null)}
|
||||||
onArticoloRimosso={() => {
|
onArticoloRimosso={() => {
|
||||||
|
|
|
||||||
|
|
@ -143,15 +143,9 @@ export async function rimuoviArticoloDaMacchina(
|
||||||
);
|
);
|
||||||
const articolo = articoloRows[0];
|
const articolo = articoloRows[0];
|
||||||
|
|
||||||
const [magazzinoRows] = await db.execute<(RowDataPacket & { descrizione: string })[]>(
|
|
||||||
"SELECT descrizione FROM magazzini WHERE id = :idMagazzino LIMIT 1",
|
|
||||||
{ idMagazzino }
|
|
||||||
);
|
|
||||||
const magazzinoNome = magazzinoRows[0]?.descrizione || "";
|
|
||||||
|
|
||||||
await db.execute(
|
await db.execute(
|
||||||
`INSERT INTO movimenti (id_articolo, articolo_codice, articolo_descrizione, quantita, tipo_movimento, causale, utente, id_magazzino, nome_magazzino)
|
`INSERT INTO movimenti (id_articolo, articolo_codice, articolo_descrizione, quantita, tipo_movimento, causale, utente, id_magazzino_destinazione)
|
||||||
VALUES (:id_articolo, :articolo_codice, :articolo_descrizione, :quantita, 1, :causale, :utente, :id_magazzino, :nome_magazzino)`,
|
VALUES (:id_articolo, :articolo_codice, :articolo_descrizione, :quantita, 1, :causale, :utente, :id_magazzino_destinazione)`,
|
||||||
{
|
{
|
||||||
id_articolo: idart,
|
id_articolo: idart,
|
||||||
articolo_codice: articolo?.codice || "",
|
articolo_codice: articolo?.codice || "",
|
||||||
|
|
@ -159,10 +153,27 @@ export async function rimuoviArticoloDaMacchina(
|
||||||
quantita,
|
quantita,
|
||||||
causale: "Rientro da macchina",
|
causale: "Rientro da macchina",
|
||||||
utente: user,
|
utente: user,
|
||||||
id_magazzino: idMagazzino,
|
id_magazzino_destinazione: idMagazzino,
|
||||||
nome_magazzino: magazzinoNome,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Aggiorna la giacenza nel magazzino
|
||||||
|
const [existingGiacenza] = await db.execute<(RowDataPacket & { id: number; quantita: number })[]>(
|
||||||
|
"SELECT id, quantita FROM giacenze WHERE articolo_id = :articoloId AND id_magazzino = :magazzinoId",
|
||||||
|
{ articoloId: idart, magazzinoId: idMagazzino }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingGiacenza.length > 0) {
|
||||||
|
await db.execute(
|
||||||
|
"UPDATE giacenze SET quantita = quantita + :quantita WHERE articolo_id = :articoloId AND id_magazzino = :magazzinoId",
|
||||||
|
{ quantita, articoloId: idart, magazzinoId: idMagazzino }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await db.execute(
|
||||||
|
"INSERT INTO giacenze (articolo_id, id_magazzino, quantita) VALUES (:articoloId, :magazzinoId, :quantita)",
|
||||||
|
{ articoloId: idart, magazzinoId: idMagazzino, quantita }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true, message: opzione === "carico" ? "Articolo rientrato in magazzino" : "Articolo rimosso" };
|
return { success: true, message: opzione === "carico" ? "Articolo rientrato in magazzino" : "Articolo rimosso" };
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue