feat: add backend migration and API for maintenance receipt linking (refs #151)
Add receipt_document_id FK on maintenance_records, update types/repo/service to support receipt linking on create and return document metadata on GET. Add OCR proxy endpoint POST /api/ocr/extract/maintenance-receipt with tier gating (maintenance.receiptScan) through full chain: routes -> controller -> service -> client. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
51
backend/src/features/ocr/external/ocr-client.ts
vendored
51
backend/src/features/ocr/external/ocr-client.ts
vendored
@@ -177,6 +177,57 @@ export class OcrClient {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract data from a maintenance receipt image using maintenance-specific OCR.
|
||||
*
|
||||
* @param fileBuffer - Image file buffer
|
||||
* @param contentType - MIME type of the file
|
||||
* @returns Receipt extraction result (receiptType: "maintenance")
|
||||
*/
|
||||
async extractMaintenanceReceipt(
|
||||
fileBuffer: Buffer,
|
||||
contentType: string
|
||||
): Promise<ReceiptExtractionResponse> {
|
||||
const formData = this.buildFormData(fileBuffer, contentType);
|
||||
const url = `${this.baseUrl}/extract/maintenance-receipt`;
|
||||
|
||||
logger.info('OCR maintenance receipt extract request', {
|
||||
operation: 'ocr.client.extractMaintenanceReceipt',
|
||||
url,
|
||||
contentType,
|
||||
fileSize: fileBuffer.length,
|
||||
});
|
||||
|
||||
const response = await this.fetchWithTimeout(url, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
logger.error('OCR maintenance receipt extract failed', {
|
||||
operation: 'ocr.client.extractMaintenanceReceipt.error',
|
||||
status: response.status,
|
||||
error: errorText,
|
||||
});
|
||||
const err: any = new Error(`OCR service error: ${response.status} - ${errorText}`);
|
||||
err.statusCode = response.status;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ReceiptExtractionResponse;
|
||||
|
||||
logger.info('OCR maintenance receipt extract completed', {
|
||||
operation: 'ocr.client.extractMaintenanceReceipt.success',
|
||||
success: result.success,
|
||||
receiptType: result.receiptType,
|
||||
fieldCount: Object.keys(result.extractedFields).length,
|
||||
processingTimeMs: result.processingTimeMs,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit an async OCR job for large files.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user