Fix v3 mirror flow

This commit is contained in:
SepehrYahyaee
2026-06-22 17:30:58 +03:30
parent 83e82ea68e
commit db569db9d1
15 changed files with 1004 additions and 248 deletions

View File

@@ -0,0 +1,46 @@
import {
countUnifiedFileStatuses,
resolveUnifiedFileStatus,
} from "./unified-file-status";
import { CaseStatus } from "src/Types&Enums/blame-request-management/caseStatus.enum";
import { ClaimCaseStatus } from "src/Types&Enums/claim-request-management/claim-case-status.enum";
describe("resolveUnifiedFileStatus", () => {
it("prefers claim completed over blame in progress", () => {
expect(
resolveUnifiedFileStatus({
blameStatus: CaseStatus.WAITING_FOR_EXPERT,
claimStatus: ClaimCaseStatus.COMPLETED,
}),
).toBe("COMPLETED");
});
it("maps blame expert queue", () => {
expect(
resolveUnifiedFileStatus({
blameStatus: CaseStatus.WAITING_FOR_EXPERT,
}),
).toBe("WAITING_FOR_BLAME_EXPERT");
});
it("maps claim damage expert queue", () => {
expect(
resolveUnifiedFileStatus({
blameStatus: CaseStatus.COMPLETED,
claimStatus: ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT,
}),
).toBe("WAITING_FOR_DAMAGE_EXPERT");
});
it("counts merged entries", () => {
const counts = countUnifiedFileStatuses([
{ blameStatus: CaseStatus.OPEN },
{
blameStatus: CaseStatus.COMPLETED,
claimStatus: ClaimCaseStatus.CAPTURING_PART_DAMAGES,
},
]);
expect(counts.all).toBe(2);
expect(counts.IN_PROGRESS).toBe(2);
});
});

View File

