chore: upload parte 1 - logica
DevSecOps Enterprise Pipeline / security-gate-and-deploy (push) Failing after 41s

This commit is contained in:
2026-06-01 15:35:53 +01:00
parent a63625d228
commit 9c14a19a87
127 changed files with 22255 additions and 0 deletions
+174
View File
@@ -0,0 +1,174 @@
import { NextRequest, NextResponse } from "next/server";
import { getDb } from "@/lib/db";
export async function GET(request: NextRequest) {
try {
const sql = getDb();
const { searchParams } = new URL(request.url);
const search = searchParams.get("search");
const orderId = searchParams.get("orderId");
let query = `
SELECT pl.*,
po.po_number,
c.name AS customer_name,
c.code AS customer_code,
c.email AS customer_email,
c.phone AS customer_phone,
c.address AS customer_address,
p.name AS product_name,
p.sku AS product_sku,
(SELECT COUNT(*) FROM packing_list_serials pls WHERE pls.packing_list_id = pl.id) AS serial_count
FROM packing_lists pl
JOIN purchase_orders po ON po.id = pl.purchase_order_id
JOIN customers c ON c.id = po.customer_id
JOIN purchase_order_items poi ON poi.id = pl.po_item_id
JOIN products p ON p.id = poi.product_id
`;
const conditions: string[] = [];
const params: (string | number)[] = [];
if (orderId) {
params.push(Number(orderId));
conditions.push(`pl.purchase_order_id = $${params.length}`);
}
if (search) {
params.push(`%${search}%`);
const i = params.length;
conditions.push(
`(pl.packing_number ILIKE $${i} OR po.po_number ILIKE $${i} OR c.name ILIKE $${i} OR p.name ILIKE $${i})`
);
}
if (conditions.length > 0) {
query += ` WHERE ${conditions.join(" AND ")}`;
}
query += ` ORDER BY pl.created_at DESC`;
const rows = await sql(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error("[v0] Packing list GET error:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Failed to fetch packing lists" },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const sql = getDb();
const body = await request.json();
const { purchase_order_id, po_item_id, serial_numbers, notes } = body;
if (!purchase_order_id || !po_item_id || !serial_numbers?.length) {
return NextResponse.json(
{ error: "purchase_order_id, po_item_id, and serial_numbers are required" },
{ status: 400 }
);
}
const quantity = serial_numbers.length;
// Fetch customer name for packing number generation
const custRows = await sql(
`SELECT c.name FROM purchase_orders po JOIN customers c ON c.id = po.customer_id WHERE po.id = $1`,
[purchase_order_id]
);
if (custRows.length === 0) {
return NextResponse.json({ error: "Purchase order not found" }, { status: 404 });
}
const customerName = String(custRows[0].name).replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
// Generate packing number: PL-EACH-YYYY_MM_DD-RR-CUSTOMERNAME
const now = new Date();
const yyyy = now.getFullYear();
const mm = String(now.getMonth() + 1).padStart(2, "0");
const dd = String(now.getDate()).padStart(2, "0");
const datePrefix = `PL-EACH-${yyyy}_${mm}_${dd}`;
const dateSuffix = `-${customerName}`;
const pattern = `${datePrefix}-__-${customerName}`;
// Count existing packing lists with same date + customer to determine revision
const existingRows = await sql(
`SELECT COUNT(*) AS cnt FROM packing_lists WHERE packing_number LIKE $1`,
[`${datePrefix}-%${dateSuffix}`]
);
const revision = Number(existingRows[0].cnt) + 1;
const packing_number = `${datePrefix}-${String(revision).padStart(2, "0")}${dateSuffix}`;
// Check remaining capacity on the PO item
const poItemRows = await sql(
`SELECT poi.quantity, COALESCE(poi.shipped_quantity, 0) AS shipped_quantity, poi.product_id, p.name AS product_name
FROM purchase_order_items poi
JOIN products p ON p.id = poi.product_id
WHERE poi.id = $1`,
[po_item_id]
);
if (poItemRows.length === 0) {
return NextResponse.json({ error: "PO item not found" }, { status: 404 });
}
const poItem = poItemRows[0];
const productId = poItemRows[0].product_id;
const remaining = Number(poItem.quantity) - Number(poItem.shipped_quantity);
if (quantity > remaining) {
return NextResponse.json(
{ error: `Only ${remaining} units remaining to ship for ${poItem.product_name}` },
{ status: 400 }
);
}
// Check for duplicate serial numbers within the same Purchase Order
if (serial_numbers.length > 0) {
const placeholders = serial_numbers.map((_: string, i: number) => `$${i + 2}`).join(", ");
const dupes = await sql(
`SELECT pls.serial_number
FROM packing_list_serials pls
JOIN packing_lists pl ON pl.id = pls.packing_list_id
WHERE pl.purchase_order_id = $1
AND pls.serial_number IN (${placeholders})`,
[purchase_order_id, ...serial_numbers]
);
if (dupes.length > 0) {
const dupeList = dupes.map((d: { serial_number: string }) => d.serial_number).join(", ");
return NextResponse.json(
{ error: `Duplicate serial number(s) in this PO: ${dupeList}` },
{ status: 400 }
);
}
}
// Create packing list
const plRows = await sql(
`INSERT INTO packing_lists (purchase_order_id, po_item_id, packing_number, quantity, notes)
VALUES ($1, $2, $3, $4, $5)
RETURNING *`,
[purchase_order_id, po_item_id, packing_number, quantity, notes || null]
);
const packingList = plRows[0];
// Insert serial numbers
for (const sn of serial_numbers) {
await sql(
`INSERT INTO packing_list_serials (packing_list_id, serial_number)
VALUES ($1, $2)`,
[packingList.id, sn]
);
}
// Update shipped_quantity on the PO item
await sql(
`UPDATE purchase_order_items SET shipped_quantity = COALESCE(shipped_quantity, 0) + $1 WHERE id = $2`,
[quantity, po_item_id]
);
return NextResponse.json(packingList, { status: 201 });
} catch (error) {
console.error("[v0] Packing list POST error:", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "Failed to create packing list" },
{ status: 500 }
);
}
}