import { FetchState, ID } from '../../commonStateTypes/common'; import { ZeniAPIStatus } from '../../responsePayload'; import { ZeniDate } from '../../zeniDayJS'; /** * A category grouping merchant category codes (MCCs) used while configuring * card policies (e.g. "Apparel", "AC Refrigeration Repair"). The same data * is consumed by both the manual policy-creation flow and the AI-CFO-driven * flow. */ export interface MccCategory { count: number; mccCodes: string[]; name: string; } export declare const ALL_CARD_POLICY_TEMPLATE_MODES: readonly ["strict", "flexible"]; export declare const toCardPolicyTemplateMode: (v: string) => "strict" | "flexible"; export type CardPolicyTemplateMode = ReturnType; export declare const ALL_CARD_POLICY_TEMPLATE_STATUSES: readonly ["active", "inactive", "archived"]; export declare const toCardPolicyTemplateStatus: (v: string) => "active" | "inactive" | "archived"; export type CardPolicyTemplateStatus = ReturnType; /** * Allow- / block-list pair scoped to a card-policy template. Empty arrays * mean "no restrictions on this dimension". */ export interface CardPolicyTemplateEntityList { categoryCodes: string[]; merchantNames: string[]; } /** * Spend-limit caps configured per template. Only `transaction` is modeled * today; additional cadences (e.g. daily, monthly) will be added if/when * the backend exposes them. * * `transaction` is `number | null`: `null` means the row's toggle is off * (no limit configured), `0` means the user explicitly entered zero with * the toggle on, and any positive value is the configured per-transaction * cap. */ export interface CardPolicyTemplateSpendLimits { transaction: number | null; } /** * Mapped (camelCase) representation of a card-policy template returned by * the cards micro-service. Stored on the entity slice keyed by * `templateId` so both the manual policy-creation UI and the AI-CFO flow * can read it. */ export interface CardPolicyTemplate { allowedEntity: CardPolicyTemplateEntityList; appliedCards: ID[]; blockedEntity: CardPolicyTemplateEntityList; cardsCount: number; categoryRestrictions: unknown[]; createdAt: ZeniDate; createdBy: ID; description: string; mode: CardPolicyTemplateMode; name: string; /** * Receipt-required threshold in dollars. `null` means the toggle is off * (no receipt requirement); `0` means the user explicitly entered zero * with the toggle on; any positive value is the configured threshold. */ requiredReceiptThreshold: number | null; spendLimits: CardPolicyTemplateSpendLimits; status: CardPolicyTemplateStatus; templateId: ID; tenantId: ID; updatedAt: ZeniDate; } /** * Aggregate counters returned by the list endpoint and reused across * any surface that wants to display tenant-wide policy stats without * triggering an extra fetch. */ export interface CardPolicyStats { activePolicies: number; totalCards: number; totalTemplates: number; } /** * FE-side (camelCase) mirror of the wire payload * `ExtractedCardPolicyRulesPayload`. Field names align slice-wise with * `CardPolicyTemplate` (`allowedEntity`, `blockedEntity`, * `requiredReceiptThreshold`) so the pre-fill mapper consumed by both * `CardPolicyCreatePage` (manual) and `CardPolicyInteractiveForm` * (AI CFO) can read either shape uniformly. */ export interface ExtractedCardPolicyRules { allowedEntity: CardPolicyTemplateEntityList; blockedEntity: CardPolicyTemplateEntityList; confidenceScore: number; policyName: string; requiredReceiptThreshold: number; transactionLimit: number; } /** * Lifecycle for the `POST /cards/1.0/policy-documents/extract` request. * Lives on the entity slice (rather than a view slice) so both the manual * `CardPolicyCreatePage` and the AI CFO `CardPolicyInteractiveForm` can * read the extracted rules from a single source of truth. * * `uploadedFileName` is captured at request-kickoff time so the UI can * render the "Policy.pdf ×" pill once the request completes without * having to keep a separate local copy of the file. */ export interface PolicyDocumentExtractionState { fetchState: FetchState; /** * AI CFO answer that owns the in-flight upload, when the extraction * was kicked off from inside an `upload`-mode `CardPolicyInteractiveForm`. * Captured at request-kickoff and read by the bridge epic to chain * `fetchCardPolicyRecommendationFromUpload` against the right answer. * `undefined` for manual `CardPolicyCreatePage` callers. */ aiCfoAnswerId?: ID; aiCfoChatSessionId?: ID; error?: ZeniAPIStatus; extractedRules?: ExtractedCardPolicyRules; uploadedFileName?: string; } /** * Lifecycle for `POST /cards/1.0/ai-cfo/policy-recommendation-from-upload`. * Chained after `extractPolicyDocument` succeeds in the AI CFO `upload` * mode — the FE forwards the just-returned `extracted_rules` and the BE * synthesizes a wizard plan + upload source metadata. * * `answerId` captures which AI CFO answer's `card_policy` payload should * receive the resulting `wizard_plan` patch (via * `updateAiCfoAnswerCardPolicyWizardPlan`). Stored here rather than on * the answer slice so the bridge epic can correlate the extract success * → recommendation kickoff without re-deriving it from the visualization. */ export interface PolicyRecommendationFromUploadState { fetchState: FetchState; answerId?: ID; chatSessionId?: ID; error?: ZeniAPIStatus; } /** * Lightweight `{vendorId, name}` row stored on the card-policy slice for * the chip-picker's vendor search dropdown. Sourced from * `/accounting/1.0/vendors` via `fetchCardPolicyVendorOptionsEpic`. * * Intentionally a subset of the full `Vendor` entity — populating this * slice does NOT touch the global `vendor`/`account`/`vendorList` * entities, so a card-policy search session never disturbs the user's * Vendors-tab list state. */ export interface CardPolicyVendorSearchEntry { name: string; vendorId: ID; } /** * Lifecycle for the `GET /accounting/1.0/vendors` (card-policy mode) * request. Only one in-flight search at a time; the latest typed search * wins (via `switchMap` in the epic). `searchString` is the text that * produced `vendors`, useful for stale-result guards in the UI. */ export interface CardPolicyVendorSearchState { fetchState: FetchState; searchString: string; vendors: CardPolicyVendorSearchEntry[]; error?: ZeniAPIStatus; } /** * Slice state for card-policy reference data shared across the manual and * AI-driven policy-creation flows. Each sub-resource tracks its own * `fetchState`/`error` so additional card-policy APIs can be added * alongside without coupling. */ export interface CardPolicyState { cardPolicyTemplateById: Record; mccCategories: MccCategory[]; mccCategoriesFetchState: FetchState; policyDocumentExtraction: PolicyDocumentExtractionState; /** * Lifecycle for the AI CFO `upload`-mode follow-up call. Sibling of * `policyDocumentExtraction`; the two together describe the full * upload chain: drop file → extract → recommend → wizard plan ready. */ policyRecommendationFromUpload: PolicyRecommendationFromUploadState; /** * MCC categories suggested by the BE as a default "Allow" seed for the * category chip cloud. Empty when the user lands without prior spend * history. See `suggested_allow_catagories` on the wire payload. */ suggestedAllowCategories: MccCategory[]; /** * Merchant names suggested by the BE as a default "Allow" seed for the * vendor chip cloud. Empty when the BE has no recommendation. See * `suggested_allow_merchants` on the wire payload. */ suggestedAllowMerchants: string[]; suggestedBlockCategories: MccCategory[]; suggestedBlockMerchants: string[]; /** * Server-driven vendor search results powering the chip picker's * search dropdown. Distinct from the global vendor entity store so * the card-policy flow never disturbs the user's Vendors-tab list. */ vendorSearch: CardPolicyVendorSearchState; cardPolicyStats?: CardPolicyStats; mccCategoriesError?: ZeniAPIStatus; }