Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions apply_db_fixes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const { Pool } = require('pg');
const { config } = require('./src/config/env');

const connectionString = config.DATABASE_PUBLIC_URL || config.DATABASE_URL;

const pool = new Pool({
connectionString,
ssl: connectionString.includes('localhost') ? false : { rejectUnauthorized: false }
});

async function applyFixes() {
try {
const client = await pool.connect();
console.log('Connected to DB');

console.log('Adding "Others" to ConstructionStage enum...');
try {
await client.query(`ALTER TYPE daily_updates_constructionstage_enum ADD VALUE 'Others'`);
console.log('Added "Others" successfully');
} catch (e) {
if (e.code === '42710') { // duplicate_object
console.log('"Others" already exists in enum');
} else {
throw e;
}
}

console.log('Adding "work_completed" column to daily_updates...');
try {
// Since some columns in this table are CamelCase and some are snake_case,
// let's check what the schema expects.
// Schema has: @map("work_completed")
// So column should be "work_completed" (lowercase snake_case)
await client.query(`ALTER TABLE daily_updates ADD COLUMN work_completed VARCHAR(255)`);
console.log('Added "work_completed" successfully');
} catch (e) {
if (e.code === '42701') { // duplicate_column
console.log('"work_completed" already exists');
} else {
throw e;
}
}

client.release();
} catch (err) {
console.error('Error applying fixes:', err);
} finally {
await pool.end();
}
}

applyFixes();
40 changes: 40 additions & 0 deletions debug_db_columns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const { Pool } = require('pg');
const { config } = require('./src/config/env');

const connectionString = config.DATABASE_PUBLIC_URL || config.DATABASE_URL;

const pool = new Pool({
connectionString,
ssl: connectionString.includes('localhost') ? false : { rejectUnauthorized: false }
});

async function checkColumns() {
try {
const client = await pool.connect();
console.log('Connected to DB');

const tables = ['daily_updates', 'projects', 'supervisors', 'users'];

for (const table of tables) {
console.log(`\nTable: ${table}`);
const res = await client.query(`
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = $1
ORDER BY ordinal_position;
`, [table]);

res.rows.forEach(row => {
console.log(`- ${row.column_name}: ${row.data_type}`);
});
}

client.release();
} catch (err) {
console.error('Error:', err);
} finally {
await pool.end();
}
}

checkColumns();
47 changes: 47 additions & 0 deletions debug_db_enums.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { Pool } = require('pg');
const { config } = require('./src/config/env');

const connectionString = config.DATABASE_PUBLIC_URL || config.DATABASE_URL;

const pool = new Pool({
connectionString,
ssl: connectionString.includes('localhost') ? false : { rejectUnauthorized: false }
});

async function checkEnums() {
try {
const client = await pool.connect();
console.log('Connected to DB');

const enums = [
'daily_updates_constructionstage_enum',
'daily_updates_status_enum',
'users_role_enum',
'projects_initialstatus_enum',
'supervisors_status_enum'
];

for (const enumName of enums) {
console.log(`\nEnum: ${enumName}`);
const res = await client.query(`
SELECT enumlabel
FROM pg_enum
JOIN pg_type ON pg_enum.enumtypid = pg_type.oid
WHERE pg_type.typname = $1
ORDER BY enumsortorder;
`, [enumName]);

res.rows.forEach(row => {
console.log(`- ${row.enumlabel}`);
});
}

client.release();
} catch (err) {
console.error('Error:', err);
} finally {
await pool.end();
}
}

checkEnums();
37 changes: 37 additions & 0 deletions debug_db_exact_columns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const { Pool } = require('pg');
const { config } = require('./src/config/env');

const connectionString = config.DATABASE_PUBLIC_URL || config.DATABASE_URL;

const pool = new Pool({
connectionString,
ssl: connectionString.includes('localhost') ? false : { rejectUnauthorized: false }
});

async function checkExactColumns() {
try {
const client = await pool.connect();
const tables = ['daily_updates', 'projects', 'supervisors'];

for (const table of tables) {
console.log(`\nExact Columns for ${table}:`);
const res = await client.query(`
SELECT column_name
FROM information_schema.columns
WHERE table_name = $1
`, [table]);

res.rows.forEach(row => {
console.log(`'${row.column_name}'`);
});
}

client.release();
} catch (err) {
console.error('Error:', err);
} finally {
await pool.end();
}
}

checkExactColumns();
Binary file modified diff.sql
Binary file not shown.
24 changes: 24 additions & 0 deletions list_tables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const { Pool } = require('pg');
const { config } = require('./src/config/env');

const connectionString = config.DATABASE_PUBLIC_URL || config.DATABASE_URL;

const pool = new Pool({
connectionString,
ssl: connectionString.includes('localhost') ? false : { rejectUnauthorized: false }
});

async function listTables() {
try {
const client = await pool.connect();
const res = await client.query("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'");
res.rows.forEach(r => console.log(r.table_name));
client.release();
} catch (err) {
console.error(err);
} finally {
await pool.end();
}
}

