/** * POST /api/materials/locators/generate — Auto Generate: the X × Y × Z product of three ranges. * Body { warehouseId, organizationId, xFrom, xTo, yFrom, yTo, zFrom, zTo, priorityNo?, isActive?, locatorTypeId? } * Response { status, message, created, skipped, totalCombinations, failed[] } * Creation goes through server/utils/locatorBulk.ts (shared with the Warehouse Builder). */ import refreshTokenHelper from "../../../utils/refreshTokenHelper" import forceLogoutHelper from "../../../utils/forceLogoutHelper" import errorHandlingHelper from "../../../utils/errorHandlingHelper" import getTokenHelper from "../../../utils/getTokenHelper" import { bulkCreateLocators } from "../../../utils/locatorBulk" // Range helper: numeric (zero padded), single letter (A–Z), otherwise static value(s) const generateRange = (from: string, to: string): string[] => { const range: string[] = [] const isNumeric = /^\d+$/.test(from) && /^\d+$/.test(to) const isSingleLetter = from.length === 1 && to.length === 1 && /^[A-Za-z]$/.test(from) && /^[A-Za-z]$/.test(to) if (isNumeric) { const fromNum = parseInt(from), toNum = parseInt(to) const padding = Math.max(2, from.length, to.length) for (let i = fromNum; i <= toNum; i++) range.push(String(i).padStart(padding, '0')) } else if (isSingleLetter) { const fromChar = from.toUpperCase().charCodeAt(0), toChar = to.toUpperCase().charCodeAt(0) for (let i = fromChar; i <= toChar; i++) range.push(String.fromCharCode(i)) } else if (from === to) { range.push(from) } else { range.push(from, to) } return range } const handleFunc = async (event: any, authToken: any = null) => { const token = authToken ?? await getTokenHelper(event) const body = await readBody(event) const { warehouseId, organizationId, xFrom, xTo, yFrom, yTo, zFrom, zTo, priorityNo = 50, isActive = true, locatorTypeId = null } = body if (!warehouseId || !organizationId) return { status: 400, message: 'Warehouse ID and Organization ID are required', created: 0, skipped: 0 } if (!xFrom || !xTo || !yFrom || !yTo || !zFrom || !zTo) return { status: 400, message: 'All range fields (X, Y, Z) are required', created: 0, skipped: 0 } const xRange = generateRange(String(xFrom), String(xTo)) const yRange = generateRange(String(yFrom), String(yTo)) const zRange = generateRange(String(zFrom), String(zTo)) const items: Array<{ x: string; y: string; z: string }> = [] for (const x of xRange) for (const y of yRange) for (const z of zRange) items.push({ x, y, z }) const totalCombinations = items.length if (totalCombinations > 5000) return { status: 400, message: `Too many combinations (${totalCombinations}); limit 5000`, created: 0, skipped: 0, totalCombinations } let created = 0, skipped = 0 const failed: any[] = [] for (let i = 0; i < items.length; i += 500) { const res = await bulkCreateLocators(event, token, { warehouseId: Number(warehouseId), organizationId: Number(organizationId), items: items.slice(i, i + 500), priorityNo: Number(priorityNo) || 50, isActive: isActive !== false, locatorTypeId: locatorTypeId ? Number(locatorTypeId) : null }) created += res.created.length skipped += res.skipped.length failed.push(...res.failed) } return { status: 200, message: `Successfully generated ${created} locators, ${skipped} skipped${failed.length ? `, ${failed.length} failed` : ''}`, created, skipped, failed, totalCombinations } } export default defineEventHandler(async (event) => { let data: any = {} try { data = await handleFunc(event) } catch (err: any) { try { const authToken: any = await refreshTokenHelper(event) data = await handleFunc(event, authToken) } catch (error: any) { data = errorHandlingHelper(err?.data ?? err, error?.data ?? error) forceLogoutHelper(event, data) } } return data })