Files
helix-engage-server/src/messaging/flow/flow-variable.service.ts
saridsa2 d819888351 feat: appointment QR code — generated and sent via WhatsApp after booking
- QrService: generates QR PNG from appointment data, cached in-memory
- GET /api/messaging/qr/:appointmentId serves the image (Gupshup needs URL)
- sendImage added to MessagingProvider + GupshupProvider
- send_appointment_qr tool registered in ToolRegistry
- Flow JSON updated: QR sent after booking confirmation
- Variable interpolation now supports dot notation ({{result.field}})
- SIDECAR_PUBLIC_URL env var for the QR image URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 20:23:06 +05:30

57 lines
2.3 KiB
TypeScript

import { Injectable } from '@nestjs/common';
@Injectable()
export class FlowVariableService {
// Replace {{variableName}} with values from session variables
interpolate(template: string, variables: Record<string, any>): string {
return template.replace(/\{\{([\w.]+)\}\}/g, (match, path) => {
// Support dot notation: {{bookingResult.appointmentId}}
const parts = path.split('.');
let value: any = variables;
for (const part of parts) {
value = value?.[part];
if (value === undefined) return match;
}
if (value === null) return match;
if (typeof value === 'object') return JSON.stringify(value);
return String(value);
});
}
// Interpolate all string values in an object
interpolateObject(obj: Record<string, string>, variables: Record<string, any>): Record<string, any> {
const result: Record<string, any> = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = this.interpolate(value, variables);
}
return result;
}
// Execute expressions for SetVariableBlock
evaluateExpression(expression: string, value: string, variables: Record<string, any>): any {
switch (expression) {
case 'extract_id': {
// Extract second segment: "doc:{uuid}:{name}" → uuid, "dept:{name}" → name
const parts = value.split(':');
return parts.length >= 2 ? parts[1] : value;
}
case 'extract_datetime': {
// Extract datetime from "slot:{doctorId}:{datetime}" → "2026-04-21T14:00:00"
const parts = value.split(':');
// Rejoin from index 2 onwards (datetime contains colons: 2026-04-21T14:00:00)
return parts.length >= 3 ? parts.slice(2).join(':') : value;
}
case 'date_tomorrow': {
const d = new Date(Date.now() + 86400000);
return d.toISOString().split('T')[0];
}
case 'date_day_after': {
const d = new Date(Date.now() + 2 * 86400000);
return d.toISOString().split('T')[0];
}
default:
return this.interpolate(value, variables);
}
}
}