feat(projects): link quotes & contracts to a project (precise cockpit rollup)
- Migration 121 adds quotes.project_id + contracts.project_id (nullable FK, index) and backfills the unambiguous single-project-per-customer case. - projectService rolls quotes/contracts up by project_id, with a customer-based fallback on pre-121 DBs (hasColumnCached guarded). - quote/contract create+update accept an optional projectId; detail transforms surface it for editor prefill. - POST /projects/:id/quotes and /:id/contracts assign endpoints.
This commit is contained in:
@@ -803,6 +803,10 @@ async function createContract(payload, adminId) {
|
||||
row.event_time_start = payload.eventTimeStart || null;
|
||||
row.event_time_end = payload.eventTimeEnd || null;
|
||||
}
|
||||
// Migration 121 — optional link to a Project Overview project.
|
||||
if (payload.projectId !== undefined && await hasColumnCached('contracts', 'project_id')) {
|
||||
row.project_id = payload.projectId || null;
|
||||
}
|
||||
const inserted = await trx('contracts').insert(row).returning('id');
|
||||
const contractId = typeof inserted[0] === 'object' ? inserted[0].id : inserted[0];
|
||||
|
||||
@@ -890,6 +894,10 @@ async function updateContract(id, payload, adminId) {
|
||||
for (const [api, col] of Object.entries(map)) {
|
||||
if (api in payload) updates[col] = payload[api] || null;
|
||||
}
|
||||
// Migration 121 — optional Project Overview link.
|
||||
if ('projectId' in payload && await hasColumnCached('contracts', 'project_id')) {
|
||||
updates.project_id = payload.projectId || null;
|
||||
}
|
||||
await trx('contracts').where({ id }).update(updates);
|
||||
|
||||
// Replace inclusions only when the caller sent an explicit list.
|
||||
|
||||
Reference in New Issue
Block a user