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 {
|
try {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { quantita, opzione } = body;
|
const { quantita, opzione, idMagazzino } = body;
|
||||||
|
|
||||||
if (!quantita || quantita <= 0) {
|
if (!quantita || quantita <= 0) {
|
||||||
return NextResponse.json(
|
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(
|
const result = await rimuoviArticoloDaMacchina(
|
||||||
articoloId,
|
articoloId,
|
||||||
macchinaId,
|
macchinaId,
|
||||||
quantita,
|
quantita,
|
||||||
opzione,
|
opzione,
|
||||||
session.user.email || session.user.name || "unknown"
|
session.user.email || session.user.name || "unknown",
|
||||||
|
idMagazzino
|
||||||
);
|
);
|
||||||
|
|
||||||
return NextResponse.json(result);
|
return NextResponse.json(result);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } 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";
|
||||||
|
|
||||||
interface ArticoliMacchinaModalProps {
|
interface ArticoliMacchinaModalProps {
|
||||||
macchinaId: number;
|
macchinaId: number;
|
||||||
|
|
@ -15,6 +16,7 @@ interface RimuoviModalState {
|
||||||
articolo: ArticoloAssegnatoMacchina;
|
articolo: ArticoloAssegnatoMacchina;
|
||||||
quantita: number;
|
quantita: number;
|
||||||
opzione: "carico" | "elimina";
|
opzione: "carico" | "elimina";
|
||||||
|
idMagazzino: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ArticoliMacchinaModal({
|
export default function ArticoliMacchinaModal({
|
||||||
|
|
@ -27,19 +29,53 @@ 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 [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) => {
|
const handleRimuoviClick = (articolo: ArticoloAssegnatoMacchina) => {
|
||||||
setRimuoviModal({
|
setRimuoviModal({
|
||||||
articolo,
|
articolo,
|
||||||
quantita: 1,
|
quantita: 1,
|
||||||
opzione: "carico",
|
opzione: "carico",
|
||||||
|
idMagazzino: null,
|
||||||
});
|
});
|
||||||
|
setSelectedStabilimento(null);
|
||||||
setError(null);
|
setError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfermaRimozione = async () => {
|
const handleConfermaRimozione = async () => {
|
||||||
if (!rimuoviModal) return;
|
if (!rimuoviModal) return;
|
||||||
|
|
||||||
|
if (rimuoviModal.opzione === "carico" && !rimuoviModal.idMagazzino) {
|
||||||
|
setError("Seleziona un magazzino per il rientro");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
|
|
@ -52,6 +88,7 @@ export default function ArticoliMacchinaModal({
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
quantita: rimuoviModal.quantita,
|
quantita: rimuoviModal.quantita,
|
||||||
opzione: rimuoviModal.opzione,
|
opzione: rimuoviModal.opzione,
|
||||||
|
idMagazzino: rimuoviModal.idMagazzino,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -203,7 +240,7 @@ export default function ArticoliMacchinaModal({
|
||||||
name="opzione"
|
name="opzione"
|
||||||
value="elimina"
|
value="elimina"
|
||||||
checked={rimuoviModal.opzione === "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"
|
className="w-4 h-4 text-red-500"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -213,6 +250,62 @@ export default function ArticoliMacchinaModal({
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
|
|
||||||
<div className="px-5 py-4 border-t border-zinc-800 flex justify-end gap-3">
|
<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>
|
||||||
<button
|
<button
|
||||||
onClick={handleConfermaRimozione}
|
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"
|
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 ? (
|
{saving ? (
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,8 @@ export async function rimuoviArticoloDaMacchina(
|
||||||
idmacchina: number,
|
idmacchina: number,
|
||||||
quantita: number,
|
quantita: number,
|
||||||
opzione: "carico" | "elimina",
|
opzione: "carico" | "elimina",
|
||||||
user: string = "system"
|
user: string = "system",
|
||||||
|
idMagazzino?: number
|
||||||
): Promise<{ success: boolean; message: string }> {
|
): Promise<{ success: boolean; message: string }> {
|
||||||
const [existingRows] = await db.execute<(RowDataPacket & { id: number; qtain: number; qtaout: number })[]>(
|
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",
|
"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})`);
|
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(
|
await db.execute(
|
||||||
`UPDATE art_macchine_parti
|
`UPDATE art_macchine_parti
|
||||||
SET qtaout = qtaout + :quantita, updated_at = NOW()
|
SET qtaout = qtaout + :quantita, updated_at = NOW()
|
||||||
|
|
@ -131,16 +136,22 @@ export async function rimuoviArticoloDaMacchina(
|
||||||
{ quantita, idart, idmacchina }
|
{ quantita, idart, idmacchina }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (opzione === "carico") {
|
if (opzione === "carico" && idMagazzino) {
|
||||||
const [articoloRows] = await db.execute<(RowDataPacket & { descrizione: string; codice: string })[]>(
|
const [articoloRows] = await db.execute<(RowDataPacket & { descrizione: string; codice: string })[]>(
|
||||||
"SELECT descrizione, codice FROM articoli WHERE id = :idart LIMIT 1",
|
"SELECT descrizione, codice FROM articoli WHERE id = :idart LIMIT 1",
|
||||||
{ idart }
|
{ idart }
|
||||||
);
|
);
|
||||||
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)
|
`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)`,
|
VALUES (:id_articolo, :articolo_codice, :articolo_descrizione, :quantita, 1, :causale, :utente, :id_magazzino, :nome_magazzino)`,
|
||||||
{
|
{
|
||||||
id_articolo: idart,
|
id_articolo: idart,
|
||||||
articolo_codice: articolo?.codice || "",
|
articolo_codice: articolo?.codice || "",
|
||||||
|
|
@ -148,6 +159,8 @@ export async function rimuoviArticoloDaMacchina(
|
||||||
quantita,
|
quantita,
|
||||||
causale: "Rientro da macchina",
|
causale: "Rientro da macchina",
|
||||||
utente: user,
|
utente: user,
|
||||||
|
id_magazzino: idMagazzino,
|
||||||
|
nome_magazzino: magazzinoNome,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,5 +33,6 @@ export interface AssegnaArticoloInput {
|
||||||
export interface RimuoviArticoloInput {
|
export interface RimuoviArticoloInput {
|
||||||
quantita: number;
|
quantita: number;
|
||||||
opzione: "carico" | "elimina";
|
opzione: "carico" | "elimina";
|
||||||
|
idMagazzino?: number;
|
||||||
user?: string;
|
user?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue