feat: expand documents to include manuals
This commit is contained in:
@@ -27,6 +27,7 @@ export class DocumentsRepository {
|
||||
issuedDate: row.issued_date,
|
||||
expirationDate: row.expiration_date,
|
||||
emailNotifications: row.email_notifications,
|
||||
scanForMaintenance: row.scan_for_maintenance,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
deletedAt: row.deleted_at
|
||||
@@ -48,11 +49,12 @@ export class DocumentsRepository {
|
||||
issuedDate?: string | null;
|
||||
expirationDate?: string | null;
|
||||
emailNotifications?: boolean;
|
||||
scanForMaintenance?: boolean;
|
||||
}): Promise<DocumentRecord> {
|
||||
const res = await this.db.query(
|
||||
`INSERT INTO documents (
|
||||
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date, email_notifications
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
|
||||
id, user_id, vehicle_id, document_type, title, notes, details, issued_date, expiration_date, email_notifications, scan_for_maintenance
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
|
||||
RETURNING *`,
|
||||
[
|
||||
doc.id,
|
||||
@@ -65,6 +67,7 @@ export class DocumentsRepository {
|
||||
doc.issuedDate ?? null,
|
||||
doc.expirationDate ?? null,
|
||||
doc.emailNotifications ?? false,
|
||||
doc.scanForMaintenance ?? false,
|
||||
]
|
||||
);
|
||||
return this.mapDocumentRecord(res.rows[0]);
|
||||
@@ -91,7 +94,7 @@ export class DocumentsRepository {
|
||||
await this.db.query(`UPDATE documents SET deleted_at = NOW() WHERE id = $1 AND user_id = $2`, [id, userId]);
|
||||
}
|
||||
|
||||
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issuedDate'|'expirationDate'|'emailNotifications'>>): Promise<DocumentRecord | null> {
|
||||
async updateMetadata(id: string, userId: string, patch: Partial<Pick<DocumentRecord, 'title'|'notes'|'details'|'issuedDate'|'expirationDate'|'emailNotifications'|'scanForMaintenance'>>): Promise<DocumentRecord | null> {
|
||||
const fields: string[] = [];
|
||||
const params: any[] = [];
|
||||
let i = 1;
|
||||
@@ -101,6 +104,7 @@ export class DocumentsRepository {
|
||||
if (patch.issuedDate !== undefined) { fields.push(`issued_date = $${i++}`); params.push(patch.issuedDate); }
|
||||
if (patch.expirationDate !== undefined) { fields.push(`expiration_date = $${i++}`); params.push(patch.expirationDate); }
|
||||
if (patch.emailNotifications !== undefined) { fields.push(`email_notifications = $${i++}`); params.push(patch.emailNotifications); }
|
||||
if (patch.scanForMaintenance !== undefined) { fields.push(`scan_for_maintenance = $${i++}`); params.push(patch.scanForMaintenance); }
|
||||
if (!fields.length) return this.findById(id, userId);
|
||||
params.push(id, userId);
|
||||
const sql = `UPDATE documents SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} AND deleted_at IS NULL RETURNING *`;
|
||||
|
||||
@@ -20,6 +20,7 @@ export class DocumentsService {
|
||||
issuedDate: body.issuedDate ?? null,
|
||||
expirationDate: body.expirationDate ?? null,
|
||||
emailNotifications: body.emailNotifications ?? false,
|
||||
scanForMaintenance: body.scanForMaintenance ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const DocumentTypeSchema = z.enum(['insurance', 'registration']);
|
||||
export const DocumentTypeSchema = z.enum(['insurance', 'registration', 'manual']);
|
||||
export type DocumentType = z.infer<typeof DocumentTypeSchema>;
|
||||
|
||||
// API response type (camelCase for frontend)
|
||||
@@ -21,6 +21,7 @@ export interface DocumentRecord {
|
||||
issuedDate?: string | null;
|
||||
expirationDate?: string | null;
|
||||
emailNotifications?: boolean;
|
||||
scanForMaintenance?: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string | null;
|
||||
@@ -36,6 +37,7 @@ export const CreateDocumentBodySchema = z.object({
|
||||
issuedDate: z.string().optional(),
|
||||
expirationDate: z.string().optional(),
|
||||
emailNotifications: z.boolean().optional(),
|
||||
scanForMaintenance: z.boolean().optional(),
|
||||
});
|
||||
export type CreateDocumentBody = z.infer<typeof CreateDocumentBodySchema>;
|
||||
|
||||
@@ -46,6 +48,7 @@ export const UpdateDocumentBodySchema = z.object({
|
||||
issuedDate: z.string().nullable().optional(),
|
||||
expirationDate: z.string().nullable().optional(),
|
||||
emailNotifications: z.boolean().optional(),
|
||||
scanForMaintenance: z.boolean().optional(),
|
||||
});
|
||||
export type UpdateDocumentBody = z.infer<typeof UpdateDocumentBodySchema>;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Migration: Add 'manual' document type and scan_for_maintenance column
|
||||
-- Purpose: Support vehicle/equipment manuals with future maintenance schedule scanning
|
||||
|
||||
-- Step 1: Extend document_type CHECK constraint to include 'manual'
|
||||
-- Note: Must drop and recreate since PostgreSQL doesn't support ALTER CONSTRAINT
|
||||
ALTER TABLE documents DROP CONSTRAINT IF EXISTS documents_document_type_check;
|
||||
ALTER TABLE documents ADD CONSTRAINT documents_document_type_check
|
||||
CHECK (document_type IN ('insurance', 'registration', 'manual'));
|
||||
|
||||
-- Step 2: Add scan_for_maintenance boolean column
|
||||
-- Only applicable to 'manual' type, defaults to false
|
||||
ALTER TABLE documents ADD COLUMN IF NOT EXISTS scan_for_maintenance BOOLEAN DEFAULT false;
|
||||
|
||||
-- Step 3: Create partial index for future maintenance scanning queries
|
||||
CREATE INDEX IF NOT EXISTS idx_documents_scan_for_maintenance
|
||||
ON documents(scan_for_maintenance)
|
||||
WHERE scan_for_maintenance = true AND deleted_at IS NULL AND document_type = 'manual';
|
||||
Reference in New Issue
Block a user