listTables();
2 changes: 2 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum ConstructionStage {
Interior_Walls @map("Interior Walls")
Painting
Finishing
Others

@@map("daily_updates_constructionstage_enum")
}
Expand Down Expand Up @@ -300,6 +301,7 @@ model DailyUpdate {
dailyUpdateId String @id @default(uuid()) @db.Uuid
constructionStage ConstructionStage @default(Foundation)
description String? @db.Text
workCompleted String? @map("work_completed") @db.VarChar(255)
rawMaterials Json? @default("[]")
imageUrl String? @map("image_url") @db.VarChar(500)
imageName String? @map("image_name") @db.VarChar(255)
Expand Down
5 changes: 5 additions & 0 deletions src/modules/daily-updates/daily-updates.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const createDailyUpdate = async (req: MulterRequest, res: Response) => {
const dailyUpdateData = await DailyUpdatesServices.createDailyUpdate(
{
constructionStage: req.body.constructionStage,
workCompleted: req.body.workCompleted || null,
description: req.body.description || null,
projectId: req.body.projectId || null,
rawMaterials: rawMaterials,
Expand Down Expand Up @@ -478,6 +479,10 @@ export const updateDailyUpdate = async (req: MulterRequest, res: Response) => {
updateData.constructionStage = req.body.constructionStage;
}

if (req.body.workCompleted !== undefined) {
updateData.workCompleted = req.body.workCompleted || null;
}

if (req.body.description !== undefined) {
updateData.description = req.body.description || null;
}
Expand Down
18 changes: 15 additions & 3 deletions src/modules/daily-updates/daily-updates.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const createDailyUpdate = async (
data: {
constructionStage: string;
description?: string | null;
workCompleted?: string | null;
projectId?: string | null;
rawMaterials?: Array<{
materialName: string;
Expand All @@ -30,7 +31,7 @@ export const createDailyUpdate = async (
supervisorId?: string
) => {
// Validate construction stage
const validStages = ["Foundation", "Framing", "Plumbing & Electrical", "Interior Walls", "Painting", "Finishing"];
const validStages = ["Foundation", "Framing", "Plumbing & Electrical", "Interior Walls", "Painting", "Finishing", "Others"];
if (!validStages.includes(data.constructionStage)) {
throw new Error(`Invalid construction stage. Must be one of: ${validStages.join(", ")}`);
}
Expand Down Expand Up @@ -126,6 +127,7 @@ export const createDailyUpdate = async (
data: {
constructionStage: stageEnum,
description: data.description || null,
workCompleted: data.workCompleted || null,
projectId: validProjectId,
rawMaterials: data.rawMaterials ? JSON.stringify(data.rawMaterials) : "[]", // Store as JSON string if your DB expects it or rely on Prisma Json type
status: statusEnum,
Expand Down Expand Up @@ -504,6 +506,7 @@ export const updateDailyUpdate = async (
updateData: {
constructionStage?: string;
description?: string | null;
workCompleted?: string | null;
projectId?: string | null;
rawMaterials?: Array<{
materialName: string;
Expand All @@ -529,7 +532,7 @@ export const updateDailyUpdate = async (

// Validate and update construction stage if provided
if (updateData.constructionStage !== undefined) {
const validStages = ["Foundation", "Framing", "Plumbing & Electrical", "Interior Walls", "Painting", "Finishing"];
const validStages = ["Foundation", "Framing", "Plumbing & Electrical", "Interior Walls", "Painting", "Finishing", "Others"];
if (!validStages.includes(updateData.constructionStage)) {
throw new Error(`Invalid construction stage. Must be one of: ${validStages.join(", ")}`);
}
Expand All @@ -541,6 +544,11 @@ export const updateDailyUpdate = async (
dataToUpdate.constructionStage = stageEnum;
}

// Update workCompleted if provided
if (updateData.workCompleted !== undefined) {
dataToUpdate.workCompleted = updateData.workCompleted || null;
}

// Validate and update status if provided
if (updateData.status !== undefined) {
const validStatuses = ["pending", "approved", "rejected"];
Expand Down Expand Up @@ -1476,13 +1484,15 @@ export const markStageComplete = async (projectId: string, stage: string, superv
return ConstructionStage.Plumbing___Electrical;
if (clean === "Interior_Walls" || clean === "Interior_walls")
return ConstructionStage.Interior_Walls;
if (clean === "Others")
return ConstructionStage.Others;

// Literal match check
const validValues = Object.values(ConstructionStage);
if (validValues.includes(clean as ConstructionStage)) return clean as ConstructionStage;

// Fallback or fuzzy match could go here, but let's be strict with a better error
throw new Error(`Invalid construction stage: "${s}". Valid stages are: Foundation, Framing, Plumbing & Electrical, Interior Walls, Painting, Finishing`);
throw new Error(`Invalid construction stage: "${s}". Valid stages are: Foundation, Framing, Plumbing & Electrical, Interior Walls, Painting, Finishing, Others`);
};

const stageEnum = normalizeInputStage(stage);
Expand Down Expand Up @@ -1543,6 +1553,8 @@ export const approveStage = async (projectId: string, stage: string, userId: str
return ConstructionStage.Plumbing___Electrical;
if (clean === "Interior_Walls" || clean === "Interior_walls")
return ConstructionStage.Interior_Walls;
if (clean === "Others")
return ConstructionStage.Others;

const validValues = Object.values(ConstructionStage);
if (validValues.includes(clean as ConstructionStage)) return clean as ConstructionStage;
Expand Down
20 changes: 20 additions & 0 deletions test_run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

async function main() {
try {
await prisma.dailyUpdate.findMany();
console.log('daily ok');
} catch(e) {
console.error('Daily update error:', e.message);
}

try {
await prisma.project.findMany();
console.log('project ok');
} catch(e) {
console.error('Project error:', e.message);
}
}

main().finally(() => prisma.$disconnect());
22 changes: 22 additions & 0 deletions verify_fix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import prisma from './src/config/prisma.client';

async function verify() {
try {
const dailyUpdates = await prisma.dailyUpdate.findMany({ take: 1 });
console.log('Daily Update Fetch OK');
} catch (e: any) {
console.error('Daily Update Fetch Failed:', e.message);
}

try {
const projects = await prisma.project.findMany({
take: 1,
include: { dailyUpdates: true }
});
console.log('Project Fetch OK');
} catch (e: any) {
console.error('Project Fetch Failed:', e.message);
}
}

verify().finally(() => prisma.$disconnect());
Loading