@@ -0,0 +1,221 @@
import { CaseStatus } from "src/Types&Enums/blame-request-management/caseStatus.enum";
import { ClaimCaseStatus } from "src/Types&Enums/claim-request-management/claim-case-status.enum";
/** Calculated lifecycle status for a publicId (blame + claim combined). */
export const UNIFIED_FILE_STATUS_KEYS = [
"IN_PROGRESS",
"WAITING_FOR_SECOND_PARTY",
"WAITING_FOR_BLAME_EXPERT",
"WAITING_FOR_SIGNATURES",
"WAITING_FOR_DOCUMENT_RESEND",
"WAITING_FOR_DAMAGE_EXPERT",
"EXPERT_REVIEWING",
"EXPERT_VALIDATING_FACTORS",
"INSURER_REVIEW",
"COMPLETED",
"CANCELLED",
"REJECTED",
"STOPPED",
] as const;
export type UnifiedFileStatusKey = (typeof UNIFIED_FILE_STATUS_KEYS)[number];
export type UnifiedFileStatusInput = {
blameStatus?: string | null;
claimStatus?: string | null;
};
const CLAIM_USER_PHASE = new Set<string>([
ClaimCaseStatus.CREATED,
ClaimCaseStatus.SELECTING_OUTER_PARTS,
ClaimCaseStatus.SELECTING_OTHER_PARTS,
ClaimCaseStatus.UPLOADING_REQUIRED_DOCUMENTS,
ClaimCaseStatus.CAPTURING_PART_DAMAGES,
]);
const INSURER_REVIEW_CLAIM_STATUSES = new Set<string>([
ClaimCaseStatus.WAITING_FOR_INSURER_APPROVAL,
ClaimCaseStatus.INSURER_REVIEW_AWAITING_OWNER_SIGN,
ClaimCaseStatus.INSURER_REVIEW_MIXED_FACTORS_PENDING,
ClaimCaseStatus.OWNER_REPAIR_FACTOR_UPLOAD_PENDING,
]);
export type UnifiedFileStatusDefinition = {
key: UnifiedFileStatusKey;
labelEn: string;
labelFa: string;
description: string;
};
export const UNIFIED_FILE_STATUS_CATALOG: UnifiedFileStatusDefinition[] = [
{
key: "IN_PROGRESS",
labelEn: "In progress (user)",
labelFa: "در حال تکمیل توسط کاربر",
description:
"Parties are still filling blame steps and/or the damaged party is completing the claim (parts, documents, capture).",
},
{
key: "WAITING_FOR_SECOND_PARTY",
labelEn: "Waiting for second party",
labelFa: "در انتظار طرف دوم",
description: "Blame file is waiting for the second party to join or complete steps.",
},
{
key: "WAITING_FOR_BLAME_EXPERT",
labelEn: "Waiting for blame expert",
labelFa: "در انتظار کارشناس مقصر",
description: "Blame case is in the expert disagreement / guilt-decision queue.",
},
{
key: "WAITING_FOR_SIGNATURES",
labelEn: "Waiting for signatures",
labelFa: "در انتظار امضا",
description: "Blame file is waiting for party signatures on the expert decision.",
},
{
key: "WAITING_FOR_DOCUMENT_RESEND",
labelEn: "Waiting for document resend",
labelFa: "در انتظار ارسال مجدد مدارک",
description:
"Blame or claim is waiting for the user to resubmit documents or photos requested by an expert.",
},
{
key: "WAITING_FOR_DAMAGE_EXPERT",
labelEn: "Waiting for damage expert",
labelFa: "در انتظار کارشناس خسارت",
description: "Claim is in the damage-expert review queue (not yet locked).",
},
{
key: "EXPERT_REVIEWING",
labelEn: "Damage expert reviewing",
labelFa: "در حال بررسی کارشناس خسارت",
description: "A damage expert has locked the claim and is assessing damage.",
},
{
key: "EXPERT_VALIDATING_FACTORS",
labelEn: "Validating repair factors",
labelFa: "اعتبارسنجی فاکتور تعمیر",
description: "Damage expert is validating uploaded repair-factor documents.",
},
{
key: "INSURER_REVIEW",
labelEn: "Insurer / owner review",
labelFa: "بررسی بیمه‌گر / مالک",
description:
"Expert pricing is done; owner signature, factor upload, or insurer approval is pending.",
},
{
key: "COMPLETED",
labelEn: "Completed",
labelFa: "تکمیل شده",
description: "Claim (and blame when present) is finished successfully.",
},
{
key: "CANCELLED",
labelEn: "Cancelled",
labelFa: "لغو شده",
description: "File was cancelled or auto-closed.",
},
{
key: "REJECTED",
labelEn: "Rejected",
labelFa: "رد شده",
description: "Claim was rejected.",
},
{
key: "STOPPED",
labelEn: "Stopped",
labelFa: "متوقف شده",
description: "Blame file was stopped.",
},
];
export function initialUnifiedFileStatusCounts(): Record<
UnifiedFileStatusKey | "all",
number
> {
const out: Record<string, number> = { all: 0 };
for (const key of UNIFIED_FILE_STATUS_KEYS) {
out[key] = 0;
}
return out as Record<UnifiedFileStatusKey | "all", number>;
}
/**
* Single calculatable status for a shared publicId from raw blame + claim statuses.
* Claim pipeline takes precedence once a claim exists and has left the user-only phase.
*/
export function resolveUnifiedFileStatus(
input: UnifiedFileStatusInput,
): UnifiedFileStatusKey {
const blame = input.blameStatus?.trim() || undefined;
const claim = input.claimStatus?.trim() || undefined;
if (claim === ClaimCaseStatus.COMPLETED) return "COMPLETED";
if (claim === ClaimCaseStatus.REJECTED) return "REJECTED";
if (
claim === ClaimCaseStatus.CANCELLED ||
blame === CaseStatus.CANCELLED ||
blame === CaseStatus.AUTO_CLOSED
) {
return "CANCELLED";
}
if (blame === CaseStatus.STOPPED) return "STOPPED";
if (
blame === CaseStatus.WAITING_FOR_DOCUMENT_RESEND ||
claim === ClaimCaseStatus.WAITING_FOR_USER_RESEND
) {
return "WAITING_FOR_DOCUMENT_RESEND";
}
if (claim === ClaimCaseStatus.EXPERT_REVIEWING) return "EXPERT_REVIEWING";
if (claim === ClaimCaseStatus.EXPERT_VALIDATING_REPAIR_FACTORS) {
return "EXPERT_VALIDATING_FACTORS";
}
if (claim && INSURER_REVIEW_CLAIM_STATUSES.has(claim)) {
return "INSURER_REVIEW";
}
if (claim === ClaimCaseStatus.WAITING_FOR_DAMAGE_EXPERT) {
return "WAITING_FOR_DAMAGE_EXPERT";
}
if (blame === CaseStatus.WAITING_FOR_EXPERT) return "WAITING_FOR_BLAME_EXPERT";
if (blame === CaseStatus.WAITING_FOR_SIGNATURES) {
return "WAITING_FOR_SIGNATURES";
}
if (blame === CaseStatus.WAITING_FOR_SECOND_PARTY) {
return "WAITING_FOR_SECOND_PARTY";
}
if (blame === CaseStatus.COMPLETED && !claim) return "COMPLETED";
if (
blame === CaseStatus.OPEN ||
(claim && CLAIM_USER_PHASE.has(claim)) ||
(blame === CaseStatus.COMPLETED && claim && CLAIM_USER_PHASE.has(claim))
) {
return "IN_PROGRESS";
}
if (claim) return "IN_PROGRESS";
if (blame) return "IN_PROGRESS";
return "IN_PROGRESS";
}
export function countUnifiedFileStatuses(
entries: UnifiedFileStatusInput[],
): Record<UnifiedFileStatusKey | "all", number> {
const buckets = initialUnifiedFileStatusCounts();
for (const entry of entries) {
const key = resolveUnifiedFileStatus(entry);
buckets.all++;
buckets[key]++;
}
return buckets;
}
export function getUnifiedFileStatusCatalog(): UnifiedFileStatusDefinition[] {
return UNIFIED_FILE_STATUS_CATALOG;
}