String? _parseDate(String? s) { if (s == null || s.isEmpty) return null; return s.length >= 10 ? s.substring(0, 10) : s; } class Inventory { final int id; final int? warehouseId; final int? productId; final int? stockInItemId; final double quantity; final String productCode; final String productName; final String series; final String spec; final String unit; final String warehouseName; final double? unitPrice; // 成本价(入库进价) final double? salePrice; // 单价(product 售价) final String? productionDate; final String batchNo; final String supplierName; final String remark; final int? minStock; final String brand; final String? createdAt; const Inventory({ required this.id, this.warehouseId, this.productId, this.stockInItemId, required this.quantity, this.productCode = '', this.productName = '', this.series = '', this.spec = '', this.unit = '', this.warehouseName = '', this.unitPrice, this.salePrice, this.productionDate, this.batchNo = '', this.supplierName = '', this.remark = '', this.minStock, this.brand = '', this.createdAt, }); factory Inventory.fromJson(Map json) => Inventory( id: (json['id'] as num).toInt(), warehouseId: (json['warehouse_id'] as num?)?.toInt(), productId: (json['product_id'] as num?)?.toInt(), stockInItemId: (json['stock_in_item_id'] as num?)?.toInt(), quantity: (json['quantity'] as num).toDouble(), productCode: json['product_code'] as String? ?? '', productName: json['product_name'] as String? ?? '', series: json['series'] as String? ?? '', spec: json['spec'] as String? ?? '', unit: json['unit'] as String? ?? '', warehouseName: json['warehouse_name'] as String? ?? '', unitPrice: (json['unit_price'] as num?)?.toDouble(), salePrice: (json['sale_price'] as num?)?.toDouble(), productionDate: _parseDate(json['production_date'] as String?), batchNo: json['batch_no'] as String? ?? '', supplierName: json['supplier_name'] as String? ?? '', remark: json['remark'] as String? ?? '', minStock: (json['min_stock'] as num?)?.toInt(), brand: json['brand'] as String? ?? '', createdAt: json['created_at'] as String?, ); } /// 全店库存 KPI 汇总(GET /inventory/summary,不随分页)。 class InventorySummary { final int skuCount; final double stockValue; final double inStockQty; final int shortageCount; final int warningCount; // 月初快照(KPI 环比):由 inventory_logs 反推 final int lastMonthSku; final double lastMonthQty; final double lastMonthValue; const InventorySummary({ this.skuCount = 0, this.stockValue = 0, this.inStockQty = 0, this.shortageCount = 0, this.warningCount = 0, this.lastMonthSku = 0, this.lastMonthQty = 0, this.lastMonthValue = 0, }); factory InventorySummary.fromJson(Map j) => InventorySummary( skuCount: (j['sku_count'] as num?)?.toInt() ?? 0, stockValue: (j['stock_value'] as num?)?.toDouble() ?? 0, inStockQty: (j['in_stock_qty'] as num?)?.toDouble() ?? 0, shortageCount: (j['shortage_count'] as num?)?.toInt() ?? 0, warningCount: (j['warning_count'] as num?)?.toInt() ?? 0, lastMonthSku: (j['last_month_sku'] as num?)?.toInt() ?? 0, lastMonthQty: (j['last_month_qty'] as num?)?.toDouble() ?? 0, lastMonthValue: (j['last_month_value'] as num?)?.toDouble() ?? 0, ); } class InventoryLog { final int warehouseId; final String? warehouseName; final int productId; final String? productName; final String direction; // in | out final double quantity; final double? qtyBefore; final double? qtyAfter; final String? refType; final int? refId; final String? createdAt; const InventoryLog({ required this.warehouseId, this.warehouseName, required this.productId, this.productName, required this.direction, required this.quantity, this.qtyBefore, this.qtyAfter, this.refType, this.refId, this.createdAt, }); factory InventoryLog.fromJson(Map json) => InventoryLog( warehouseId: (json['warehouse_id'] as num).toInt(), warehouseName: (json['warehouse'] as Map?)?['name'] as String?, productId: (json['product_id'] as num).toInt(), productName: (json['product'] as Map?)?['name'] as String?, direction: json['direction'] as String, quantity: (json['quantity'] as num).toDouble(), qtyBefore: json['qty_before'] != null ? (json['qty_before'] as num).toDouble() : null, qtyAfter: json['qty_after'] != null ? (json['qty_after'] as num).toDouble() : null, refType: json['ref_type'] as String?, refId: json['ref_id'] != null ? (json['ref_id'] as num).toInt() : null, createdAt: json['created_at'] as String?, ); }