/opt/mawid/apps/api/src/whatsapp
Edit: /opt/mawid/apps/api/src/whatsapp/owner-notifier.service.ts (1745B)
import { Inject, Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { WA_HTTP_CLIENT, type WaHttpClient } from './wa-http.client';
/**
* Sends WhatsApp texts to the clinic OWNER (not a patient) — used for slot
* refill notices (Phase 5) and the weekly summary (Phase 6). Owner number
* comes from clinic.settings.ownerWaPhone; if unset, notifications are skipped.
*
* Sends directly through the HTTP client (no Message/Conversation rows — those
* model patient conversations). Delivery is fire-and-forget; failures log.
*/
@Injectable()
export class OwnerNotifierService {
private readonly logger = new Logger(OwnerNotifierService.name);
constructor(
private readonly prisma: PrismaService,
@Inject(WA_HTTP_CLIENT) private readonly http: WaHttpClient,
) {}
async sendText(clinicId: string, text: string): Promise
{
const clinic = await this.prisma.clinic.findUnique({ where: { id: clinicId } });
if (!clinic) return;
const ownerPhone = ((clinic.settings ?? {}) as { ownerWaPhone?: string }).ownerWaPhone;
if (!ownerPhone || !clinic.waPhoneNumberId) {
this.logger.log(`owner notification skipped for clinic ${clinicId} (no ownerWaPhone)`);
return;
}
try {
await this.http.send(clinic.waPhoneNumberId, {
messaging_product: 'whatsapp',
to: ownerPhone.replace(/^\+/, ''),
type: 'text',
text: { body: text },
});
await this.prisma.auditLog.create({
data: { clinicId, actor: 'system', action: 'owner:notified', meta: { text } },
});
} catch (err) {
this.logger.warn(`owner notification failed for clinic ${clinicId}: ${String(err)}`);
}
}
}