export const TASK_STATUS = { PENDING_PAYMENT: 'pending_payment', PAID: 'paid', LINK_GENERATED: 'link_generated', CLAIMED: 'claimed', PENDING_BINDING_PREPARE: 'pending_binding_prepare', WAITING_BINDING: 'waiting_binding', ROLE_CONFIRMED: 'role_confirmed', REDEEMING: 'redeeming', DISPATCHED_PENDING_RETURN: 'dispatched_pending_return', COMPLETED: 'completed', REDEEMED: 'redeemed', RETRY_PENDING: 'retry_pending', MANUAL_REVIEW: 'manual_review', FAILED: 'failed', EXPIRED: 'expired', CLOSED: 'closed', } as const export type KnownTaskStatus = (typeof TASK_STATUS)[keyof typeof TASK_STATUS] export type TaskStatus = KnownTaskStatus | (string & {}) const TASK_TRANSITIONS: Record = { [TASK_STATUS.PENDING_PAYMENT]: [ TASK_STATUS.PAID, TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.CLOSED, ], [TASK_STATUS.PAID]: [ TASK_STATUS.LINK_GENERATED, TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.CLOSED, ], [TASK_STATUS.LINK_GENERATED]: [ TASK_STATUS.CLAIMED, TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ], [TASK_STATUS.CLAIMED]: [ TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ], [TASK_STATUS.PENDING_BINDING_PREPARE]: [ TASK_STATUS.WAITING_BINDING, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ], [TASK_STATUS.WAITING_BINDING]: [ TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ], [TASK_STATUS.ROLE_CONFIRMED]: [ TASK_STATUS.WAITING_BINDING, TASK_STATUS.REDEEMING, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ], [TASK_STATUS.REDEEMING]: [ TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, ], [TASK_STATUS.DISPATCHED_PENDING_RETURN]: [ TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.MANUAL_REVIEW, ], [TASK_STATUS.RETRY_PENDING]: [ TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.CLOSED, ], [TASK_STATUS.MANUAL_REVIEW]: [ TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING, TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.CLOSED, ], [TASK_STATUS.FAILED]: [TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.CLOSED], [TASK_STATUS.COMPLETED]: [], [TASK_STATUS.REDEEMED]: [], [TASK_STATUS.EXPIRED]: [], [TASK_STATUS.CLOSED]: [], } const FINAL_STATUSES = new Set([ TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ]) const OPEN_91_FAILED_STATUSES = new Set([ TASK_STATUS.FAILED, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.CLOSED, ]) const CLAIM_INACTIVE_STATUSES = new Set([ TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.FAILED, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ]) const PAID_PREPARATION_STABLE_STATUSES = new Set([ TASK_STATUS.LINK_GENERATED, TASK_STATUS.CLAIMED, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING, TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED, ]) const KUAISHOU_CLOUD_CLAIM_LINK_STATUSES = new Set([ TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.WAITING_BINDING, TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.FAILED, ]) const KUAISHOU_CLOUD_ROLE_CONFIRM_SETTLED_STATUSES = new Set([ TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING, TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.MANUAL_REVIEW, ]) const KUAISHOU_CLOUD_REDEEM_SETTLED_STATUSES = new Set([ TASK_STATUS.REDEEMING, TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.MANUAL_REVIEW, ]) const CLAIM_LINK_REGENERATABLE_STATUSES = new Set([ TASK_STATUS.LINK_GENERATED, TASK_STATUS.CLAIMED, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, ]) const KUAISHOU_CLOUD_RESULT_STATUSES = new Set([ TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.FAILED, ]) const FULFILLMENT_COMPLETED_STATUSES = new Set([ TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED, TASK_STATUS.REDEEMED, ]) const RETRYABLE_TASK_STATUSES = new Set([ TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW, ]) const KUAISHOU_CLOUD_PREPARABLE_STATUSES = new Set([ TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.FAILED, ]) const KUAISHOU_CLOUD_REBINDABLE_STATUSES = new Set([ TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.MANUAL_REVIEW, TASK_STATUS.RETRY_PENDING, ]) export function normalizeTaskStatus(value: unknown): TaskStatus { return String(value || '').trim() as TaskStatus } export function canTaskTransition(from: unknown, to: unknown): boolean { const current = normalizeTaskStatus(from) as KnownTaskStatus const next = normalizeTaskStatus(to) as KnownTaskStatus if (!current || !next || current === next) { return Boolean(current && next) } return Boolean(TASK_TRANSITIONS[current]?.includes(next)) } export function getTaskNextStatuses(status: unknown): readonly KnownTaskStatus[] { return TASK_TRANSITIONS[normalizeTaskStatus(status) as KnownTaskStatus] || [] } export function isTaskFinalStatus(status: unknown): boolean { return FINAL_STATUSES.has(normalizeTaskStatus(status)) } export function isOpen91FailedTaskStatus(status: unknown): boolean { return OPEN_91_FAILED_STATUSES.has(normalizeTaskStatus(status)) } export function isClaimInactiveTaskStatus(status: unknown): boolean { return CLAIM_INACTIVE_STATUSES.has(normalizeTaskStatus(status)) } export function isPaidPreparationStableStatus(status: unknown): boolean { return PAID_PREPARATION_STABLE_STATUSES.has(normalizeTaskStatus(status)) } export function shouldEnsureKuaishouCloudClaimLink(status: unknown): boolean { return KUAISHOU_CLOUD_CLAIM_LINK_STATUSES.has(normalizeTaskStatus(status)) } export function isKuaishouCloudRoleConfirmSettledStatus(status: unknown): boolean { return KUAISHOU_CLOUD_ROLE_CONFIRM_SETTLED_STATUSES.has(normalizeTaskStatus(status)) } export function isKuaishouCloudRedeemSettledStatus(status: unknown): boolean { return KUAISHOU_CLOUD_REDEEM_SETTLED_STATUSES.has(normalizeTaskStatus(status)) } export function canRedeemKuaishouCloudClaimStatus(status: unknown): boolean { return normalizeTaskStatus(status) === TASK_STATUS.ROLE_CONFIRMED } export function canRegenerateClaimLinkStatus(status: unknown): boolean { return CLAIM_LINK_REGENERATABLE_STATUSES.has(normalizeTaskStatus(status)) } export function hasKuaishouCloudRedeemResultStatus(status: unknown): boolean { return KUAISHOU_CLOUD_RESULT_STATUSES.has(normalizeTaskStatus(status)) } export function isTaskFulfillmentCompletedStatus(status: unknown): boolean { return FULFILLMENT_COMPLETED_STATUSES.has(normalizeTaskStatus(status)) } export function canRetryTaskStatus(status: unknown): boolean { return RETRYABLE_TASK_STATUSES.has(normalizeTaskStatus(status)) } export function canMarkManualReviewTaskStatus(status: unknown): boolean { const normalized = normalizeTaskStatus(status) return normalized !== TASK_STATUS.MANUAL_REVIEW && !isTaskFinalStatus(normalized) } export function canCompleteManualDispatchTaskStatus(status: unknown): boolean { return !isTaskFinalStatus(status) } export function canPrepareKuaishouCloudFulfillmentStatus(status: unknown): boolean { return KUAISHOU_CLOUD_PREPARABLE_STATUSES.has(normalizeTaskStatus(status)) } export function canRebindKuaishouCloudRoleStatus(status: unknown): boolean { return KUAISHOU_CLOUD_REBINDABLE_STATUSES.has(normalizeTaskStatus(status)) } export function canDispatchKuaishouCloudFulfillmentStatus(status: unknown): boolean { return normalizeTaskStatus(status) === TASK_STATUS.WAITING_BINDING } export function canReturnKuaishouCloudFulfillmentStatus(status: unknown): boolean { return normalizeTaskStatus(status) === TASK_STATUS.DISPATCHED_PENDING_RETURN } export function resolveInitialPaidTaskStatus( profile: | { requires_claim?: boolean executor_key?: unknown } | null | undefined, ): TaskStatus { if (Boolean(profile?.requires_claim)) { return TASK_STATUS.PAID } if (String(profile?.executor_key || '').trim() === 'kuaishou_ct_assisted') { return TASK_STATUS.PENDING_BINDING_PREPARE } if (String(profile?.executor_key || '').trim() === 'manual_dispatch') { return TASK_STATUS.MANUAL_REVIEW } return TASK_STATUS.PAID }