← back to Govarbitrage
src/engines/types.ts
134 lines
// Shared engine types. Engines operate on plain numbers (US dollars) so they
// are pure, deterministic, and unit-testable independent of Prisma/Decimal.
export type ConditionKey =
| "NEW"
| "LIKE_NEW"
| "USED_GOOD"
| "USED_FAIR"
| "FOR_PARTS"
| "UNKNOWN";
export type SourceKey =
| "GOVDEALS"
| "PUBLIC_SURPLUS"
| "GSA_AUCTIONS"
| "COUNTY"
| "STATE_SURPLUS"
| "UNIVERSITY_SURPLUS"
| "MUNICIBID"
| "BID4ASSETS"
| "CSV"
| "EXTENSION"
| "OTHER";
export type RiskKey = "LOW" | "MEDIUM" | "HIGH";
export type DropShipKey = "EASY" | "MODERATE" | "DIFFICULT" | "INFEASIBLE";
export type ScoreProfileKey =
| "OVERALL_OPPORTUNITY"
| "BEST_ARBITRAGE"
| "QUICK_FLIP"
| "COLLECTOR"
| "LOCAL_PICKUP"
| "EASY_FREIGHT"
| "PARTS_ONLY"
| "HIGH_CONFIDENCE"
| "HIGH_PROFIT";
/** Inputs the valuation engine needs (anchor + item facts). */
export interface ValuationInput {
/** Best estimate of new retail price; the anchor for all derived values. */
newRetail: number;
condition: ConditionKey;
quantity: number;
/** 0..100 demand for this category/brand (from research/AI or a default). */
demandScore: number;
/** How well the item was identified (0..1); drives confidence. */
identificationConfidence: number;
/** Count of real comparable sales found; drives confidence. */
comparableCount?: number;
}
export interface Valuation {
newRetail: number;
newReplacement: number;
avgRetail: number;
usedSoldPrice: number;
usedAskingPrice: number;
usedLow: number;
usedHigh: number;
wholesaleValue: number;
liquidationValue: number;
sellTodayValue: number;
value7Day: number;
value30Day: number;
value90Day: number;
expectedSalePrice: number;
probabilityOfSale: number; // 0..1
daysUntilSold: number;
confidenceScore: number; // 0..100
}
export interface CostInput {
source: SourceKey;
winningBid: number;
quantity: number;
weightLbs: number;
condition: ConditionKey;
expectedSalePrice: number;
daysUntilSold: number;
/** true when the item must be picked up in person (no shipping from seller). */
localPickup?: boolean;
/** destination sales-tax rate applied to the purchase (resale certs may zero this). */
purchaseTaxRate?: number;
/** repair estimate override (else derived from condition). */
repairsOverride?: number;
}
export interface CostBreakdown {
winningBid: number;
buyerPremium: number;
salesTax: number;
shipping: number;
freight: number;
insurance: number;
packing: number;
pickupLabor: number;
testing: number;
repairs: number;
certification: number;
marketplaceFees: number;
paymentFees: number;
storage: number;
photography: number;
listingLabor: number;
expectedReturns: number;
totalInvestment: number;
expectedNetProfit: number;
roi: number;
annualizedReturn: number;
recommendedMaxBid: number;
assumptions: Record<string, string | number>;
}
export interface ScoreComponents {
arbitrage: number;
demand: number;
velocity: number;
logistics: number;
condition: number;
competition: number;
buyer: number;
}
export interface ProfileScore {
profile: ScoreProfileKey;
value: number;
components: ScoreComponents;
risk: RiskKey;
dropShip: DropShipKey;
explanation: string;
factors: { label: string; weight: number; contribution: number }[];
}