corretto il carico dell'articolo eliminato dalla macchina in ArticoliMacchinaModale.tsx
This commit is contained in:
parent
15312ddb33
commit
42ad52e344
4 changed files with 124 additions and 9 deletions
|
|
@ -24,7 +24,7 @@ export async function DELETE(request: Request, { params }: RouteParams) {
|
|||
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { quantita, opzione } = body;
|
||||
const { quantita, opzione, idMagazzino } = body;
|
||||
|
||||
if (!quantita || quantita <= 0) {
|
||||
return NextResponse.json(
|
||||
|
|
@ -40,12 +40,20 @@ export async function DELETE(request: Request, { params }: RouteParams) {
|
|||
);
|
||||
}
|
||||
|
||||
if (opzione === "carico" && !idMagazzino) {
|
||||
return NextResponse.json(
|
||||
{ error: "Seleziona un magazzino per il rientro" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const result = await rimuoviArticoloDaMacchina(
|
||||
articoloId,
|
||||
macchinaId,
|
||||
quantita,
|
||||
opzione,
|
||||
session.user.email || session.user.name || "unknown"
|
||||
session.user.email || session.user.name || "unknown",
|
||||
idMagazzino
|
||||
);
|
||||
|
||||
return NextResponse.json(result);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { ArticoloAssegnatoMacchina } from "@/src/types/artMacchineParti";
|
||||
import type { Stabilimento, Magazzino } from "@/src/types/stabilimento";
|
||||
|
||||
interface ArticoliMacchinaModalProps {
|
||||
macchinaId: number;
|
||||
|
|
@ -15,6 +16,7 @@ interface RimuoviModalState {
|
|||
articolo: ArticoloAssegnatoMacchina;
|
||||
quantita: number;
|
||||
opzione: "carico" | "elimina";
|
||||
idMagazzino: number | null;
|
||||
}
|
||||
|
||||
export default function ArticoliMacchinaModal({
|
||||
|
|
@ -27,19 +29,53 @@ export default function ArticoliMacchinaModal({
|
|||
const [rimuoviModal, setRimuoviModal] = useState<RimuoviModalState | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [stabilimenti, setStabilimenti] = useState<Stabilimento[]>([]);
|
||||
const [magazzini, setMagazzini] = useState<Magazzino[]>([]);
|
||||
const [selectedStabilimento, setSelectedStabilimento] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const [stabRes, magRes] = await Promise.all([
|
||||
fetch("/api/stabilimenti"),
|
||||
fetch("/api/magazzini"),
|
||||
]);
|
||||
if (stabRes.ok && magRes.ok) {
|
||||
const stabData = await stabRes.json();
|
||||
const magData = await magRes.json();
|
||||
setStabilimenti(stabData.stabilimenti);
|
||||
setMagazzini(magData.magazzini);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Errore caricamento stabilimenti/magazzini:", err);
|
||||
}
|
||||
}
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const filteredMagazzini = selectedStabilimento
|
||||
? magazzini.filter((m) => m.id_stabilimento === selectedStabilimento)
|
||||
: magazzini;
|
||||
|
||||
const handleRimuoviClick = (articolo: ArticoloAssegnatoMacchina) => {
|
||||
setRimuoviModal({
|
||||
articolo,
|
||||
quantita: 1,
|
||||
opzione: "carico",
|
||||
idMagazzino: null,
|
||||
});
|
||||
setSelectedStabilimento(null);
|
||||
setError(null);
|
||||
};
|
||||
|
||||
const handleConfermaRimozione = async () => {
|
||||
if (!rimuoviModal) return;
|
||||
|
||||
if (rimuoviModal.opzione === "carico" && !rimuoviModal.idMagazzino) {
|
||||
setError("Seleziona un magazzino per il rientro");
|
||||
return;
|
||||
}
|
||||
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
|
||||
|
|
@ -52,6 +88,7 @@ export default function ArticoliMacchinaModal({
|
|||
body: JSON.stringify({
|
||||
quantita: rimuoviModal.quantita,
|
||||
opzione: rimuoviModal.opzione,
|
||||
idMagazzino: rimuoviModal.idMagazzino,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
|
@ -203,7 +240,7 @@ export default function ArticoliMacchinaModal({
|
|||
name="opzione"
|
||||
value="elimina"
|
||||
checked={rimuoviModal.opzione === "elimina"}
|
||||
onChange={() => setRimuoviModal({ ...rimuoviModal, opzione: "elimina" })}
|
||||
onChange={() => setRimuoviModal({ ...rimuoviModal, opzione: "elimina", idMagazzino: null })}
|
||||
className="w-4 h-4 text-red-500"
|
||||
/>
|
||||
<div>
|
||||
|
|
@ -213,6 +250,62 @@ export default function ArticoliMacchinaModal({
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{rimuoviModal.opzione === "carico" && (
|
||||
<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>
|
||||
|
||||
<div>
|
||||
<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">
|
||||
Devi selezionare un magazzino per confermare il rientro
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="px-5 py-4 border-t border-zinc-800 flex justify-end gap-3">
|
||||
|
|
@ -225,7 +318,7 @@ export default function ArticoliMacchinaModal({
|
|||
</button>
|
||||
<button
|
||||
onClick={handleConfermaRimozione}
|
||||
disabled={saving}
|
||||
disabled={saving || (rimuoviModal.opzione === "carico" && !rimuoviModal.idMagazzino)}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg disabled:opacity-50 flex items-center gap-2"
|
||||
>
|
||||
{saving ? (
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ export async function rimuoviArticoloDaMacchina(
|
|||
idmacchina: number,
|
||||
quantita: number,
|
||||
opzione: "carico" | "elimina",
|
||||
user: string = "system"
|
||||
user: string = "system",
|
||||
idMagazzino?: number
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
const [existingRows] = await db.execute<(RowDataPacket & { id: number; qtain: number; qtaout: number })[]>(
|
||||
"SELECT id, qtain, qtaout FROM art_macchine_parti WHERE idart = :idart AND idmacchina = :idmacchina LIMIT 1",
|
||||
|
|
@ -124,6 +125,10 @@ export async function rimuoviArticoloDaMacchina(
|
|||
throw new Error(`Quantità richiesta (${quantita}) supera quella disponibile (${quantitaDisponibile})`);
|
||||
}
|
||||
|
||||
if (opzione === "carico" && !idMagazzino) {
|
||||
throw new Error("Seleziona un magazzino per il rientro");
|
||||
}
|
||||
|
||||
await db.execute(
|
||||
`UPDATE art_macchine_parti
|
||||
SET qtaout = qtaout + :quantita, updated_at = NOW()
|
||||
|
|
@ -131,16 +136,22 @@ export async function rimuoviArticoloDaMacchina(
|
|||
{ quantita, idart, idmacchina }
|
||||
);
|
||||
|
||||
if (opzione === "carico") {
|
||||
if (opzione === "carico" && idMagazzino) {
|
||||
const [articoloRows] = await db.execute<(RowDataPacket & { descrizione: string; codice: string })[]>(
|
||||
"SELECT descrizione, codice FROM articoli WHERE id = :idart LIMIT 1",
|
||||
{ idart }
|
||||
);
|
||||
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(
|
||||
`INSERT INTO movimenti (id_articolo, articolo_codice, articolo_descrizione, quantita, tipo_movimento, causale, utente)
|
||||
VALUES (:id_articolo, :articolo_codice, :articolo_descrizione, :quantita, 1, :causale, :utente)`,
|
||||
`INSERT INTO movimenti (id_articolo, articolo_codice, articolo_descrizione, quantita, tipo_movimento, causale, utente, id_magazzino, nome_magazzino)
|
||||
VALUES (:id_articolo, :articolo_codice, :articolo_descrizione, :quantita, 1, :causale, :utente, :id_magazzino, :nome_magazzino)`,
|
||||
{
|
||||
id_articolo: idart,
|
||||
articolo_codice: articolo?.codice || "",
|
||||
|
|
@ -148,6 +159,8 @@ export async function rimuoviArticoloDaMacchina(
|
|||
quantita,
|
||||
causale: "Rientro da macchina",
|
||||
utente: user,
|
||||
id_magazzino: idMagazzino,
|
||||
nome_magazzino: magazzinoNome,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,5 +33,6 @@ export interface AssegnaArticoloInput {
|
|||
export interface RimuoviArticoloInput {
|
||||
quantita: number;
|
||||
opzione: "carico" | "elimina";
|
||||
idMagazzino?: number;
|
||||
user?: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue