Skip to content

Commit 562b616

Browse files
committed
Merge branch 'develop' into #3494-wp-status-in-cr-diff
2 parents a3c7f0f + 46764d6 commit 562b616

305 files changed

Lines changed: 13224 additions & 4880 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,17 @@
5858
"docker:start": "yarn database:setup:script && cd devContainerization && node start-containers.js",
5959
"docker:i": "cd devContainerization && docker compose -f docker-compose.dev.yml exec -T backend sh -c \"yarn install && cd src/backend && npx prisma generate\" && docker compose -f docker-compose.dev.yml exec -T frontend sh -c \"yarn install\"",
6060
"docker:test": "yarn test:setup && cd devContainerization && docker compose -f docker-compose.dev.yml exec backend bash -c \"yarn test:backend\" && docker compose -f docker-compose.dev.yml exec frontend sh -c \"yarn test:frontend\" && yarn test:teardown",
61-
"docker:rebuild": "docker compose -f devContainerization/docker-compose.dev.yml rm -f -s && yarn docker:start"
61+
"docker:rebuild": "docker compose -f devContainerization/docker-compose.dev.yml rm -f -s && yarn docker:start",
62+
"db:pull": "node scripts/db-pull.js"
6263
},
6364
"resolutions": {
6465
"@types/react": "17.0.1",
6566
"@types/react-dom": "17.0.1"
6667
},
6768
"dependencies": {
69+
"@microsoft/clarity": "^1.0.0",
6870
"@types/multer": "^1.4.12",
71+
"canvas-confetti": "^1.9.3",
6972
"mitt": "^3.0.1",
7073
"react-hook-form-persist": "^3.0.0",
7174
"recharts": "^2.15.3",
@@ -76,6 +79,7 @@
7679
"@babel/plugin-transform-object-assign": "^7.18.6",
7780
"@babel/preset-react": "^7.18.6",
7881
"@babel/preset-typescript": "^7.18.6",
82+
"@types/canvas-confetti": "^1.9.0",
7983
"@types/jest": "^29.5.14",
8084
"@types/node": "20.0.0",
8185
"@typescript-eslint/eslint-plugin": "8.20.0",

scripts/db-pull.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const { execSync } = require('child_process');
2+
const readline = require('readline');
3+
4+
function promptUser(question) {
5+
const rl = readline.createInterface({
6+
input: process.stdin,
7+
output: process.stdout
8+
});
9+
10+
return new Promise((resolve) => {
11+
rl.question(question, (answer) => {
12+
rl.close();
13+
resolve(answer.trim());
14+
});
15+
});
16+
}
17+
18+
async function main() {
19+
console.log('🚀 Database Migration Script\n');
20+
21+
try {
22+
const targetUrl = "postgresql://postgres:docker@localhost:5432/nerpm"
23+
24+
console.log(`📍 Target database: ${targetUrl.replace(/\/\/[^@]*@/, '//***:***@')}`);
25+
26+
const sourceUrl = new URL(await promptUser('\nSource database URL (READ-ONLY - will not be modified): '));
27+
sourceUrl.search = '';
28+
29+
console.log(`\n📋 Migration Summary:`);
30+
console.log(`• Source (READ-ONLY): ${sourceUrl.href.replace(/\/\/[^@]*@/, '//***:***@')}`);
31+
console.log(`• Target (WILL BE OVERWRITTEN): ${targetUrl.replace(/\/\/[^@]*@/, '//***:***@')}`);
32+
33+
const confirm = await promptUser('\n⚠️ This will COMPLETELY OVERWRITE the target database. Continue? (y/n): ');
34+
35+
if (confirm.toLowerCase() !== 'y') {
36+
console.log('❌ Cancelled');
37+
return;
38+
}
39+
40+
console.log('\n🗑️ Clearing target database...');
41+
42+
// First, clear the target database completely
43+
const clearCommand = `psql "${targetUrl}" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"`;
44+
console.log(targetUrl)
45+
46+
try {
47+
execSync(clearCommand, { stdio: 'inherit' });
48+
console.log('✅ Target database cleared');
49+
} catch (error) {
50+
console.log('⚠️ Warning: Could not clear database, continuing anyway...');
51+
}
52+
53+
console.log('\n📦 Dumping and restoring database...');
54+
55+
const dumpCommand = `pg_dump "${sourceUrl}" --no-acl --no-owner --clean --if-exists | psql "${targetUrl}"`;
56+
57+
execSync(dumpCommand, { stdio: 'inherit' });
58+
59+
console.log('✅ Migration complete!');
60+
61+
} catch (error) {
62+
console.error('❌ Error:', error.message);
63+
process.exit(1);
64+
}
65+
}
66+
67+
main();

src/backend/custom.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Organization, User as PrismaUser } from '@prisma/client';
1+
import { Organization } from '@prisma/client';
2+
import { User as SharedUser } from 'shared';
23

