feat: import unfinished birth-time cases
This commit is contained in:
@@ -167,6 +167,26 @@ function declaredBirthInputFromProfile(value: unknown): DeclaredBirthInput {
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
export function declaredBirthInputForLegacyCase(
|
||||
currentProfileValue: unknown,
|
||||
legacyCaseValue: unknown,
|
||||
): DeclaredBirthInput {
|
||||
const currentProfile = profileRecord(currentProfileValue);
|
||||
const legacyCase = profileRecord(legacyCaseValue);
|
||||
if (!currentProfile || !legacyCase) {
|
||||
throw new ConversationalRectificationError("profile_incomplete");
|
||||
}
|
||||
return declaredBirthInputFromProfile({
|
||||
...currentProfile,
|
||||
birth_date: legacyCase.reported_date,
|
||||
reported_birth_time: legacyCase.reported_time,
|
||||
birth_time_source: legacyCase.source,
|
||||
birth_time_period: legacyCase.reported_period,
|
||||
uncertainty_before_minutes: legacyCase.uncertainty_before_minutes,
|
||||
uncertainty_after_minutes: legacyCase.uncertainty_after_minutes,
|
||||
});
|
||||
}
|
||||
|
||||
export type ProductionConversationalRectificationProfileDependencies = Readonly<{
|
||||
loadProfile(userId: string): Promise<unknown>;
|
||||
loadRectificationCase(userId: string, caseId: string): Promise<unknown>;
|
||||
@@ -178,22 +198,42 @@ export async function loadProductionConversationalRectificationProfile(
|
||||
): Promise<Readonly<{
|
||||
declaredBirthInput: DeclaredBirthInput;
|
||||
revisionOfCaseId: string | null;
|
||||
legacyCaseId: string | null;
|
||||
}>> {
|
||||
const profileValue = await dependencies.loadProfile(userId);
|
||||
const profile = profileRecord(profileValue);
|
||||
if (!profile) throw new ConversationalRectificationError("profile_incomplete");
|
||||
const declaredBirthInput = declaredBirthInputFromProfile(profile);
|
||||
const priorCaseId = text(profile.rectification_case_id);
|
||||
if (!priorCaseId) return { declaredBirthInput, revisionOfCaseId: null };
|
||||
if (!priorCaseId) return {
|
||||
declaredBirthInput,
|
||||
revisionOfCaseId: null,
|
||||
legacyCaseId: null,
|
||||
};
|
||||
|
||||
const prior = profileRecord(await dependencies.loadRectificationCase(userId, priorCaseId));
|
||||
const terminalV3Revision = prior
|
||||
&& text(prior.id) === priorCaseId
|
||||
&& text(prior.journey_protocol) === "conversational-evidence-v3"
|
||||
&& (text(prior.status) === "completed" || text(prior.status) === "abandoned");
|
||||
const protocol = prior ? text(prior.journey_protocol) : null;
|
||||
const status = prior ? text(prior.status) : null;
|
||||
const unfinishedLegacyStatuses = new Set([
|
||||
"reported",
|
||||
"assessing",
|
||||
"rectifying",
|
||||
"candidate",
|
||||
"confirming",
|
||||
]);
|
||||
const unfinishedLegacy = prior
|
||||
&& text(prior.id) === priorCaseId
|
||||
&& (protocol === "legacy-guided-v1" || protocol === "dynamic-choice-v2")
|
||||
&& status !== null
|
||||
&& unfinishedLegacyStatuses.has(status);
|
||||
return {
|
||||
declaredBirthInput,
|
||||
revisionOfCaseId: terminalV3Revision ? priorCaseId : null,
|
||||
legacyCaseId: unfinishedLegacy ? priorCaseId : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,7 +468,7 @@ export async function buildProductionConversationalRectificationPacket(
|
||||
events,
|
||||
})
|
||||
: null;
|
||||
const selectedRange = eventScore?.winningSegment
|
||||
const selectedRange = !input.preserveCandidateRange && eventScore?.winningSegment
|
||||
? { startTime: eventScore.winningSegment.startTime, endTime: eventScore.winningSegment.endTime }
|
||||
: baseRange;
|
||||
const questionnaires: RectificationQuestionnaire[] = [];
|
||||
@@ -474,7 +514,9 @@ export async function buildProductionConversationalRectificationPacket(
|
||||
packet: buildRectificationTechnicalPacket({
|
||||
scan: questionnaire,
|
||||
candidateDifferences,
|
||||
eventScore,
|
||||
eventScore: input.preserveCandidateRange && eventScore
|
||||
? { ...eventScore, confidence: "low", canApply: false, winningSegment: null }
|
||||
: eventScore,
|
||||
consultation: {
|
||||
source: "server_consultation_workflow",
|
||||
calculationVersion,
|
||||
@@ -562,6 +604,55 @@ async function createProductionService(
|
||||
},
|
||||
}, userId);
|
||||
},
|
||||
async loadLegacyCase(userId, legacyCaseId) {
|
||||
const { createJourneyLoadClient, loadStoredRectificationCase } = await import(
|
||||
"../../../lib/birth-time-journey-case-loader.ts"
|
||||
);
|
||||
const { data: identity, error } = await admin
|
||||
.from("birth_time_rectification_cases")
|
||||
.select("id,user_id,journey_protocol,status,reported_date,reported_time,reported_period,source,uncertainty_before_minutes,uncertainty_after_minutes")
|
||||
.eq("id", legacyCaseId)
|
||||
.eq("user_id", userId)
|
||||
.maybeSingle();
|
||||
if (error || !identity
|
||||
|| (identity.journey_protocol !== "legacy-guided-v1"
|
||||
&& identity.journey_protocol !== "dynamic-choice-v2")) return null;
|
||||
const { data: currentProfile, error: profileError } = await profileClient
|
||||
.from("profiles")
|
||||
.select("birth_date,reported_birth_time,active_birth_time,birth_time_source,birth_time_period,birth_time_clue,uncertainty_before_minutes,uncertainty_after_minutes,country_code,province_code,city_code,district_code,latitude,longitude,timezone_offset,rectification_case_id")
|
||||
.eq("id", userId)
|
||||
.maybeSingle();
|
||||
if (profileError || !currentProfile) {
|
||||
throw new ConversationalRectificationError("store_unavailable");
|
||||
}
|
||||
const declaredBirthInput = declaredBirthInputForLegacyCase(currentProfile, identity);
|
||||
const loaded = await loadStoredRectificationCase(
|
||||
createJourneyLoadClient(admin),
|
||||
userId,
|
||||
legacyCaseId,
|
||||
);
|
||||
if (!loaded) return null;
|
||||
const winning = loaded.candidateResult?.winningSegment;
|
||||
const snapshotRange = loaded.snapshot.reportedRange;
|
||||
const currentRange = loaded.journeyProtocol === "dynamic-choice-v2"
|
||||
? loaded.dynamicTurnState.progress.currentRange
|
||||
: winning
|
||||
? { startTime: winning.startTime, endTime: winning.endTime }
|
||||
: snapshotRange.startTime && snapshotRange.endTime
|
||||
? { startTime: snapshotRange.startTime, endTime: snapshotRange.endTime }
|
||||
: null;
|
||||
if (!currentRange) throw new ConversationalRectificationError("store_unavailable");
|
||||
return {
|
||||
caseId: loaded.id,
|
||||
userId: loaded.userId,
|
||||
journeyProtocol: loaded.journeyProtocol,
|
||||
status: identity.status,
|
||||
turnVersion: loaded.turnVersion ?? 0,
|
||||
declaredBirthInput,
|
||||
currentRange,
|
||||
lifeEvents: loaded.lifeEvents ?? [],
|
||||
};
|
||||
},
|
||||
buildTechnicalPacket: (input) => buildProductionConversationalRectificationPacket(engine, input),
|
||||
narrativeGenerator,
|
||||
asOfDate: () => new Date().toISOString().slice(0, 10),
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
import { z } from "zod";
|
||||
import type { LifeEvent } from "../birth-time-evidence.ts";
|
||||
import { ConversationalRectificationError } from "./errors.ts";
|
||||
import {
|
||||
declaredBirthInputSchema,
|
||||
lifeEventEvidenceSchema,
|
||||
type DeclaredBirthInput,
|
||||
type LifeEventEvidence,
|
||||
} from "./persistence-contracts.ts";
|
||||
|
||||
const uuidSchema = z.string().uuid();
|
||||
const dateSchema = z.string().date();
|
||||
const timeRangeSchema = z.object({
|
||||
startTime: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),
|
||||
endTime: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),
|
||||
}).strict().readonly();
|
||||
|
||||
const unfinishedLegacyStatuses = new Set([
|
||||
"assessing",
|
||||
"rectifying",
|
||||
"candidate",
|
||||
"confirming",
|
||||
"starting",
|
||||
"active",
|
||||
"paused",
|
||||
]);
|
||||
|
||||
export type LegacyConversationalImportSource = Readonly<{
|
||||
caseId: string;
|
||||
userId: string;
|
||||
journeyProtocol: "legacy-guided-v1" | "dynamic-choice-v2";
|
||||
status: string;
|
||||
turnVersion: number;
|
||||
declaredBirthInput: DeclaredBirthInput;
|
||||
currentRange: Readonly<{ startTime: string; endTime: string }>;
|
||||
lifeEvents: readonly LifeEvent[];
|
||||
// Loaders may carry these old private fields. The projection deliberately
|
||||
// never reads them: choices are not dated life-event facts.
|
||||
currentChoicePrompt?: string | null;
|
||||
choiceAnswers?: readonly unknown[];
|
||||
}>;
|
||||
|
||||
export type ProjectedLegacyConversationalImport = Readonly<{
|
||||
legacyCaseId: string;
|
||||
expectedVersion: number;
|
||||
declaredBirthInput: DeclaredBirthInput;
|
||||
currentRange: Readonly<{ startTime: string; endTime: string }>;
|
||||
evidence: readonly LifeEventEvidence[];
|
||||
}>;
|
||||
|
||||
const domainLabels = {
|
||||
career: "事业",
|
||||
education: "学业",
|
||||
relocation: "迁居",
|
||||
relationship: "关系",
|
||||
family: "家庭",
|
||||
other: "其他",
|
||||
} as const;
|
||||
|
||||
function importedDomain(domain: LifeEvent["domain"]): LifeEventEvidence["domain"] {
|
||||
return domain === "finance" || domain === "health_pressure" ? "other" : domain;
|
||||
}
|
||||
|
||||
function eventIsWithinHistoricalWindow(
|
||||
event: LifeEvent,
|
||||
birthDate: string,
|
||||
asOfDate: string,
|
||||
): boolean {
|
||||
const lowerBound = event.precision === "year"
|
||||
? birthDate.slice(0, 4)
|
||||
: event.precision === "month" ? birthDate.slice(0, 7) : birthDate;
|
||||
const upperBound = event.precision === "year"
|
||||
? asOfDate.slice(0, 4)
|
||||
: event.precision === "month" ? asOfDate.slice(0, 7) : asOfDate;
|
||||
return event.date >= lowerBound && event.date <= upperBound;
|
||||
}
|
||||
|
||||
function importedEvidence(event: LifeEvent): LifeEventEvidence {
|
||||
const domain = importedDomain(event.domain);
|
||||
const label = domainLabels[domain];
|
||||
const summary = `旧校时记录中的${label}事件`;
|
||||
return lifeEventEvidenceSchema.parse({
|
||||
id: event.id,
|
||||
rawText: `${summary}(${event.date})`,
|
||||
domain,
|
||||
eventSummary: summary,
|
||||
dateValue: event.date,
|
||||
datePrecision: event.precision,
|
||||
extractionStatus: "clear",
|
||||
scoreable: true,
|
||||
correctsEvidenceIds: [],
|
||||
});
|
||||
}
|
||||
|
||||
export function projectLegacyCaseForConversationalImport(input: Readonly<{
|
||||
source: LegacyConversationalImportSource;
|
||||
asOfDate: string;
|
||||
expectedUserId?: string;
|
||||
}>): ProjectedLegacyConversationalImport {
|
||||
const source = input.source;
|
||||
const sourceCaseId = uuidSchema.safeParse(source.caseId);
|
||||
const sourceUserId = uuidSchema.safeParse(source.userId);
|
||||
const expectedUserId = input.expectedUserId === undefined
|
||||
? null
|
||||
: uuidSchema.safeParse(input.expectedUserId);
|
||||
if (!sourceCaseId.success || !sourceUserId.success
|
||||
|| (expectedUserId !== null && (!expectedUserId.success
|
||||
|| expectedUserId.data !== sourceUserId.data))) {
|
||||
throw new ConversationalRectificationError("case_not_found");
|
||||
}
|
||||
if (source.journeyProtocol !== "legacy-guided-v1"
|
||||
&& source.journeyProtocol !== "dynamic-choice-v2") {
|
||||
throw new ConversationalRectificationError("case_not_found");
|
||||
}
|
||||
if (!unfinishedLegacyStatuses.has(source.status)) {
|
||||
throw new ConversationalRectificationError("invalid_transition");
|
||||
}
|
||||
if (!Number.isSafeInteger(source.turnVersion) || source.turnVersion < 0) {
|
||||
throw new ConversationalRectificationError("case_not_found");
|
||||
}
|
||||
const range = timeRangeSchema.safeParse(source.currentRange);
|
||||
const declared = declaredBirthInputSchema.safeParse(source.declaredBirthInput);
|
||||
const asOfDate = dateSchema.safeParse(input.asOfDate);
|
||||
if (!range.success || !declared.success || !asOfDate.success) {
|
||||
throw new ConversationalRectificationError("profile_incomplete");
|
||||
}
|
||||
|
||||
const evidence: LifeEventEvidence[] = [];
|
||||
const importedIds = new Set<string>();
|
||||
for (const event of source.lifeEvents) {
|
||||
if (importedIds.has(event.id)
|
||||
|| !eventIsWithinHistoricalWindow(event, declared.data.birthDate, asOfDate.data)) continue;
|
||||
try {
|
||||
const projected = importedEvidence(event);
|
||||
importedIds.add(projected.id);
|
||||
evidence.push(projected);
|
||||
} catch {
|
||||
// Legacy rows predate today's stricter schema. Invalid historical
|
||||
// fragments remain in the read-only old row and never become v3 facts.
|
||||
}
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
legacyCaseId: sourceCaseId.data,
|
||||
expectedVersion: source.turnVersion,
|
||||
declaredBirthInput: declared.data,
|
||||
currentRange: range.data,
|
||||
evidence: Object.freeze(evidence.slice(-20)),
|
||||
});
|
||||
}
|
||||
@@ -27,6 +27,10 @@ import {
|
||||
type RectificationTechnicalPacket,
|
||||
} from "./technical-packet.ts";
|
||||
import type { ConversationalRectificationBilling } from "./billing.ts";
|
||||
import {
|
||||
projectLegacyCaseForConversationalImport,
|
||||
type LegacyConversationalImportSource,
|
||||
} from "./legacy-import.ts";
|
||||
import type {
|
||||
ConversationalRectificationStore,
|
||||
LifeEventEvidenceInput,
|
||||
@@ -48,6 +52,7 @@ export type ComputedConversationalRectificationPacket = Readonly<{
|
||||
export type ConversationalRectificationProfile = Readonly<{
|
||||
declaredBirthInput: unknown;
|
||||
revisionOfCaseId: string | null;
|
||||
legacyCaseId?: string | null;
|
||||
}>;
|
||||
|
||||
export type ConversationalRectificationPacketBuildInput = Readonly<{
|
||||
@@ -57,14 +62,20 @@ export type ConversationalRectificationPacketBuildInput = Readonly<{
|
||||
declaredBirthInput: DeclaredBirthInput;
|
||||
privateCandidate: PrivateCandidateInput | null;
|
||||
evidence: ReadonlyArray<LifeEventEvidenceInput>;
|
||||
preserveCandidateRange?: true;
|
||||
}>;
|
||||
|
||||
export type ConversationalRectificationServicePorts = Readonly<{
|
||||
store: Pick<ConversationalRectificationStore,
|
||||
"createCaseWithFirstTurn" | "loadCase" | "loadActionReceipt" | "saveTurn" | "pause" | "abandon" | "confirm">;
|
||||
"createCaseWithFirstTurn" | "loadCase" | "loadActionReceipt" | "saveTurn" | "pause" | "abandon" | "confirm">
|
||||
& Partial<Pick<ConversationalRectificationStore, "importLegacy">>;
|
||||
billing: Pick<ConversationalRectificationBilling, "reserve" | "complete" | "release">;
|
||||
rectificationPriceCredits: number;
|
||||
loadDeclaredProfile(userId: string): Promise<ConversationalRectificationProfile>;
|
||||
loadLegacyCase?(
|
||||
userId: string,
|
||||
legacyCaseId: string,
|
||||
): Promise<LegacyConversationalImportSource | null>;
|
||||
buildTechnicalPacket(
|
||||
input: ConversationalRectificationPacketBuildInput,
|
||||
): Promise<ComputedConversationalRectificationPacket>;
|
||||
@@ -73,6 +84,12 @@ export type ConversationalRectificationServicePorts = Readonly<{
|
||||
}>;
|
||||
|
||||
export type ConversationalRectificationService = Readonly<{
|
||||
importLegacyCase(
|
||||
userId: string,
|
||||
legacyCaseId: string,
|
||||
actionId: string,
|
||||
pendingConsultationQuestion?: string | null,
|
||||
): Promise<ConversationalRectificationTurn>;
|
||||
start(userId: string, command: CommandOf<"start">): Promise<ConversationalRectificationTurn>;
|
||||
resume(userId: string, command: CommandOf<"resume">): Promise<ConversationalRectificationTurn>;
|
||||
answer(userId: string, command: CommandOf<"answer">): Promise<ConversationalRectificationTurn>;
|
||||
@@ -316,6 +333,21 @@ function boundedNarrative(previous: string, suffix: string): string {
|
||||
return `${previous.slice(0, room)}\n\n${suffix}`.slice(0, 12_000);
|
||||
}
|
||||
|
||||
function midpointOfRange(range: Readonly<{ startTime: string; endTime: string }>): string {
|
||||
const minute = (value: string) => {
|
||||
const [hour = 0, part = 0] = value.split(":").map(Number);
|
||||
return hour * 60 + part;
|
||||
};
|
||||
const clock = (value: number) => {
|
||||
const normalized = ((value % 1_440) + 1_440) % 1_440;
|
||||
return `${String(Math.floor(normalized / 60)).padStart(2, "0")}:${String(normalized % 60).padStart(2, "0")}`;
|
||||
};
|
||||
const start = minute(range.startTime);
|
||||
let end = minute(range.endTime);
|
||||
if (end < start) end += 1_440;
|
||||
return clock(Math.round((start + end) / 2));
|
||||
}
|
||||
|
||||
function domainsForClarification(
|
||||
current: ConversationalRectificationTurn,
|
||||
hint: RectificationEvidenceDomain | undefined,
|
||||
@@ -454,6 +486,114 @@ export function createConversationalRectificationService(
|
||||
}
|
||||
}
|
||||
|
||||
async function importLegacyCase(
|
||||
userId: string,
|
||||
legacyCaseId: string,
|
||||
actionId: string,
|
||||
pendingConsultationQuestion: string | null = null,
|
||||
): Promise<ConversationalRectificationTurn> {
|
||||
const importer = ports.store.importLegacy;
|
||||
const loadLegacy = ports.loadLegacyCase;
|
||||
if (!importer || !loadLegacy) {
|
||||
throw new ConversationalRectificationError("service_unavailable");
|
||||
}
|
||||
|
||||
try {
|
||||
const existingByAction = await ports.store.loadCase({ userId, caseId: actionId });
|
||||
if (existingByAction) {
|
||||
if (existingByAction.importedFromCaseId !== legacyCaseId
|
||||
|| existingByAction.billingState !== "migration_waived"
|
||||
|| existingByAction.pendingConsultationQuestion !== pendingConsultationQuestion) {
|
||||
throw new ConversationalRectificationError("action_conflict");
|
||||
}
|
||||
return publicTurn(existingByAction);
|
||||
}
|
||||
const current = await ports.store.loadCase({ userId });
|
||||
if (current?.importedFromCaseId === legacyCaseId
|
||||
&& current.billingState === "migration_waived"
|
||||
&& current.pendingConsultationQuestion === pendingConsultationQuestion) {
|
||||
return publicTurn(current);
|
||||
}
|
||||
if (current?.importedFromCaseId === legacyCaseId
|
||||
&& current.billingState === "migration_waived") {
|
||||
throw new ConversationalRectificationError("action_conflict");
|
||||
}
|
||||
|
||||
const legacy = await loadLegacy(userId, legacyCaseId);
|
||||
if (!legacy) throw new ConversationalRectificationError("case_not_found");
|
||||
const projected = projectLegacyCaseForConversationalImport({
|
||||
source: legacy,
|
||||
asOfDate: ports.asOfDate(),
|
||||
expectedUserId: userId,
|
||||
});
|
||||
const rangeSeed = privateCandidateSchema.parse({
|
||||
resultId: null,
|
||||
representativeTime: midpointOfRange(projected.currentRange),
|
||||
rangeStart: projected.currentRange.startTime,
|
||||
rangeEnd: projected.currentRange.endTime,
|
||||
calculationVersion: "legacy-import-range-v1",
|
||||
workingState: { phase: "collecting_evidence", iteration: 0, notes: [] },
|
||||
});
|
||||
const computed = await ports.buildTechnicalPacket({
|
||||
userId,
|
||||
caseId: actionId,
|
||||
asOfDate: ports.asOfDate(),
|
||||
declaredBirthInput: projected.declaredBirthInput,
|
||||
privateCandidate: rangeSeed,
|
||||
evidence: projected.evidence,
|
||||
preserveCandidateRange: true,
|
||||
});
|
||||
const narrative = await generateRectificationNarrative({
|
||||
phase: "first",
|
||||
packet: computed.packet,
|
||||
generator: ports.narrativeGenerator,
|
||||
});
|
||||
const privateCandidate = privateCandidateFromPacket({
|
||||
packet: computed.packet,
|
||||
resultId: computed.resultId,
|
||||
iteration: 0,
|
||||
});
|
||||
const firstTurn = turnFromNarrative({
|
||||
caseId: actionId,
|
||||
turnVersion: 0,
|
||||
pendingConsultationQuestion,
|
||||
packet: computed.packet,
|
||||
narrative,
|
||||
evidence: projected.evidence,
|
||||
});
|
||||
const imported = await importer.call(ports.store, {
|
||||
userId,
|
||||
caseId: actionId,
|
||||
expectedVersion: projected.expectedVersion,
|
||||
actionId,
|
||||
legacyCaseId,
|
||||
price: ports.rectificationPriceCredits,
|
||||
pendingConsultationQuestion,
|
||||
declaredBirthInput: projected.declaredBirthInput,
|
||||
evidence: projected.evidence,
|
||||
firstTurn,
|
||||
validationReceipt: narrative.validationReceipt,
|
||||
privateCandidate,
|
||||
});
|
||||
return publicTurn(imported);
|
||||
} catch (error) {
|
||||
if (error instanceof ConversationalRectificationError
|
||||
&& error.code === "action_conflict") {
|
||||
try {
|
||||
const winner = await ports.store.loadCase({ userId });
|
||||
if (winner?.importedFromCaseId === legacyCaseId
|
||||
&& winner.billingState === "migration_waived"
|
||||
&& winner.pendingConsultationQuestion === pendingConsultationQuestion) {
|
||||
return publicTurn(winner);
|
||||
}
|
||||
} catch {
|
||||
// Preserve the original stable conflict below.
|
||||
}
|
||||
}
|
||||
throw safeFailure(error);
|
||||
}
|
||||
}
|
||||
|
||||
function extractedEvidence(command: CommandOf<"answer">): readonly LifeEventEvidence[] {
|
||||
let extracted: readonly LifeEventEvidence[];
|
||||
try {
|
||||
@@ -480,6 +620,7 @@ export function createConversationalRectificationService(
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
importLegacyCase,
|
||||
async start(userId, rawCommand) {
|
||||
const command = parseCommand("start", rawCommand);
|
||||
let profile: ConversationalRectificationProfile;
|
||||
@@ -491,6 +632,15 @@ export function createConversationalRectificationService(
|
||||
const declared = declaredBirthInputSchema.safeParse(profile.declaredBirthInput);
|
||||
if (!declared.success) throw new ConversationalRectificationError("profile_incomplete");
|
||||
|
||||
if (profile.legacyCaseId) {
|
||||
return importLegacyCase(
|
||||
userId,
|
||||
profile.legacyCaseId,
|
||||
command.actionId,
|
||||
command.pendingConsultationQuestion ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
let price: number;
|
||||
try {
|
||||
price = ports.rectificationPriceCredits;
|
||||
|
||||
@@ -127,6 +127,8 @@ export type ImportLegacyConversationalRectificationInput = MutationIdentity & Re
|
||||
legacyCaseId: string;
|
||||
price: number;
|
||||
pendingConsultationQuestion: string | null;
|
||||
declaredBirthInput: DeepReadonly<DeclaredBirthInput>;
|
||||
evidence: ReadonlyArray<LifeEventEvidenceInput>;
|
||||
firstTurn: ConversationalRectificationTurnInput;
|
||||
validationReceipt: ValidationReceiptInput;
|
||||
privateCandidate: PrivateCandidateInput;
|
||||
@@ -414,6 +416,8 @@ export class ConversationalRectificationStore {
|
||||
p_legacy_case_id: input.legacyCaseId,
|
||||
p_price: input.price,
|
||||
p_pending_consultation_question: input.pendingConsultationQuestion,
|
||||
p_declared_birth_input: requireDeclaredBirthInput(input.declaredBirthInput),
|
||||
p_evidence: requireEvidence(input.evidence),
|
||||
p_first_turn: requirePublicTurn(input.firstTurn),
|
||||
p_validation_receipt: requireValidationReceipt(input.validationReceipt),
|
||||
p_private_candidate: requirePrivateCandidate(input.privateCandidate),
|
||||
|
||||
Reference in New Issue
Block a user