Skip to content

Commit c69dbb0

Browse files
fix: email sender help@ciyex.org, provider name resolution, template alignment
- V192 migration: update sender_address to help@ciyex.org for all orgs - Provider name: enhanced resolution from multiple sources (provider ref, providerId, participant) - Email template: proper HTML table layout with inline styles for alignment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ec3b6d8 commit c69dbb0

3 files changed

Lines changed: 84 additions & 19 deletions

File tree

src/main/java/org/ciyex/ehr/fhir/GenericFhirResourceController.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,37 @@ private void fireAppointmentNotificationIfNeeded(String tabKey,
328328
// Resolve provider name if not present
329329
if (!notifData.containsKey("providerName") || String.valueOf(notifData.getOrDefault("providerName", "")).isBlank()) {
330330
try {
331-
Object providerRef = formData.get("provider");
331+
// Try multiple sources for provider ID
332332
String providerId = null;
333+
Object providerRef = formData.get("provider");
333334
if (providerRef instanceof String ref && ref.contains("/")) {
334335
providerId = ref.substring(ref.lastIndexOf("/") + 1);
336+
} else if (providerRef instanceof String ref && !ref.isBlank()) {
337+
providerId = ref; // direct ID string
338+
} else if (providerRef instanceof Number num) {
339+
providerId = String.valueOf(num.longValue());
340+
}
341+
// Fallback to providerId in form data or created data
342+
if (providerId == null || providerId.isBlank()) {
343+
Object pid = notifData.get("providerId");
344+
if (pid == null) pid = formData.get("providerId");
345+
if (pid == null) pid = formData.get("practitionerId");
346+
if (pid == null) pid = created.get("providerId");
347+
if (pid != null) providerId = String.valueOf(pid);
335348
}
336-
if (providerId == null) providerId = String.valueOf(notifData.getOrDefault("providerId", ""));
337-
if (providerId != null && !providerId.isBlank()) {
349+
// Also check participant references for Practitioner
350+
if ((providerId == null || providerId.isBlank()) && created.get("participant") instanceof List<?> participants) {
351+
for (Object p : participants) {
352+
if (p instanceof Map<?, ?> pm) {
353+
String actorRef = pm.get("actor") != null ? String.valueOf(pm.get("actor")) : "";
354+
if (actorRef.contains("Practitioner/")) {
355+
providerId = actorRef.substring(actorRef.lastIndexOf("/") + 1);
356+
break;
357+
}
358+
}
359+
}
360+
}
361+
if (providerId != null && !providerId.isBlank() && !"null".equals(providerId)) {
338362
Map<String, Object> provData = resourceService.get("providers", null, providerId);
339363
if (provData != null) {
340364
Object idBlock = provData.get("identification");
@@ -345,6 +369,11 @@ private void fireAppointmentNotificationIfNeeded(String tabKey,
345369
if (!provName.isBlank()) notifData.put("providerName", provName);
346370
} else if (provData.get("name") != null) {
347371
notifData.put("providerName", String.valueOf(provData.get("name")));
372+
} else if (provData.get("firstName") != null || provData.get("lastName") != null) {
373+
String fn = provData.get("firstName") != null ? String.valueOf(provData.get("firstName")) : "";
374+
String ln = provData.get("lastName") != null ? String.valueOf(provData.get("lastName")) : "";
375+
String provName = (fn + " " + ln).trim();
376+
if (!provName.isBlank()) notifData.put("providerName", provName);
348377
}
349378
}
350379
}

src/main/java/org/ciyex/ehr/notification/service/AppointmentNotificationService.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -205,28 +205,42 @@ private String buildDefaultBody(String eventType, Map<String, String> vars) {
205205
String date = vars.getOrDefault("appointmentDate", "");
206206
String time = vars.getOrDefault("appointmentTime", "");
207207
String practice = vars.getOrDefault("practiceName", "");
208+
String location = vars.getOrDefault("location_name", "");
208209

209-
return switch (eventType) {
210+
String innerHtml = switch (eventType) {
210211
case "appointment_confirmation" -> String.format(
211-
"<p>Dear %s,</p>" +
212-
"<p>Your appointment has been confirmed.</p>" +
213-
"<p><strong>Date:</strong> %s<br/>" +
214-
"<strong>Time:</strong> %s<br/>" +
215-
"<strong>Provider:</strong> %s</p>" +
216-
"<p>We look forward to seeing you!</p>" +
217-
"<p>Thank you,<br/>%s</p>",
212+
"<p style=\"margin:0 0 16px\">Dear %s,</p>" +
213+
"<p style=\"margin:0 0 16px\">Your appointment has been confirmed.</p>" +
214+
"<table style=\"border-collapse:collapse;margin:0 0 16px\">" +
215+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Date:</td><td style=\"padding:4px 0\">%s</td></tr>" +
216+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Time:</td><td style=\"padding:4px 0\">%s</td></tr>" +
217+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Provider:</td><td style=\"padding:4px 0\">%s</td></tr>" +
218+
(location.isBlank() ? "" : "<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Location:</td><td style=\"padding:4px 0\">" + location + "</td></tr>") +
219+
"</table>" +
220+
"<p style=\"margin:0 0 16px\">We look forward to seeing you!</p>" +
221+
"<p style=\"margin:0\">Thank you,<br/>%s</p>",
218222
name, date, time, provider, practice);
219223
case "appointment_reminder" -> String.format(
220-
"<p>Dear %s,</p>" +
221-
"<p>This is a reminder about your upcoming appointment.</p>" +
222-
"<p><strong>Date:</strong> %s<br/>" +
223-
"<strong>Time:</strong> %s<br/>" +
224-
"<strong>Provider:</strong> %s</p>" +
225-
"<p>We look forward to seeing you!</p>" +
226-
"<p>Thank you,<br/>%s</p>",
224+
"<p style=\"margin:0 0 16px\">Dear %s,</p>" +
225+
"<p style=\"margin:0 0 16px\">This is a reminder about your upcoming appointment.</p>" +
226+
"<table style=\"border-collapse:collapse;margin:0 0 16px\">" +
227+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Date:</td><td style=\"padding:4px 0\">%s</td></tr>" +
228+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Time:</td><td style=\"padding:4px 0\">%s</td></tr>" +
229+
"<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Provider:</td><td style=\"padding:4px 0\">%s</td></tr>" +
230+
(location.isBlank() ? "" : "<tr><td style=\"padding:4px 12px 4px 0;font-weight:bold\">Location:</td><td style=\"padding:4px 0\">" + location + "</td></tr>") +
231+
"</table>" +
232+
"<p style=\"margin:0 0 16px\">We look forward to seeing you!</p>" +
233+
"<p style=\"margin:0\">Thank you,<br/>%s</p>",
227234
name, date, time, provider, practice);
228-
default -> String.format("<p>Dear %s,</p><p>You have a new notification from %s.</p>", name, practice);
235+
default -> String.format(
236+
"<p style=\"margin:0 0 16px\">Dear %s,</p>" +
237+
"<p style=\"margin:0\">You have a new notification from %s.</p>",
238+
name, practice);
229239
};
240+
241+
// Wrap in a responsive HTML email wrapper for proper alignment
242+
return "<div style=\"font-family:'Segoe UI',Arial,sans-serif;max-width:600px;margin:0 auto;padding:24px;color:#333\">" +
243+
innerHtml + "</div>";
230244
}
231245

232246
private String extractString(Map<String, Object> data, String key) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- V192: Ensure sender_address is help@ciyex.org for all email configs
2+
-- Note: SMTP username (auth) stays unchanged — only the visible "From" address changes.
3+
-- If using Gmail, configure help@ciyex.org as a "Send as" alias in Gmail settings.
4+
5+
-- 1. Update sender_address for all email configs that still use old addresses
6+
UPDATE notification_config
7+
SET sender_address = 'help@ciyex.org',
8+
sender_name = COALESCE(
9+
NULLIF(sender_name, ''),
10+
'Ciyex EHR'
11+
),
12+
updated_at = now()
13+
WHERE channel_type = 'email'
14+
AND (sender_address IS NULL OR sender_address != 'help@ciyex.org');
15+
16+
-- 2. Update from_email in config JSON
17+
UPDATE notification_config
18+
SET config = jsonb_set(config, '{from_email}', '"help@ciyex.org"'),
19+
updated_at = now()
20+
WHERE channel_type = 'email'
21+
AND config IS NOT NULL
22+
AND (config->>'from_email' IS NULL OR config->>'from_email' != 'help@ciyex.org');

0 commit comments

Comments
 (0)