expense_model.dart 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. import '../../shared/models/approval_status.dart';
  2. /// 费用报销主表,对应 [Expense] 表。
  3. class ExpenseModel {
  4. final String id;
  5. final String expenseNo;
  6. final DateTime? expenseDate;
  7. final String applicantId;
  8. final String applicantName;
  9. final String deptId;
  10. final String deptName;
  11. final String currencyCode;
  12. final bool isGenerateVoucher;
  13. final String voucherNo;
  14. final double approvedAmount;
  15. final double totalAmount;
  16. final String purpose;
  17. final String remark;
  18. final String paymentMethod;
  19. final bool isInvoiceVerified;
  20. final bool isTaxIdMatched;
  21. final bool isCategoryCompliant;
  22. final String bankTransferNo;
  23. final String paymentStatus;
  24. final String status;
  25. final String approvalInstanceId;
  26. final String previousInstanceIds;
  27. final DateTime? effectiveDate;
  28. final String auditorId;
  29. final int version;
  30. final DateTime createTime;
  31. final DateTime updateTime;
  32. final bool isDeleted;
  33. final int isTransferred;
  34. final int isClosed;
  35. // ── 瞬态字段(API 从 ERP 实时查询,非存储) ──
  36. final String currentApproverId;
  37. final List<String> approvalChain;
  38. final List<ApprovalRecord> approvalRecords;
  39. // ── 子表 ──
  40. final List<ExpenseDetailModel> details;
  41. final List<String> attachments;
  42. const ExpenseModel({
  43. required this.id,
  44. required this.expenseNo,
  45. this.expenseDate,
  46. this.applicantId = '',
  47. this.applicantName = '',
  48. this.deptId = '',
  49. this.deptName = '',
  50. this.currencyCode = '',
  51. this.isGenerateVoucher = true,
  52. this.voucherNo = '',
  53. this.approvedAmount = 0.0,
  54. this.totalAmount = 0.0,
  55. this.purpose = '',
  56. this.remark = '',
  57. this.paymentMethod = '',
  58. this.isInvoiceVerified = false,
  59. this.isTaxIdMatched = false,
  60. this.isCategoryCompliant = false,
  61. this.bankTransferNo = '',
  62. this.paymentStatus = 'unpaid',
  63. this.status = 'draft',
  64. this.approvalInstanceId = '',
  65. this.previousInstanceIds = '',
  66. this.effectiveDate,
  67. this.auditorId = '',
  68. this.version = 1,
  69. required this.createTime,
  70. required this.updateTime,
  71. this.isDeleted = false,
  72. this.isTransferred = 0,
  73. this.isClosed = 0,
  74. this.currentApproverId = '',
  75. this.approvalChain = const [],
  76. this.approvalRecords = const [],
  77. this.details = const [],
  78. this.attachments = const [],
  79. });
  80. factory ExpenseModel.fromJson(Map<String, dynamic> json) {
  81. return ExpenseModel(
  82. id: json['id'] as String? ?? '',
  83. expenseNo: json['expenseNo'] as String? ?? '',
  84. expenseDate: json['expenseDate'] != null
  85. ? DateTime.parse(json['expenseDate'] as String)
  86. : null,
  87. applicantId: json['usrNo'] as String? ?? '',
  88. applicantName: json['applicantName'] as String? ?? json['usrNo'] as String? ?? '',
  89. deptId: json['dept'] as String? ?? '',
  90. deptName: json['deptName'] as String? ?? json['dept'] as String? ?? '',
  91. currencyCode: json['curId'] as String? ?? '',
  92. isGenerateVoucher: json['isGenerateVoucher'] as bool? ?? false,
  93. voucherNo: json['vohNo'] as String? ?? '',
  94. approvedAmount: (json['approvedAmount'] as num?)?.toDouble() ?? 0.0,
  95. totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? 0.0,
  96. purpose: json['reason'] as String? ?? json['purpose'] as String? ?? '',
  97. remark: json['rem'] as String? ?? '',
  98. paymentMethod: json['payId'] as String? ?? '',
  99. isInvoiceVerified: json['isInvoiceVerified'] as bool? ?? false,
  100. isTaxIdMatched: json['isTaxIdMatched'] as bool? ?? false,
  101. isCategoryCompliant: json['isCategoryCompliant'] as bool? ?? false,
  102. bankTransferNo: json['bankTransferNo'] as String? ?? '',
  103. paymentStatus: json['paymentStatus'] as String? ?? 'unpaid',
  104. status: json['clsDate'] != null ? 'closed' : (json['status'] as String? ?? 'draft'),
  105. approvalInstanceId: json['approvalInstanceId'] as String? ?? '',
  106. previousInstanceIds: json['previousInstanceIds'] as String? ?? '',
  107. effectiveDate: json['effDd'] != null
  108. ? DateTime.parse(json['effDd'] as String)
  109. : null,
  110. auditorId: json['chkMan'] as String? ?? '',
  111. version: json['version'] as int? ?? 1,
  112. createTime: json['createTime'] != null
  113. ? DateTime.parse(json['createTime'] as String)
  114. : DateTime.now(),
  115. updateTime: json['updateTime'] != null
  116. ? DateTime.parse(json['updateTime'] as String)
  117. : DateTime.now(),
  118. isDeleted: json['isDeleted'] as bool? ?? false,
  119. isTransferred: json['isTransferred'] as int? ?? 0,
  120. isClosed: json['isClosed'] as int? ?? 0,
  121. currentApproverId: json['currentApproverId'] as String? ?? '',
  122. approvalChain:
  123. (json['approvalChain'] as List<dynamic>?)
  124. ?.map((e) => e as String)
  125. .toList() ??
  126. [],
  127. approvalRecords:
  128. (json['approvalRecords'] as List<dynamic>?)
  129. ?.map((e) => ApprovalRecord.fromJson(e as Map<String, dynamic>))
  130. .toList() ??
  131. [],
  132. details:
  133. (json['details'] as List<dynamic>?)
  134. ?.map(
  135. (e) => ExpenseDetailModel.fromJson(e as Map<String, dynamic>),
  136. )
  137. .toList() ??
  138. [],
  139. attachments:
  140. (json['attachments'] as List<dynamic>?)
  141. ?.map((e) => e as String)
  142. .toList() ??
  143. [],
  144. );
  145. }
  146. Map<String, dynamic> toJson() => {
  147. 'id': id,
  148. 'expenseNo': expenseNo,
  149. 'expenseDate': expenseDate?.toIso8601String(),
  150. 'applicantId': applicantId,
  151. 'applicantName': applicantName,
  152. 'deptId': deptId,
  153. 'deptName': deptName,
  154. 'currencyCode': currencyCode,
  155. 'isGenerateVoucher': isGenerateVoucher,
  156. 'voucherNo': voucherNo,
  157. 'approvedAmount': approvedAmount,
  158. 'totalAmount': totalAmount,
  159. 'purpose': purpose,
  160. 'remark': remark,
  161. 'paymentMethod': paymentMethod,
  162. 'isInvoiceVerified': isInvoiceVerified,
  163. 'isTaxIdMatched': isTaxIdMatched,
  164. 'isCategoryCompliant': isCategoryCompliant,
  165. 'bankTransferNo': bankTransferNo,
  166. 'paymentStatus': paymentStatus,
  167. 'status': status,
  168. 'approvalInstanceId': approvalInstanceId,
  169. 'previousInstanceIds': previousInstanceIds,
  170. 'effectiveDate': effectiveDate?.toIso8601String(),
  171. 'auditorId': auditorId,
  172. 'version': version,
  173. 'createTime': createTime.toIso8601String(),
  174. 'updateTime': updateTime.toIso8601String(),
  175. 'isDeleted': isDeleted,
  176. 'isTransferred': isTransferred,
  177. 'isClosed': isClosed,
  178. 'currentApproverId': currentApproverId,
  179. 'approvalChain': approvalChain,
  180. 'approvalRecords': approvalRecords.map((r) => r.toJson()).toList(),
  181. 'details': details.map((d) => d.toJson()).toList(),
  182. 'attachments': attachments,
  183. };
  184. ExpenseModel copyWith({
  185. String? id,
  186. String? expenseNo,
  187. DateTime? expenseDate,
  188. String? applicantId,
  189. String? applicantName,
  190. String? deptId,
  191. String? deptName,
  192. String? currencyCode,
  193. bool? isGenerateVoucher,
  194. String? voucherNo,
  195. double? approvedAmount,
  196. double? totalAmount,
  197. String? purpose,
  198. String? remark,
  199. String? paymentMethod,
  200. bool? isInvoiceVerified,
  201. bool? isTaxIdMatched,
  202. bool? isCategoryCompliant,
  203. String? bankTransferNo,
  204. String? paymentStatus,
  205. String? status,
  206. String? approvalInstanceId,
  207. String? previousInstanceIds,
  208. DateTime? effectiveDate,
  209. String? auditorId,
  210. int? version,
  211. DateTime? createTime,
  212. DateTime? updateTime,
  213. bool? isDeleted,
  214. int? isTransferred,
  215. int? isClosed,
  216. String? currentApproverId,
  217. List<String>? approvalChain,
  218. List<ApprovalRecord>? approvalRecords,
  219. List<ExpenseDetailModel>? details,
  220. List<String>? attachments,
  221. }) {
  222. return ExpenseModel(
  223. id: id ?? this.id,
  224. expenseNo: expenseNo ?? this.expenseNo,
  225. expenseDate: expenseDate ?? this.expenseDate,
  226. applicantId: applicantId ?? this.applicantId,
  227. applicantName: applicantName ?? this.applicantName,
  228. deptId: deptId ?? this.deptId,
  229. deptName: deptName ?? this.deptName,
  230. currencyCode: currencyCode ?? this.currencyCode,
  231. isGenerateVoucher: isGenerateVoucher ?? this.isGenerateVoucher,
  232. voucherNo: voucherNo ?? this.voucherNo,
  233. approvedAmount: approvedAmount ?? this.approvedAmount,
  234. totalAmount: totalAmount ?? this.totalAmount,
  235. purpose: purpose ?? this.purpose,
  236. remark: remark ?? this.remark,
  237. paymentMethod: paymentMethod ?? this.paymentMethod,
  238. isInvoiceVerified: isInvoiceVerified ?? this.isInvoiceVerified,
  239. isTaxIdMatched: isTaxIdMatched ?? this.isTaxIdMatched,
  240. isCategoryCompliant: isCategoryCompliant ?? this.isCategoryCompliant,
  241. bankTransferNo: bankTransferNo ?? this.bankTransferNo,
  242. paymentStatus: paymentStatus ?? this.paymentStatus,
  243. status: status ?? this.status,
  244. approvalInstanceId: approvalInstanceId ?? this.approvalInstanceId,
  245. previousInstanceIds: previousInstanceIds ?? this.previousInstanceIds,
  246. effectiveDate: effectiveDate ?? this.effectiveDate,
  247. auditorId: auditorId ?? this.auditorId,
  248. version: version ?? this.version,
  249. createTime: createTime ?? this.createTime,
  250. updateTime: updateTime ?? this.updateTime,
  251. isDeleted: isDeleted ?? this.isDeleted,
  252. isTransferred: isTransferred ?? this.isTransferred,
  253. isClosed: isClosed ?? this.isClosed,
  254. currentApproverId: currentApproverId ?? this.currentApproverId,
  255. approvalChain: approvalChain ?? this.approvalChain,
  256. approvalRecords: approvalRecords ?? this.approvalRecords,
  257. details: details ?? this.details,
  258. attachments: attachments ?? this.attachments,
  259. );
  260. }
  261. }
  262. /// 费用报销明细,对应 [ExpenseDetail] 表。
  263. class ExpenseDetailModel {
  264. final String id;
  265. final String expenseId;
  266. final String expenseApplyId;
  267. final String expenseApplyNo;
  268. final DateTime? expenseApplyDate;
  269. final String expenseCategory;
  270. final String categoryName;
  271. final String priority;
  272. final String purpose;
  273. final String projectId;
  274. final String projectName;
  275. final String costDeptId;
  276. final String costDeptName;
  277. final String acctSubjectId;
  278. final String acctSubjectName;
  279. final double amount;
  280. final double taxRate;
  281. final double taxAmount;
  282. final double totalAmount;
  283. final String currencyCode;
  284. final double exchangeRate;
  285. final double baseAmount;
  286. final double approvedAmount;
  287. final String customerVendorId;
  288. final String customerVendorName;
  289. final double offsetAmount;
  290. final String bankName;
  291. final String bankAccountName;
  292. final String bankAccount;
  293. final String sqMan;
  294. final String sqManName;
  295. final String aeNo;
  296. final String aeDd;
  297. final String remark;
  298. final int? preItm;
  299. final int sortOrder;
  300. final List<String> attachments;
  301. final DateTime createTime;
  302. final DateTime updateTime;
  303. final bool isDeleted;
  304. const ExpenseDetailModel({
  305. required this.id,
  306. required this.expenseId,
  307. this.expenseApplyId = '',
  308. this.expenseApplyNo = '',
  309. this.expenseApplyDate,
  310. this.expenseCategory = '',
  311. this.categoryName = '',
  312. this.priority = '1',
  313. this.purpose = '',
  314. this.projectId = '',
  315. this.projectName = '',
  316. this.costDeptId = '',
  317. this.costDeptName = '',
  318. this.acctSubjectId = '',
  319. this.acctSubjectName = '',
  320. required this.amount,
  321. this.taxRate = 0,
  322. this.taxAmount = 0.0,
  323. required this.totalAmount,
  324. this.currencyCode = '',
  325. this.exchangeRate = 1.0,
  326. this.baseAmount = 0.0,
  327. this.approvedAmount = 0.0,
  328. this.customerVendorId = '',
  329. this.customerVendorName = '',
  330. this.offsetAmount = 0.0,
  331. this.bankName = '',
  332. this.bankAccountName = '',
  333. this.bankAccount = '',
  334. this.sqMan = '',
  335. this.sqManName = '',
  336. this.aeNo = '',
  337. this.aeDd = '',
  338. this.remark = '',
  339. this.preItm,
  340. this.sortOrder = 1,
  341. this.attachments = const [],
  342. required this.createTime,
  343. required this.updateTime,
  344. this.isDeleted = false,
  345. });
  346. factory ExpenseDetailModel.fromJson(Map<String, dynamic> json) {
  347. return ExpenseDetailModel(
  348. id: json['id'] as String? ?? '',
  349. expenseId: json['expenseId'] as String? ?? '',
  350. expenseApplyId: json['aeNo'] as String? ?? '',
  351. expenseApplyNo: json['aeNo'] as String? ?? '',
  352. expenseApplyDate: json['aeDd'] != null
  353. ? DateTime.parse(json['aeDd'] as String)
  354. : null,
  355. expenseCategory: json['idxNo'] as String? ?? json['expenseCategory'] as String? ?? '',
  356. categoryName: json['idxName'] as String? ?? json['categoryName'] as String? ?? '',
  357. priority: json['priority'] as String? ?? '1',
  358. purpose: json['purpose'] as String? ?? '',
  359. projectId: json['objNo'] as String? ?? '',
  360. projectName: json['objName'] as String? ?? json['projectName'] as String? ?? '',
  361. costDeptId: json['dep'] as String? ?? '',
  362. costDeptName: json['depName'] as String? ?? json['dep'] as String? ?? '',
  363. acctSubjectId: json['accNo'] as String? ?? '',
  364. acctSubjectName: json['accName'] as String? ?? '',
  365. amount: (json['amount'] as num?)?.toDouble() ?? (json['amtn'] as num?)?.toDouble() ?? 0.0,
  366. taxRate: (json['taxRate'] as num?)?.toDouble() ?? (json['taxRto'] as num?)?.toDouble() ?? 0.0,
  367. taxAmount: (json['taxAmount'] as num?)?.toDouble() ?? (json['tax'] as num?)?.toDouble() ?? 0.0,
  368. totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? (json['amt'] as num?)?.toDouble() ?? 0.0,
  369. currencyCode: json['currencyCode'] as String? ?? '',
  370. exchangeRate: (json['exchangeRate'] as num?)?.toDouble() ?? 1.0,
  371. baseAmount: (json['baseAmount'] as num?)?.toDouble() ?? 0.0,
  372. approvedAmount: (json['approvedAmount'] as num?)?.toDouble() ?? 0.0,
  373. customerVendorId: json['cust'] as String? ?? '',
  374. customerVendorName: json['custName'] as String? ?? '',
  375. offsetAmount: (json['offsetAmount'] as num?)?.toDouble() ?? 0.0,
  376. bankName: json['bankName'] as String? ?? '',
  377. bankAccountName: json['bankAccountName'] as String? ?? '',
  378. bankAccount: json['bankAccount'] as String? ?? '',
  379. sqMan: json['sqMan'] as String? ?? '',
  380. sqManName: json['sqName'] as String? ?? json['sqManName'] as String? ?? json['sqMan'] as String? ?? '',
  381. aeNo: json['aeNo'] as String? ?? '',
  382. aeDd: json['aeDd'] as String? ?? '',
  383. remark: json['rem'] as String? ?? '',
  384. preItm: json['preItm'] as int?,
  385. sortOrder: json['itm'] as int? ?? 1,
  386. attachments:
  387. (json['attachments'] as List<dynamic>?)
  388. ?.map((e) => e as String)
  389. .toList() ??
  390. [],
  391. createTime: json['createTime'] != null
  392. ? DateTime.parse(json['createTime'] as String)
  393. : DateTime.now(),
  394. updateTime: json['updateTime'] != null
  395. ? DateTime.parse(json['updateTime'] as String)
  396. : DateTime.now(),
  397. isDeleted: json['isDeleted'] as bool? ?? false,
  398. );
  399. }
  400. Map<String, dynamic> toJson() => {
  401. 'id': id,
  402. 'expenseId': expenseId,
  403. 'expenseApplyId': expenseApplyId,
  404. 'expenseApplyNo': expenseApplyNo,
  405. 'expenseApplyDate': expenseApplyDate?.toIso8601String(),
  406. 'expenseCategory': expenseCategory,
  407. 'categoryName': categoryName,
  408. 'priority': priority,
  409. 'purpose': purpose,
  410. 'projectId': projectId,
  411. 'projectName': projectName,
  412. 'costDeptId': costDeptId,
  413. 'costDeptName': costDeptName,
  414. 'acctSubjectId': acctSubjectId,
  415. 'acctSubjectName': acctSubjectName,
  416. 'amount': amount,
  417. 'taxRate': taxRate,
  418. 'taxAmount': taxAmount,
  419. 'totalAmount': totalAmount,
  420. 'currencyCode': currencyCode,
  421. 'exchangeRate': exchangeRate,
  422. 'baseAmount': baseAmount,
  423. 'approvedAmount': approvedAmount,
  424. 'customerVendorId': customerVendorId,
  425. 'customerVendorName': customerVendorName,
  426. 'offsetAmount': offsetAmount,
  427. 'bankName': bankName,
  428. 'bankAccountName': bankAccountName,
  429. 'bankAccount': bankAccount,
  430. 'sqMan': sqMan,
  431. 'sqManName': sqManName,
  432. 'aeNo': aeNo,
  433. 'aeDd': aeDd,
  434. 'remark': remark,
  435. 'preItm': preItm,
  436. 'sortOrder': sortOrder,
  437. 'attachments': attachments,
  438. 'createTime': createTime.toIso8601String(),
  439. 'updateTime': updateTime.toIso8601String(),
  440. 'isDeleted': isDeleted,
  441. };
  442. ExpenseDetailModel copyWith({
  443. String? id,
  444. String? expenseId,
  445. String? expenseApplyId,
  446. String? expenseApplyNo,
  447. DateTime? expenseApplyDate,
  448. String? expenseCategory,
  449. String? categoryName,
  450. String? priority,
  451. String? purpose,
  452. String? projectId,
  453. String? projectName,
  454. String? costDeptId,
  455. String? costDeptName,
  456. String? acctSubjectId,
  457. String? acctSubjectName,
  458. double? amount,
  459. double? taxRate,
  460. double? taxAmount,
  461. double? totalAmount,
  462. String? currencyCode,
  463. double? exchangeRate,
  464. double? baseAmount,
  465. double? approvedAmount,
  466. String? customerVendorId,
  467. String? customerVendorName,
  468. double? offsetAmount,
  469. String? bankName,
  470. String? bankAccountName,
  471. String? bankAccount,
  472. String? sqMan,
  473. String? sqManName,
  474. String? aeNo,
  475. String? aeDd,
  476. String? remark,
  477. int? preItm,
  478. int? sortOrder,
  479. List<String>? attachments,
  480. DateTime? createTime,
  481. DateTime? updateTime,
  482. bool? isDeleted,
  483. }) {
  484. return ExpenseDetailModel(
  485. id: id ?? this.id,
  486. expenseId: expenseId ?? this.expenseId,
  487. expenseApplyId: expenseApplyId ?? this.expenseApplyId,
  488. expenseApplyNo: expenseApplyNo ?? this.expenseApplyNo,
  489. expenseApplyDate: expenseApplyDate ?? this.expenseApplyDate,
  490. expenseCategory: expenseCategory ?? this.expenseCategory,
  491. categoryName: categoryName ?? this.categoryName,
  492. priority: priority ?? this.priority,
  493. purpose: purpose ?? this.purpose,
  494. projectId: projectId ?? this.projectId,
  495. projectName: projectName ?? this.projectName,
  496. costDeptId: costDeptId ?? this.costDeptId,
  497. costDeptName: costDeptName ?? this.costDeptName,
  498. acctSubjectId: acctSubjectId ?? this.acctSubjectId,
  499. acctSubjectName: acctSubjectName ?? this.acctSubjectName,
  500. amount: amount ?? this.amount,
  501. taxRate: taxRate ?? this.taxRate,
  502. taxAmount: taxAmount ?? this.taxAmount,
  503. totalAmount: totalAmount ?? this.totalAmount,
  504. currencyCode: currencyCode ?? this.currencyCode,
  505. exchangeRate: exchangeRate ?? this.exchangeRate,
  506. baseAmount: baseAmount ?? this.baseAmount,
  507. approvedAmount: approvedAmount ?? this.approvedAmount,
  508. customerVendorId: customerVendorId ?? this.customerVendorId,
  509. customerVendorName: customerVendorName ?? this.customerVendorName,
  510. offsetAmount: offsetAmount ?? this.offsetAmount,
  511. bankName: bankName ?? this.bankName,
  512. bankAccountName: bankAccountName ?? this.bankAccountName,
  513. bankAccount: bankAccount ?? this.bankAccount,
  514. sqMan: sqMan ?? this.sqMan,
  515. sqManName: sqManName ?? this.sqManName,
  516. aeNo: aeNo ?? this.aeNo,
  517. aeDd: aeDd ?? this.aeDd,
  518. remark: remark ?? this.remark,
  519. preItm: preItm ?? this.preItm,
  520. sortOrder: sortOrder ?? this.sortOrder,
  521. attachments: attachments ?? this.attachments,
  522. createTime: createTime ?? this.createTime,
  523. updateTime: updateTime ?? this.updateTime,
  524. isDeleted: isDeleted ?? this.isDeleted,
  525. );
  526. }
  527. }