fix(consult): mark rectification opened only after the case opens (BUG-1306)

This commit is contained in:
jesse-ux
2026-10-12 15:36:36 +08:00
committed by Jesse_Chen
parent 798e15effe
commit 805932addd
14 changed files with 228 additions and 27 deletions
@@ -64,9 +64,11 @@ async function writeMessages(client: SupabaseClient, userId: string, sessionId:
}
/**
* After a free direct-entry reply is appended, hang the opened offer on that
* message. Idempotent: an offer already on the message (including one a later
* bind gave a case id) is left as it is. Does not touch consultation_requests.
* After a free direct-entry reply is appended, hang the offer on that message.
* The record is not opened yet (`offered` + `autoOpen`); bindOfferToCase sets
* opened after the case actually opens. Idempotent: an offer already on the
* message (including one a later bind gave a case id) is left as it is.
* Does not touch consultation_requests.
*/
export async function persistOpenedDirectOffer(input: {
client: SupabaseClient;
+11 -3
View File
@@ -28,6 +28,12 @@ export const rectificationOfferRecordSchema = z.object({
offeredAt: z.string().min(1).max(40),
caseId: z.string().uuid().optional(),
rectificationSessionId: z.string().uuid().optional(),
/**
* Present only when this turn should open the case without a click.
* Writers omit it unless it is true. Older stored offers omit it too.
* The card stays an ordinary offer until status is opened (BUG-1306 F3).
*/
autoOpen: z.boolean().optional(),
}).strict();
export type RectificationOfferRecord = z.infer<typeof rectificationOfferRecordSchema>;
@@ -149,8 +155,9 @@ export function bindOfferToCase(
for (let index = stored.length - 1; index >= 0; index -= 1) {
const offer = parseRectificationOfferRecord(stored[index]!.rectificationOffer);
if (!offer || offer.caseId) continue;
// A direct open records `opened` before the case id exists (BUG-1306).
// An offer already bound to another case is left alone.
// Offered cards, including a direct open that is still offered (autoOpen).
// An older direct-open row stored as opened before it had a case id still binds.
// Returned rows, and a card already bound to another case, are left alone.
if (offer.status !== "offered" && offer.status !== "opened") continue;
const next = [...stored];
next[index] = {
@@ -164,7 +171,8 @@ export function bindOfferToCase(
/**
* After `complete_consultation_free` appends the one-sentence reply, hang the
* opened offer on that message so a reload can still find the source. Returns
* offer on that message so a reload can still find the source. The record is
* not opened yet (still `offered`, with `autoOpen` on a direct open). Returns
* the next array, "present" when that message already has an offer (do not
* overwrite a later case id), or "missing" when the free reply is not there yet.
*/