fix(crm): tell the admin whether a customer's invitation actually went out
Closes #1261. "Invite customer" is two calls: createDirect, then sendInvite. The mode wiring is right -- CustomerManagementPage passes mode='invite' and InlineCustomerCreate does call sendInvite -- so the reported symptom is not a missed branch. It is that nothing downstream distinguishes the outcomes. Three things could not be told apart afterwards: - The success toast claimed "portal invitation sent". sendInvite only queues an email_queue row; whether it was delivered is decided minutes later by the queue processor. The toast now says queued, and says what sends it. - When sendInvite failed, the warning read "Invitation email failed -- retry from the customer detail page", which sounds like the mail bounced. What actually remains is a PASSIVE customer with no invitation at all, so it says that instead. A 409 is now separated out: that means an invitation for the address is already open and the RE-invite was refused, so the customer is invited and telling them to retry sends them the wrong way. - The customers table rendered a customer whose invitation never went out identically to one the admin created as passive on purpose -- both showed only "Passive - admin only". Passive customers with an open invitation now show "Invitation pending", matched case-insensitively because customer_invitations lowercases the address while customer_accounts keeps what the admin typed. The invitations list was already being fetched for the tab; this only cross-references it. Active customers are left alone: they have portal access, so a stale invitation row for their address says nothing about them. 7 tests; the 5 that assert the new behaviour all fail before the change, and the 2 negative controls pass on both sides.
This commit is contained in:
@@ -16,6 +16,11 @@
|
||||
* stays saved (passive) and a warning toast asks the admin to retry
|
||||
* from the customer detail page.
|
||||
*
|
||||
* #1261 — the toasts here say what actually happened rather than what was
|
||||
* intended. Two calls means three outcomes, and the middle one used to be
|
||||
* indistinguishable from success: the invitation email is only QUEUED, so
|
||||
* "invitation sent" was a claim this code cannot make.
|
||||
*
|
||||
* Field set mirrors the customer detail page so admins see the same
|
||||
* shape regardless of where they're editing.
|
||||
*/
|
||||
@@ -182,10 +187,17 @@ export const InlineCustomerCreate: React.FC<Props> = ({ onCreated, onCancel, mod
|
||||
try {
|
||||
await customerAdminService.sendInvite(customer.id);
|
||||
toast.success(t('customers.create.savedActiveToast',
|
||||
'Customer created and portal invitation sent.'));
|
||||
'Customer created and portal invitation queued. It is sent by the email queue — check System health if it does not arrive.'));
|
||||
} catch (err: any) {
|
||||
toast.warn(t('customers.create.inviteFailedToast',
|
||||
'Customer saved (passive). Invitation email failed — retry from the customer detail page.'));
|
||||
// A 409 means an invitation for this address is already open, which
|
||||
// is a different thing from the email failing: the customer is
|
||||
// invited, and re-inviting is what was refused.
|
||||
const alreadyInvited = err?.response?.status === 409;
|
||||
toast.warn(alreadyInvited
|
||||
? t('customers.create.inviteAlreadyPendingToast',
|
||||
'Customer saved. An invitation for this address is already open — cancel it on the Invitations tab before sending a new one.')
|
||||
: t('customers.create.inviteFailedToast',
|
||||
'Customer saved as PASSIVE — no invitation went out. Retry "Send portal invitation" from the customer detail page.'));
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('sendInvite failed', err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user