import '../../shared/models/approval_status.dart'; /// 费用报销主表,对应 [Expense] 表。 class ExpenseModel { final String id; final String expenseNo; final DateTime? expenseDate; final String applicantId; final String applicantName; final String deptId; final String deptName; final String currencyCode; final bool isGenerateVoucher; final String voucherNo; final double approvedAmount; final double totalAmount; final String purpose; final String remark; final String paymentMethod; final bool isInvoiceVerified; final bool isTaxIdMatched; final bool isCategoryCompliant; final String bankTransferNo; final String paymentStatus; final String status; final String approvalInstanceId; final String previousInstanceIds; final DateTime? effectiveDate; final String auditorId; final int version; final DateTime createTime; final DateTime updateTime; final bool isDeleted; // ── 瞬态字段(API 从 ERP 实时查询,非存储) ── final String currentApproverId; final List approvalChain; final List approvalRecords; // ── 子表 ── final List details; final List attachments; const ExpenseModel({ required this.id, required this.expenseNo, this.expenseDate, this.applicantId = '', this.applicantName = '', this.deptId = '', this.deptName = '', this.currencyCode = 'CNY', this.isGenerateVoucher = false, this.voucherNo = '', this.approvedAmount = 0.0, this.totalAmount = 0.0, this.purpose = '', this.remark = '', this.paymentMethod = '', this.isInvoiceVerified = false, this.isTaxIdMatched = false, this.isCategoryCompliant = false, this.bankTransferNo = '', this.paymentStatus = 'unpaid', this.status = 'draft', this.approvalInstanceId = '', this.previousInstanceIds = '', this.effectiveDate, this.auditorId = '', this.version = 1, required this.createTime, required this.updateTime, this.isDeleted = false, this.currentApproverId = '', this.approvalChain = const [], this.approvalRecords = const [], this.details = const [], this.attachments = const [], }); factory ExpenseModel.fromJson(Map json) { return ExpenseModel( id: json['id'] as String, expenseNo: json['expenseNo'] as String? ?? '', expenseDate: json['expenseDate'] != null ? DateTime.parse(json['expenseDate'] as String) : null, applicantId: json['applicantId'] as String? ?? '', applicantName: json['applicantName'] as String? ?? '', deptId: json['deptId'] as String? ?? '', deptName: json['deptName'] as String? ?? '', currencyCode: json['currencyCode'] as String? ?? 'CNY', isGenerateVoucher: json['isGenerateVoucher'] as bool? ?? false, voucherNo: json['voucherNo'] as String? ?? '', approvedAmount: (json['approvedAmount'] as num?)?.toDouble() ?? 0.0, totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? 0.0, purpose: json['purpose'] as String? ?? '', remark: json['remark'] as String? ?? '', paymentMethod: json['paymentMethod'] as String? ?? '', isInvoiceVerified: json['isInvoiceVerified'] as bool? ?? false, isTaxIdMatched: json['isTaxIdMatched'] as bool? ?? false, isCategoryCompliant: json['isCategoryCompliant'] as bool? ?? false, bankTransferNo: json['bankTransferNo'] as String? ?? '', paymentStatus: json['paymentStatus'] as String? ?? 'unpaid', status: json['status'] as String? ?? 'draft', approvalInstanceId: json['approvalInstanceId'] as String? ?? '', previousInstanceIds: json['previousInstanceIds'] as String? ?? '', effectiveDate: json['effectiveDate'] != null ? DateTime.parse(json['effectiveDate'] as String) : null, auditorId: json['auditorId'] as String? ?? '', version: json['version'] as int? ?? 1, createTime: DateTime.parse(json['createTime'] as String), updateTime: DateTime.parse(json['updateTime'] as String), isDeleted: json['isDeleted'] as bool? ?? false, currentApproverId: json['currentApproverId'] as String? ?? '', approvalChain: (json['approvalChain'] as List?) ?.map((e) => e as String) .toList() ?? [], approvalRecords: (json['approvalRecords'] as List?) ?.map((e) => ApprovalRecord.fromJson(e as Map)) .toList() ?? [], details: (json['details'] as List?) ?.map( (e) => ExpenseDetailModel.fromJson(e as Map), ) .toList() ?? [], attachments: (json['attachments'] as List?) ?.map((e) => e as String) .toList() ?? [], ); } Map toJson() => { 'id': id, 'expenseNo': expenseNo, 'expenseDate': expenseDate?.toIso8601String(), 'applicantId': applicantId, 'applicantName': applicantName, 'deptId': deptId, 'deptName': deptName, 'currencyCode': currencyCode, 'isGenerateVoucher': isGenerateVoucher, 'voucherNo': voucherNo, 'approvedAmount': approvedAmount, 'totalAmount': totalAmount, 'purpose': purpose, 'remark': remark, 'paymentMethod': paymentMethod, 'isInvoiceVerified': isInvoiceVerified, 'isTaxIdMatched': isTaxIdMatched, 'isCategoryCompliant': isCategoryCompliant, 'bankTransferNo': bankTransferNo, 'paymentStatus': paymentStatus, 'status': status, 'approvalInstanceId': approvalInstanceId, 'previousInstanceIds': previousInstanceIds, 'effectiveDate': effectiveDate?.toIso8601String(), 'auditorId': auditorId, 'version': version, 'createTime': createTime.toIso8601String(), 'updateTime': updateTime.toIso8601String(), 'isDeleted': isDeleted, 'currentApproverId': currentApproverId, 'approvalChain': approvalChain, 'approvalRecords': approvalRecords.map((r) => r.toJson()).toList(), 'details': details.map((d) => d.toJson()).toList(), 'attachments': attachments, }; ExpenseModel copyWith({ String? id, String? expenseNo, DateTime? expenseDate, String? applicantId, String? applicantName, String? deptId, String? deptName, String? currencyCode, bool? isGenerateVoucher, String? voucherNo, double? approvedAmount, double? totalAmount, String? purpose, String? remark, String? paymentMethod, bool? isInvoiceVerified, bool? isTaxIdMatched, bool? isCategoryCompliant, String? bankTransferNo, String? paymentStatus, String? status, String? approvalInstanceId, String? previousInstanceIds, DateTime? effectiveDate, String? auditorId, int? version, DateTime? createTime, DateTime? updateTime, bool? isDeleted, String? currentApproverId, List? approvalChain, List? approvalRecords, List? details, List? attachments, }) { return ExpenseModel( id: id ?? this.id, expenseNo: expenseNo ?? this.expenseNo, expenseDate: expenseDate ?? this.expenseDate, applicantId: applicantId ?? this.applicantId, applicantName: applicantName ?? this.applicantName, deptId: deptId ?? this.deptId, deptName: deptName ?? this.deptName, currencyCode: currencyCode ?? this.currencyCode, isGenerateVoucher: isGenerateVoucher ?? this.isGenerateVoucher, voucherNo: voucherNo ?? this.voucherNo, approvedAmount: approvedAmount ?? this.approvedAmount, totalAmount: totalAmount ?? this.totalAmount, purpose: purpose ?? this.purpose, paymentMethod: paymentMethod ?? this.paymentMethod, isInvoiceVerified: isInvoiceVerified ?? this.isInvoiceVerified, isTaxIdMatched: isTaxIdMatched ?? this.isTaxIdMatched, isCategoryCompliant: isCategoryCompliant ?? this.isCategoryCompliant, bankTransferNo: bankTransferNo ?? this.bankTransferNo, paymentStatus: paymentStatus ?? this.paymentStatus, status: status ?? this.status, approvalInstanceId: approvalInstanceId ?? this.approvalInstanceId, previousInstanceIds: previousInstanceIds ?? this.previousInstanceIds, effectiveDate: effectiveDate ?? this.effectiveDate, auditorId: auditorId ?? this.auditorId, version: version ?? this.version, createTime: createTime ?? this.createTime, updateTime: updateTime ?? this.updateTime, isDeleted: isDeleted ?? this.isDeleted, currentApproverId: currentApproverId ?? this.currentApproverId, approvalChain: approvalChain ?? this.approvalChain, approvalRecords: approvalRecords ?? this.approvalRecords, details: details ?? this.details, attachments: attachments ?? this.attachments, ); } } /// 费用报销明细,对应 [ExpenseDetail] 表。 class ExpenseDetailModel { final String id; final String expenseId; final String expenseApplyId; final String expenseApplyNo; final DateTime? expenseApplyDate; final String expenseCategory; final String purpose; final String projectId; final String projectName; final String costDeptId; final String costDeptName; final String acctSubjectId; final String acctSubjectName; final double amount; final double taxRate; final double taxAmount; final double totalAmount; final String currencyCode; final double exchangeRate; final double baseAmount; final double approvedAmount; final String customerVendorId; final String customerVendorName; final double offsetAmount; final String bankName; final String bankAccountName; final String bankAccount; final String remark; final int sortOrder; final List attachments; final DateTime createTime; final DateTime updateTime; final bool isDeleted; const ExpenseDetailModel({ required this.id, required this.expenseId, this.expenseApplyId = '', this.expenseApplyNo = '', this.expenseApplyDate, this.expenseCategory = '', this.purpose = '', this.projectId = '', this.projectName = '', this.costDeptId = '', this.costDeptName = '', this.acctSubjectId = '', this.acctSubjectName = '', required this.amount, this.taxRate = 0.0, this.taxAmount = 0.0, required this.totalAmount, this.currencyCode = 'CNY', this.exchangeRate = 1.0, this.baseAmount = 0.0, this.approvedAmount = 0.0, this.customerVendorId = '', this.customerVendorName = '', this.offsetAmount = 0.0, this.bankName = '', this.bankAccountName = '', this.bankAccount = '', this.remark = '', this.sortOrder = 1, this.attachments = const [], required this.createTime, required this.updateTime, this.isDeleted = false, }); factory ExpenseDetailModel.fromJson(Map json) { return ExpenseDetailModel( id: json['id'] as String, expenseId: json['expenseId'] as String? ?? '', expenseApplyId: json['expenseApplyId'] as String? ?? '', expenseApplyNo: json['expenseApplyNo'] as String? ?? '', expenseApplyDate: json['expenseApplyDate'] != null ? DateTime.parse(json['expenseApplyDate'] as String) : null, expenseCategory: json['expenseCategory'] as String? ?? '', purpose: json['purpose'] as String? ?? '', projectId: json['projectId'] as String? ?? '', projectName: json['projectName'] as String? ?? '', costDeptId: json['costDeptId'] as String? ?? '', costDeptName: json['costDeptName'] as String? ?? '', acctSubjectId: json['acctSubjectId'] as String? ?? '', acctSubjectName: json['acctSubjectName'] as String? ?? '', amount: (json['amount'] as num?)?.toDouble() ?? 0.0, taxRate: (json['taxRate'] as num?)?.toDouble() ?? 0.0, taxAmount: (json['taxAmount'] as num?)?.toDouble() ?? 0.0, totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? 0.0, currencyCode: json['currencyCode'] as String? ?? 'CNY', exchangeRate: (json['exchangeRate'] as num?)?.toDouble() ?? 1.0, baseAmount: (json['baseAmount'] as num?)?.toDouble() ?? 0.0, approvedAmount: (json['approvedAmount'] as num?)?.toDouble() ?? 0.0, customerVendorId: json['customerVendorId'] as String? ?? '', customerVendorName: json['customerVendorName'] as String? ?? '', offsetAmount: (json['offsetAmount'] as num?)?.toDouble() ?? 0.0, bankName: json['bankName'] as String? ?? '', bankAccountName: json['bankAccountName'] as String? ?? '', bankAccount: json['bankAccount'] as String? ?? '', remark: json['remark'] as String? ?? '', sortOrder: json['sortOrder'] as int? ?? 1, attachments: (json['attachments'] as List?) ?.map((e) => e as String) .toList() ?? [], createTime: DateTime.parse(json['createTime'] as String), updateTime: DateTime.parse(json['updateTime'] as String), isDeleted: json['isDeleted'] as bool? ?? false, ); } Map toJson() => { 'id': id, 'expenseId': expenseId, 'expenseApplyId': expenseApplyId, 'expenseApplyNo': expenseApplyNo, 'expenseApplyDate': expenseApplyDate?.toIso8601String(), 'expenseCategory': expenseCategory, 'purpose': purpose, 'projectId': projectId, 'projectName': projectName, 'costDeptId': costDeptId, 'costDeptName': costDeptName, 'acctSubjectId': acctSubjectId, 'acctSubjectName': acctSubjectName, 'amount': amount, 'taxRate': taxRate, 'taxAmount': taxAmount, 'totalAmount': totalAmount, 'currencyCode': currencyCode, 'exchangeRate': exchangeRate, 'baseAmount': baseAmount, 'approvedAmount': approvedAmount, 'customerVendorId': customerVendorId, 'customerVendorName': customerVendorName, 'offsetAmount': offsetAmount, 'bankName': bankName, 'bankAccountName': bankAccountName, 'bankAccount': bankAccount, 'remark': remark, 'sortOrder': sortOrder, 'attachments': attachments, 'createTime': createTime.toIso8601String(), 'updateTime': updateTime.toIso8601String(), 'isDeleted': isDeleted, }; ExpenseDetailModel copyWith({ String? id, String? expenseId, String? expenseApplyId, String? expenseApplyNo, DateTime? expenseApplyDate, String? expenseCategory, String? purpose, String? projectId, String? projectName, String? costDeptId, String? costDeptName, String? acctSubjectId, String? acctSubjectName, double? amount, double? taxRate, double? taxAmount, double? totalAmount, String? currencyCode, double? exchangeRate, double? baseAmount, double? approvedAmount, String? customerVendorId, String? customerVendorName, double? offsetAmount, String? bankName, String? bankAccountName, String? bankAccount, String? remark, int? sortOrder, List? attachments, DateTime? createTime, DateTime? updateTime, bool? isDeleted, }) { return ExpenseDetailModel( id: id ?? this.id, expenseId: expenseId ?? this.expenseId, expenseApplyId: expenseApplyId ?? this.expenseApplyId, expenseApplyNo: expenseApplyNo ?? this.expenseApplyNo, expenseApplyDate: expenseApplyDate ?? this.expenseApplyDate, expenseCategory: expenseCategory ?? this.expenseCategory, purpose: purpose ?? this.purpose, projectId: projectId ?? this.projectId, projectName: projectName ?? this.projectName, costDeptId: costDeptId ?? this.costDeptId, costDeptName: costDeptName ?? this.costDeptName, acctSubjectId: acctSubjectId ?? this.acctSubjectId, acctSubjectName: acctSubjectName ?? this.acctSubjectName, amount: amount ?? this.amount, taxRate: taxRate ?? this.taxRate, taxAmount: taxAmount ?? this.taxAmount, totalAmount: totalAmount ?? this.totalAmount, currencyCode: currencyCode ?? this.currencyCode, exchangeRate: exchangeRate ?? this.exchangeRate, baseAmount: baseAmount ?? this.baseAmount, approvedAmount: approvedAmount ?? this.approvedAmount, customerVendorId: customerVendorId ?? this.customerVendorId, customerVendorName: customerVendorName ?? this.customerVendorName, offsetAmount: offsetAmount ?? this.offsetAmount, bankName: bankName ?? this.bankName, bankAccountName: bankAccountName ?? this.bankAccountName, bankAccount: bankAccount ?? this.bankAccount, remark: remark ?? this.remark, sortOrder: sortOrder ?? this.sortOrder, attachments: attachments ?? this.attachments, createTime: createTime ?? this.createTime, updateTime: updateTime ?? this.updateTime, isDeleted: isDeleted ?? this.isDeleted, ); } }