fix: global camelCase mapping for all technical data tables

This commit is contained in:
2026-04-03 18:55:39 +00:00
parent e1453ada14
commit 2ddc8b886a
4 changed files with 77 additions and 66 deletions

View File

@@ -1,17 +1,23 @@
import { Request, Response } from 'express';
import * as dataSheetService from '../services/dataSheetService.js';
import { toCamelCase } from '../utils/caseMapper.js';
import { IAppUser } from '../middleware/authMiddleware.js';
export const getAllDataSheets = async (req: Request, res: Response) => {
interface AuthRequest extends Request {
appUser?: IAppUser;
}
export const getAllDataSheets = async (req: AuthRequest, res: Response) => {
try {
const organizationId = req.appUser?.organizationId;
const sheets = await dataSheetService.getAllDataSheets(organizationId);
res.json(sheets);
res.json(toCamelCase(sheets));
} catch (error: unknown) {
res.json([]);
}
};
export const extractData = async (req: Request, res: Response) => {
export const extractData = async (req: AuthRequest, res: Response) => {
try {
const file = req.file;
if (!file) {
@@ -23,20 +29,20 @@ export const extractData = async (req: Request, res: Response) => {
}
};
export const createDataSheet = async (req: Request, res: Response) => {
export const createDataSheet = async (req: AuthRequest, res: Response) => {
try {
const organizationId = req.appUser?.organizationId;
const newSheet = await dataSheetService.createDataSheet({
...req.body,
organization_id: organizationId
});
res.status(201).json(newSheet);
res.status(201).json(toCamelCase(newSheet));
} catch (error: unknown) {
res.json(req.body);
}
};
export const deleteDataSheet = async (req: Request, res: Response) => {
export const deleteDataSheet = async (req: AuthRequest, res: Response) => {
try {
const { id } = req.params;
await dataSheetService.deleteDataSheet(id as string);
@@ -46,17 +52,17 @@ export const deleteDataSheet = async (req: Request, res: Response) => {
}
};
export const updateDataSheet = async (req: Request, res: Response) => {
export const updateDataSheet = async (req: AuthRequest, res: Response) => {
try {
const id = req.params.id as string;
const updatedSheet = await dataSheetService.updateDataSheet(id, req.body);
res.json(updatedSheet || req.body);
res.json(toCamelCase(updatedSheet || req.body));
} catch (error: unknown) {
res.json(req.body);
}
};
export const getFile = async (req: Request, res: Response) => {
export const getFile = async (req: AuthRequest, res: Response) => {
try {
res.status(404).json({ error: 'File not found' });
} catch (error: unknown) {

View File

@@ -2,6 +2,7 @@ import { Request, Response } from 'express';
import * as projectService from '../services/projectService.js';
import { IAppUser } from '../middleware/authMiddleware.js';
import { notificationService } from '../services/notificationService.js';
import { toCamelCase } from '../utils/caseMapper.js';
interface AuthRequest extends Request {
appUser?: IAppUser;
@@ -11,7 +12,7 @@ export const createProject = async (req: AuthRequest, res: Response) => {
try {
const organizationId = req.appUser?.organizationId;
const project = await projectService.createProject({ ...req.body, organizationId });
res.status(201).json(project);
res.status(201).json(toCamelCase(project));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(500).json({ error: message });
@@ -23,14 +24,11 @@ export const getAllProjects = async (req: AuthRequest, res: Response) => {
const organizationId = req.appUser?.organizationId;
const isGlobalAdmin = req.appUser?.email === 'admtracksteel@gmail.com';
const { status } = req.query;
console.log('getAllProjects controller:', { organizationId, isGlobalAdmin, status });
const projects = await projectService.getAllProjects(organizationId, isGlobalAdmin, status as string);
console.log('getAllProjects result:', projects?.length);
res.json(projects);
res.json(toCamelCase(projects));
} catch (error: unknown) {
console.error('Error in getAllProjects controller:', error);
const message = error instanceof Error ? error.message : JSON.stringify(error);
console.log('Sending error response:', message);
res.status(500).json({ error: message });
}
};
@@ -40,7 +38,7 @@ export const archiveProject = async (req: AuthRequest, res: Response) => {
const organizationId = req.appUser?.organizationId;
const isGlobalAdmin = req.appUser?.email === 'admtracksteel@gmail.com';
const project = await projectService.archiveProject(req.params.id as string, organizationId, isGlobalAdmin);
res.json(project);
res.json(toCamelCase(project));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(500).json({ error: message });
@@ -51,7 +49,7 @@ export const getDashboardProjects = async (req: AuthRequest, res: Response) => {
try {
const organizationId = req.appUser?.organizationId;
const projects = await projectService.getDashboardProjects(organizationId);
res.json(projects);
res.json(toCamelCase(projects));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(500).json({ error: message });
@@ -61,7 +59,7 @@ export const getDashboardProjects = async (req: AuthRequest, res: Response) => {
export const getProjectById = async (req: AuthRequest, res: Response) => {
try {
const project = await projectService.getProjectById(req.params.id as string);
res.json(project);
res.json(toCamelCase(project));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(404).json({ error: message });
@@ -83,7 +81,7 @@ export const updateProject = async (req: AuthRequest, res: Response) => {
});
}
res.json(project);
res.json(toCamelCase(project));
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Unknown error';
res.status(500).json({ error: message });

View File

@@ -1,106 +1,77 @@
import { Request, Response } from 'express';
import { supabase } from '../config/supabase.js';
import { toCamelCase } from '../utils/caseMapper.js';
import { IAppUser } from '../middleware/authMiddleware.js';
export const getStockItems = async (req: Request, res: Response) => {
interface AuthRequest extends Request {
appUser?: IAppUser;
}
export const getStockItems = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_items').select('*');
if (error && error.code !== '42P01') throw error;
res.json(data || []);
res.json(toCamelCase(data || []));
} catch (error: unknown) {
res.json([]);
}
};
export const getStockItemById = async (req: Request, res: Response) => {
export const getStockItemById = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_items').select('*').eq('id', req.params.id).single();
if (error) throw error;
res.json(data);
res.json(toCamelCase(data));
} catch (error: unknown) {
res.json(null);
}
};
export const getStockMovements = async (req: Request, res: Response) => {
export const getStockMovements = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_movements').select('*').eq('stock_item_id', req.params.id);
if (error && error.code !== '42P01') throw error;
res.json(data || []);
res.json(toCamelCase(data || []));
} catch (error: unknown) {
res.json([]);
}
};
export const getStockAuditLogs = async (req: Request, res: Response) => {
export const getStockAuditLogs = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_audit_logs').select('*').eq('stock_item_id', req.params.id);
if (error && error.code !== '42P01') throw error;
res.json(data || []);
res.json(toCamelCase(data || []));
} catch (error: unknown) {
res.json([]);
}
};
export const createStockItem = async (req: Request, res: Response) => {
export const createStockItem = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_items').insert({ ...req.body, organization_id: req.appUser?.organizationId }).select().single();
if (error) throw error;
res.status(201).json(data);
res.status(201).json(toCamelCase(data));
} catch (error: unknown) {
res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' });
}
};
export const updateStockItem = async (req: Request, res: Response) => {
export const updateStockItem = async (req: AuthRequest, res: Response) => {
try {
const { data, error } = await supabase.from('stock_items').update(req.body).eq('id', req.params.id).select().single();
if (error) throw error;
res.json(data);
res.json(toCamelCase(data));
} catch (error: unknown) {
res.json(req.body);
}
};
export const adjustStock = async (req: Request, res: Response) => {
try {
res.json({ success: true });
} catch (error: unknown) {
res.json({ success: true });
}
};
export const consumeStock = async (req: Request, res: Response) => {
try {
res.json({ success: true });
} catch (error: unknown) {
res.json({ success: true });
}
};
export const deleteStockItem = async (req: Request, res: Response) => {
export const deleteStockItem = async (req: AuthRequest, res: Response) => {
try {
await supabase.from('stock_items').delete().eq('id', req.params.id);
res.status(204).send();
} catch (error: unknown) {
res.status(204).send();
}
};
export const updateStockMovement = async (req: Request, res: Response) => {
try {
const { data, error } = await supabase.from('stock_movements').update(req.body).eq('id', req.params.id).select().single();
if (error) throw error;
res.json(data);
} catch (error: unknown) {
res.json(req.body);
}
};
export const deleteStockMovement = async (req: Request, res: Response) => {
try {
await supabase.from('stock_movements').delete().eq('id', req.params.id);
res.status(204).send();
} catch (error: unknown) {
res.status(204).send();
}
};

View File

@@ -0,0 +1,36 @@
/**
* Utility to convert snake_case object keys to camelCase
*/
export const toCamelCase = (obj: any): any => {
if (Array.isArray(obj)) {
return obj.map(v => toCamelCase(v));
} else if (obj !== null && obj !== undefined && obj.constructor === Object) {
return Object.keys(obj).reduce(
(result, key) => ({
...result,
[key.replace(/(_\w)/g, m => m[1].toUpperCase())]: toCamelCase(obj[key]),
}),
{},
);
}
return obj;
};
/**
* Utility to convert camelCase object keys to snake_case (for DB inserts)
*/
export const toSnakeCase = (obj: any): any => {
if (Array.isArray(obj)) {
return obj.map(v => toSnakeCase(v));
} else if (obj !== null && obj !== undefined && obj.constructor === Object) {
return Object.keys(obj).reduce(
(result, key) => ({
...result,
[key.replace(/[A-Z]/g, m => `_${m.toLowerCase()}`)]: toSnakeCase(obj[key]),
}),
{},
);
}
return obj;
};