Fix donation-assignment admin email reading as a real payment

The internal admin notice for applying a donation to a registration
reused buildPaymentAdminNotice as-is, so it read "Payment recorded" /
"Registration payment" — indistinguishable from an actual incoming
payment even though no new money changed hands. Adds a dedicated
buildDonationAssignmentAdminNotice wrapper (mirroring the one already
added for unassignment) so the subject, heading, and Type field all
say "Donation applied" instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 00:59:24 +02:00
co-authored by Claude Sonnet 5
parent 252f80fadb
commit 34f9826829
2 changed files with 33 additions and 3 deletions
+29 -3
View File
@@ -697,6 +697,29 @@ function buildDonationUnassignedFromRegistrant(payment) {
return { subject, text, html: emailWrapper(body, { preheader }) };
}
// Internal admin notice for a donation-assignment — same table layout as
// buildPaymentAdminNotice (which reads payment.user as "Payer" — for a leg that's the donor,
// since legs copy userId from the original donation, not the registrant), relabeled so it
// doesn't read as a fresh incoming payment: no new money changed hands here, an
// already-recorded donation was just reallocated to a registration.
function buildDonationAssignmentAdminNotice(payment) {
const notice = buildPaymentAdminNotice(payment);
const eventTitle = payment.registration?.event?.title || 'Event';
const payerName = payment.user?.name || '—';
const subject = `Donation applied: ${fmtAmount(payment.amount)}${payerName} (${eventTitle})`;
return {
...notice,
subject,
html: notice.html
.replace('Payment recorded', 'Donation applied')
.replace('Internal notification', 'Internal notification — donation applied to a registration')
.replace('>Registration payment<', '>Donation applied<'),
text: notice.text
.replace('Payment recorded', 'Donation applied')
.replace('Type: Registration payment', 'Type: Donation applied'),
};
}
// Internal admin notice for a donation-unassignment — same table layout as
// buildPaymentAdminNotice (which reads payment.user as "Payer" — for a leg that's the donor,
// since legs copy userId from the original donation, not the registrant), with copy adjusted
@@ -711,8 +734,11 @@ function buildDonationUnassignmentAdminNotice(payment) {
subject,
html: notice.html
.replace('Payment recorded', 'Donation unassigned')
.replace('Internal notification', 'Internal notification — donation removed from registration'),
text: notice.text.replace('Payment recorded', 'Donation unassigned'),
.replace('Internal notification', 'Internal notification — donation removed from registration')
.replace('>Registration payment<', '>Donation unassigned<'),
text: notice.text
.replace('Payment recorded', 'Donation unassigned')
.replace('Type: Registration payment', 'Type: Donation unassigned'),
};
}
@@ -1057,7 +1083,7 @@ async function sendDonationAssignmentEmails(paymentId) {
} else {
sends.push(waTextAny(user, buildWADonationAppliedToRegistrant(payment)));
}
const adminMsg = buildPaymentAdminNotice(payment);
const adminMsg = buildDonationAssignmentAdminNotice(payment);
if (adminMsg.to && adminMsg.to.length) {
sends.push(sendMail({ to: adminMsg.to.join(','), subject: adminMsg.subject, html: adminMsg.html, text: adminMsg.text }));
}