34
declare global {
45
namespace Express {
56
export interface Request {
6-
currentUser: PrismaUser;
7+
currentUser: SharedUser;
78
organization: Organization;
89
}
910
}

src/backend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"prisma:manual": "ts-node ./src/prisma/manual.ts"
1010
},
1111
"dependencies": {
12-
"@prisma/client": "6.2.1",
12+
"@prisma/client": "^6.2.1",
1313
"@slack/events-api": "^3.0.1",
1414
"@slack/web-api": "^7.8.0",
1515
"@types/concat-stream": "^2.0.0",
@@ -32,6 +32,7 @@
3232
"jsonwebtoken": "^8.5.1",
3333
"multer": "^1.4.5-lts.1",
3434
"nodemailer": "^6.9.1",
35+
"prisma": "^6.2.1",
3536
"shared": "1.0.0"
3637
},
3738
"devDependencies": {
@@ -40,7 +41,6 @@
4041
"@types/node": "^20.0.0",
4142
"@types/supertest": "^2.0.12",
4243
"nodemon": "^2.0.16",
43-
"prisma": "6.2.1",
4444
"supertest": "^6.2.4",
4545
"ts-node": "^8.10.1",
4646
"typescript": "^5.7.3",

src/backend/src/controllers/finance.controllers.ts

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class FinanceController {
1212
activeYears,
1313
sponsorTierId,
1414
taxExempt,
15-
vendorContact,
15+
sponsorContact,
1616
sponsorTasks,
1717
discountCode
1818
} = req.body;
@@ -26,7 +26,7 @@ export default class FinanceController {
2626
activeYears,
2727
sponsorTierId,
2828
taxExempt,
29-
vendorContact,
29+
sponsorContact,
3030
sponsorTasks,
3131
req.organization,
3232
discountCode
@@ -157,15 +157,17 @@ export default class FinanceController {
157157
static async getReimbursementRequestTeamData(req: Request, res: Response, next: NextFunction) {
158158
try {
159159
const { teamId } = req.params;
160-
const { startDate, endDate } = req.query;
160+
const { startDate, endDate, carNumber } = req.query;
161161
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
162162
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
163+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
163164

164165
const rrData = await FinanceServices.getReimbursementRequestTeamData(
165166
req.organization,
166167
teamId,
167168
parsedStartDate,
168-
parsedEndDate
169+
parsedEndDate,
170+
parsedCarNumber
169171
);
170172
res.status(200).json(rrData);
171173
} catch (error: unknown) {
@@ -176,15 +178,17 @@ export default class FinanceController {
176178
static async getReimbursementRequestTeamTypeData(req: Request, res: Response, next: NextFunction) {
177179
try {
178180
const { teamTypeId } = req.params;
179-
const { startDate, endDate } = req.query;
181+
const { startDate, endDate, carNumber } = req.query;
180182
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
181183
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
184+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
182185

183186
const rrData = await FinanceServices.getReimbursementRequestTeamTypeData(
184187
req.organization,
185188
teamTypeId,
186189
parsedStartDate,
187-
parsedEndDate
190+
parsedEndDate,
191+
parsedCarNumber
188192
);
189193
res.status(200).json(rrData);
190194
} catch (error: unknown) {
@@ -195,15 +199,17 @@ export default class FinanceController {
195199
static async getSpendingBarTeamData(req: Request, res: Response, next: NextFunction) {
196200
try {
197201
const { teamId } = req.params;
198-
const { startDate, endDate } = req.query;
202+
const { startDate, endDate, carNumber } = req.query;
199203
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
200204
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
205+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
201206

202207
const spendingBarData = await FinanceServices.getSpendingBarTeamData(
203208
req.organization,
204209
teamId,
205210
parsedStartDate,
206-
parsedEndDate
211+
parsedEndDate,
212+
parsedCarNumber
207213
);
208214
res.status(200).json(spendingBarData);
209215
} catch (error: unknown) {
@@ -214,15 +220,17 @@ export default class FinanceController {
214220
static async getSpendingBarTeamTypeData(req: Request, res: Response, next: NextFunction) {
215221
try {
216222
const { teamTypeId } = req.params;
217-
const { startDate, endDate } = req.query;
223+
const { startDate, endDate, carNumber } = req.query;
218224
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
219225
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
226+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
220227

221228
const spendingBarData = await FinanceServices.getSpendingBarTeamTypeData(
222229
req.organization,
223230
teamTypeId,
224231
parsedStartDate,
225-
parsedEndDate
232+
parsedEndDate,
233+
parsedCarNumber
226234
);
227235
res.status(200).json(spendingBarData);
228236
} catch (error: unknown) {
@@ -232,11 +240,17 @@ export default class FinanceController {
232240

233241
static async getAllReimbursementRequestData(req: Request, res: Response, next: NextFunction) {
234242
try {
235-
const { startDate, endDate } = req.query;
243+
const { startDate, endDate, carNumber } = req.query;
236244
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
237245
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
246+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
238247

239-
const rrData = await FinanceServices.getAllReimbursementRequestData(req.organization, parsedStartDate, parsedEndDate);
248+
const rrData = await FinanceServices.getAllReimbursementRequestData(
249+
req.organization,
250+
parsedStartDate,
251+
parsedEndDate,
252+
parsedCarNumber
253+
);
240254
res.status(200).json(rrData);
241255
} catch (error: unknown) {
242256
next(error);
@@ -246,15 +260,17 @@ export default class FinanceController {
246260
static async getReimbursementRequestCategoryData(req: Request, res: Response, next: NextFunction) {
247261
try {
248262
const { otherReasonId } = req.params;
249-
const { startDate, endDate } = req.query;
263+
const { startDate, endDate, carNumber } = req.query;
250264
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
251265
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
266+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
252267

253268
const rrData = await FinanceServices.getReimbursementRequestCategoryData(
254269
otherReasonId,
255270
req.organization,
256271
parsedStartDate,
257-
parsedEndDate
272+
parsedEndDate,
273+
parsedCarNumber
258274
);
259275
res.status(200).json(rrData);
260276
} catch (error: unknown) {
@@ -264,11 +280,17 @@ export default class FinanceController {
264280

265281
static async getAllSpendingBarData(req: Request, res: Response, next: NextFunction) {
266282
try {
267-
const { startDate, endDate } = req.query;
283+
const { startDate, endDate, carNumber } = req.query;
268284
const parsedStartDate = typeof startDate === 'string' ? new Date(startDate) : undefined;
269285
const parsedEndDate = typeof endDate === 'string' ? new Date(endDate) : undefined;
286+
const parsedCarNumber = typeof carNumber === 'string' ? Number(carNumber) : undefined;
270287

271-
const spendingBarData = await FinanceServices.getAllSpendingBarData(req.organization, parsedStartDate, parsedEndDate);
288+
const spendingBarData = await FinanceServices.getAllSpendingBarData(
289+
req.organization,
290+
parsedStartDate,
291+
parsedEndDate,
292+
parsedCarNumber
293+
);
272294
res.status(200).json(spendingBarData);
273295
} catch (error: unknown) {
274296
next(error);
@@ -303,7 +325,7 @@ export default class FinanceController {
303325
joinDate,
304326
activeYears,
305327
sponsorTierId,
306-
vendorContact,
328+
sponsorContact,
307329
taxExempt,
308330
sponsorTasks,
309331
discountCode
@@ -319,7 +341,7 @@ export default class FinanceController {
319341
joinDate,
320342
activeYears,
321343
sponsorTierId,
322-
vendorContact,
344+
sponsorContact,
323345
taxExempt,
324346
sponsorTasks,
325347
discountCode

src/backend/src/controllers/organizations.controllers.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,27 @@ export default class OrganizationsController {
217217
next(error);
218218
}
219219
}
220+
221+
static async getFinanceDelegates(req: Request, res: Response, next: NextFunction) {
222+
try {
223+
const financeDelegates = await OrganizationsService.getFinanceDelegates(req.organization.organizationId);
224+
res.status(200).json(financeDelegates);
225+
} catch (error: unknown) {
226+
next(error);
227+
}
228+
}
229+
230+
static async setFinanceDelegates(req: Request, res: Response, next: NextFunction) {
231+
try {
232+
const { userIds } = req.body;
233+
const updatedDelegates = await OrganizationsService.setFinanceDelegates(
234+
req.currentUser,
235+
req.organization.organizationId,
236+
userIds
237+
);
238+
res.status(200).json(updatedDelegates);
239+
} catch (error: unknown) {
240+
next(error);
241+
}
242+
}
220243
}

0 commit comments

Comments
 (0)