const storeModel = require("../models/store.model"); const { sendError } = require("../utils/http"); const { logError } = require("../utils/logger"); function parsePositiveInteger(value) { const parsed = Number.parseInt(String(value), 10); return Number.isInteger(parsed) && parsed > 0 ? parsed : null; } function getHouseholdId(req) { return req.params.householdId || req.household?.id; } function getLocationId(req) { return req.params.locationId || req.params.storeId; } // Legacy global store catalog. Kept for system-admin compatibility. exports.getAllStores = async (req, res) => { try { const stores = await storeModel.getAllStores(); res.json(stores); } catch (error) { logError(req, "stores.getAllStores", error); sendError(res, 500, "Failed to fetch stores"); } }; exports.createStore = async (req, res) => { try { const { name, default_zones } = req.body; if (!name || name.trim().length === 0) { return sendError(res, 400, "Store name is required"); } const store = await storeModel.createStore(name.trim(), default_zones || null); res.status(201).json({ message: "Store created successfully", store, }); } catch (error) { logError(req, "stores.createStore", error); if (error.code === "23505") { return sendError(res, 400, "Store with this name already exists"); } sendError(res, 500, "Failed to create store"); } }; exports.updateStore = async (req, res) => { try { const { name, default_zones } = req.body; const store = await storeModel.updateStore(req.params.storeId, { name: name?.trim(), default_zones, }); if (!store) { return sendError(res, 404, "Store not found"); } res.json({ message: "Store updated successfully", store, }); } catch (error) { logError(req, "stores.updateStore", error); sendError(res, 500, "Failed to update store"); } }; exports.deleteStore = async (req, res) => { try { await storeModel.deleteStore(req.params.storeId); res.json({ message: "Store deleted successfully" }); } catch (error) { logError(req, "stores.deleteStore", error); if (error.message.includes("in use")) { return sendError(res, 400, error.message); } sendError(res, 500, "Failed to delete store"); } }; // Household-owned store/location management. exports.getHouseholdStores = async (req, res) => { try { const stores = await storeModel.getHouseholdStores(getHouseholdId(req)); res.json(stores); } catch (error) { logError(req, "stores.getHouseholdStores", error); sendError(res, 500, "Failed to fetch household stores"); } }; exports.createHouseholdStore = async (req, res) => { try { const householdId = getHouseholdId(req); const { name, location_name, address } = req.body; if (!name || name.trim().length === 0) { return sendError(res, 400, "Store name is required"); } const store = await storeModel.createHouseholdStore( householdId, name, location_name || "Default Location", address || null, req.user.id ); res.status(201).json({ message: "Store location created successfully", store, }); } catch (error) { logError(req, "stores.createHouseholdStore", error); if (error.code === "23505") { return sendError(res, 400, "Store or location already exists for this household"); } sendError(res, 500, "Failed to create store location"); } }; exports.updateHouseholdStore = async (req, res) => { try { const { name } = req.body; const householdStoreId = parsePositiveInteger(req.params.householdStoreId); if (!householdStoreId) { return sendError(res, 400, "Store ID must be a positive integer"); } if (!name || name.trim().length === 0) { return sendError(res, 400, "Store name is required"); } const store = await storeModel.updateHouseholdStore(getHouseholdId(req), householdStoreId, { name, }); if (!store) { return sendError(res, 404, "Store not found"); } res.json({ message: "Store updated successfully", store }); } catch (error) { logError(req, "stores.updateHouseholdStore", error); sendError(res, 500, "Failed to update store"); } }; exports.deleteHouseholdStore = async (req, res) => { try { const householdStoreId = parsePositiveInteger(req.params.householdStoreId); if (!householdStoreId) { return sendError(res, 400, "Store ID must be a positive integer"); } const deleted = await storeModel.deleteHouseholdStore(getHouseholdId(req), householdStoreId); if (!deleted) { return sendError(res, 404, "Store not found"); } res.json({ message: "Store deleted successfully" }); } catch (error) { logError(req, "stores.deleteHouseholdStore", error); if (error.message.includes("last store location")) { return sendError(res, 400, error.message); } sendError(res, 500, "Failed to delete store"); } }; exports.addLocationToStore = async (req, res) => { try { const householdStoreId = parsePositiveInteger(req.params.householdStoreId); const { name, address } = req.body; if (!householdStoreId) { return sendError(res, 400, "Store ID must be a positive integer"); } if (!name || name.trim().length === 0) { return sendError(res, 400, "Location name is required"); } const location = await storeModel.addLocationToStore( getHouseholdId(req), householdStoreId, name, address || null, req.user.id ); if (!location) { return sendError(res, 404, "Store not found"); } res.status(201).json({ message: "Location added successfully", store: location, }); } catch (error) { logError(req, "stores.addLocationToStore", error); if (error.code === "23505") { return sendError(res, 400, "Location already exists for this store"); } sendError(res, 500, "Failed to add location"); } }; exports.updateLocation = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); const { name, address, map_data } = req.body; if (!locationId) { return sendError(res, 400, "Location ID must be a positive integer"); } const location = await storeModel.updateLocation(getHouseholdId(req), locationId, { name, address, map_data, }); if (!location) { return sendError(res, 404, "Location not found"); } res.json({ message: "Location updated successfully", store: location }); } catch (error) { logError(req, "stores.updateLocation", error); sendError(res, 500, "Failed to update location"); } }; exports.deleteLocation = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); if (!locationId) { return sendError(res, 400, "Location ID must be a positive integer"); } const deleted = await storeModel.deleteLocation(getHouseholdId(req), locationId); if (!deleted) { return sendError(res, 404, "Location not found"); } res.json({ message: "Location removed successfully" }); } catch (error) { logError(req, "stores.deleteLocation", error); if (error.message.includes("last store location")) { return sendError(res, 400, error.message); } sendError(res, 500, "Failed to remove location"); } }; exports.setDefaultLocation = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); if (!locationId) { return sendError(res, 400, "Location ID must be a positive integer"); } await storeModel.setDefaultLocation(getHouseholdId(req), locationId); res.json({ message: "Default location updated successfully" }); } catch (error) { logError(req, "stores.setDefaultLocation", error); sendError(res, 500, "Failed to set default location"); } }; exports.getLocationZones = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); if (!locationId) { return sendError(res, 400, "Location ID must be a positive integer"); } const zones = await storeModel.listLocationZones(getHouseholdId(req), locationId); res.json({ zones }); } catch (error) { logError(req, "stores.getLocationZones", error); sendError(res, 500, "Failed to load zones"); } }; exports.createZone = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); const { name, sort_order, color, map_metadata } = req.body; if (!locationId) { return sendError(res, 400, "Location ID must be a positive integer"); } if (!name || name.trim().length === 0) { return sendError(res, 400, "Zone name is required"); } const zone = await storeModel.createZone(getHouseholdId(req), locationId, { name, sort_order: Number.isInteger(sort_order) ? sort_order : Number.parseInt(sort_order, 10), color, map_metadata, }); res.status(201).json({ message: "Zone created successfully", zone }); } catch (error) { logError(req, "stores.createZone", error); if (error.code === "23505") { return sendError(res, 400, "Zone already exists for this location"); } sendError(res, 500, "Failed to create zone"); } }; exports.updateZone = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); const zoneId = parsePositiveInteger(req.params.zoneId); if (!locationId || !zoneId) { return sendError(res, 400, "Location ID and zone ID must be positive integers"); } const sortOrder = req.body.sort_order; const zone = await storeModel.updateZone(getHouseholdId(req), locationId, zoneId, { name: req.body.name, sort_order: sortOrder === undefined ? undefined : Number.isInteger(sortOrder) ? sortOrder : Number.parseInt(sortOrder, 10), color: req.body.color, map_metadata: req.body.map_metadata, is_active: req.body.is_active, }); if (!zone) { return sendError(res, 404, "Zone not found"); } res.json({ message: "Zone updated successfully", zone }); } catch (error) { logError(req, "stores.updateZone", error); sendError(res, 500, "Failed to update zone"); } }; exports.deleteZone = async (req, res) => { try { const locationId = parsePositiveInteger(getLocationId(req)); const zoneId = parsePositiveInteger(req.params.zoneId); if (!locationId || !zoneId) { return sendError(res, 400, "Location ID and zone ID must be positive integers"); } const deleted = await storeModel.deleteZone(getHouseholdId(req), locationId, zoneId); if (!deleted) { return sendError(res, 404, "Zone not found"); } res.json({ message: "Zone removed successfully" }); } catch (error) { logError(req, "stores.deleteZone", error); sendError(res, 500, "Failed to remove zone"); } }; // Backward-compatible handlers for the old /stores/household routes. exports.addStoreToHousehold = async (req, res) => { try { const { storeId } = req.body; if (!storeId) { return sendError(res, 400, "Store ID is required"); } const legacyStore = await storeModel.getStoreById(storeId); if (!legacyStore) { return sendError(res, 404, "Store not found"); } const store = await storeModel.createHouseholdStore( getHouseholdId(req), legacyStore.name, "Default Location", null, req.user.id ); res.status(201).json({ message: "Store added to household successfully", store, }); } catch (error) { logError(req, "stores.addStoreToHousehold", error); sendError(res, 500, "Failed to add store to household"); } }; exports.removeStoreFromHousehold = exports.deleteLocation; exports.setDefaultStore = exports.setDefaultLocation;