| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import '../../core/storage/draft_storage.dart';
- import 'expense_model.dart';
- import 'expense_api.dart';
- const expenseDraftKey = 'expense';
- class ExpenseCreateState {
- final ExpenseModel expense;
- final bool isSubmitting;
- const ExpenseCreateState({required this.expense, this.isSubmitting = false});
- ExpenseCreateState copyWith({ExpenseModel? expense, bool? isSubmitting}) {
- return ExpenseCreateState(
- expense: expense ?? this.expense,
- isSubmitting: isSubmitting ?? this.isSubmitting,
- );
- }
- }
- class ExpenseCreateController extends StateNotifier<ExpenseCreateState> {
- final ExpenseApi _api;
- ExpenseCreateController(this._api, {ExpenseModel? initial})
- : super(
- ExpenseCreateState(
- expense:
- initial ??
- ExpenseModel(
- id: '',
- expenseNo: '',
- createTime: DateTime.now(),
- updateTime: DateTime.now(),
- ),
- ),
- );
- void updateCurrencyCode(String code, double excRto) {
- state = state.copyWith(
- expense: state.expense.copyWith(currencyCode: code, excRto: excRto),
- );
- }
- void updateApprovedAmount(double amount) {
- state = state.copyWith(
- expense: state.expense.copyWith(approvedAmount: amount),
- );
- }
- void updateDetailApprovedAmount(int index, double amount) {
- final details = [...state.expense.details];
- details[index] = details[index].copyWith(approvedAmount: amount);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void updateDetailCustomerVendor(int index, String name) {
- final details = [...state.expense.details];
- details[index] = details[index].copyWith(customerVendorName: name);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void updateDetailProjectId(int index, String id) {
- final details = [...state.expense.details];
- details[index] = details[index].copyWith(projectId: id);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void updateDetailAcctSubjectId(int index, String id) {
- final details = [...state.expense.details];
- details[index] = details[index].copyWith(acctSubjectId: id);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void updateDetailOffsetAmount(int index, double amount) {
- final details = [...state.expense.details];
- details[index] = details[index].copyWith(offsetAmount: amount);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void restoreFromDraft(ExpenseModel draft, ExpenseApi api) {
- state = ExpenseCreateState(
- expense: draft.copyWith(
- deptId: '',
- deptName: '',
- applicantId: '',
- applicantName: '',
- ),
- );
- }
- void reset() {
- state = ExpenseCreateState(
- expense: ExpenseModel(
- id: '',
- expenseNo: '',
- createTime: DateTime.now(),
- updateTime: DateTime.now(),
- ),
- );
- }
- void updatePurpose(String purpose) {
- state = state.copyWith(expense: state.expense.copyWith(purpose: purpose));
- }
- ExpenseCreateState get currentState => state;
- void updateAttachments(List<String> paths) {
- state = state.copyWith(expense: state.expense.copyWith(attachments: paths));
- }
- void updatePaymentMethod(String method) {
- state = state.copyWith(
- expense: state.expense.copyWith(paymentMethod: method),
- );
- }
- void updateRemark(String remark) {
- state = state.copyWith(expense: state.expense.copyWith(remark: remark));
- }
- void setGenerateVoucher(bool value) {
- state = state.copyWith(
- expense: state.expense.copyWith(isGenerateVoucher: value),
- );
- }
- void updateDept(String deptId, String deptName) {
- state = state.copyWith(
- expense: state.expense.copyWith(deptId: deptId, deptName: deptName),
- );
- }
- void updateEmployee(String applicantId, String applicantName) {
- state = state.copyWith(
- expense: state.expense.copyWith(
- applicantId: applicantId,
- applicantName: applicantName,
- ),
- );
- }
- void addDetail(ExpenseDetailModel detail) {
- final details = [...state.expense.details, detail];
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void removeDetail(int index) {
- final details = [...state.expense.details]..removeAt(index);
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void removeDetailsByAeNo(String aeNo) {
- final details = state.expense.details.where((d) => d.aeNo != aeNo).toList();
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void updateDetail(int index, ExpenseDetailModel detail) {
- final details = [...state.expense.details];
- details[index] = detail;
- state = state.copyWith(expense: state.expense.copyWith(details: details));
- }
- void recalculateAmount() {
- var totalAmount = 0.0;
- var approvedAmount = 0.0;
- for (final d in state.expense.details) {
- totalAmount += d.totalAmount;
- approvedAmount += d.approvedAmount;
- }
- state = state.copyWith(
- expense: state.expense.copyWith(
- totalAmount: totalAmount,
- approvedAmount: approvedAmount,
- ),
- );
- }
- Future<bool> submit() async {
- state = state.copyWith(isSubmitting: true);
- try {
- final expense = state.expense.copyWith(status: 'pending');
- // 手动拼 Map(提交流程专用,保持 camelCase key,与 BillSave 接口一致)
- final data = <String, dynamic>{
- 'id': expense.id,
- 'expenseNo': expense.expenseNo,
- 'expenseDate': expense.expenseDate?.toIso8601String(),
- 'applicantId': expense.applicantId,
- 'applicantName': expense.applicantName,
- 'deptId': expense.deptId,
- 'deptName': expense.deptName,
- 'currencyCode': expense.currencyCode,
- 'excRto': expense.excRto,
- 'isGenerateVoucher': expense.isGenerateVoucher,
- 'voucherNo': expense.voucherNo,
- 'approvedAmount': expense.approvedAmount,
- 'totalAmount': expense.totalAmount,
- 'totalAmtnSh': expense.totalAmtnSh,
- 'purpose': expense.purpose,
- 'remark': expense.remark,
- 'paymentMethod': expense.paymentMethod,
- 'status': expense.status,
- 'approvalInstanceId': expense.approvalInstanceId,
- 'previousInstanceIds': expense.previousInstanceIds,
- 'effectiveDate': expense.effectiveDate?.toIso8601String(),
- 'auditorId': expense.auditorId,
- 'version': expense.version,
- 'createTime': expense.createTime.toIso8601String(),
- 'updateTime': expense.updateTime.toIso8601String(),
- 'details': expense.details.map((d) => d.toJson()).toList(),
- 'attachments': expense.attachments,
- };
- await _api.submit(data);
- await DraftStorage.delete(expenseDraftKey);
- return true;
- } catch (_) {
- return false;
- } finally {
- state = state.copyWith(isSubmitting: false);
- }
- }
- Future<bool> saveDraft() async {
- state = state.copyWith(isSubmitting: true);
- try {
- final data = state.expense.toJson();
- data.remove('dept');
- data.remove('deptName');
- data.remove('usrNo');
- data.remove('applicantName');
- await DraftStorage.save(expenseDraftKey, data);
- return true;
- } catch (_) {
- return false;
- } finally {
- state = state.copyWith(isSubmitting: false);
- }
- }
- static Future<ExpenseModel?> loadDraft() async {
- final data = await DraftStorage.load(expenseDraftKey);
- if (data == null) return null;
- try {
- return ExpenseModel.fromJson(data);
- } catch (_) {
- return null;
- }
- }
- static Future<bool> hasDraft() => DraftStorage.has(expenseDraftKey);
- static Future<void> deleteDraft() => DraftStorage.delete(expenseDraftKey);
- }
- final expenseCreateProvider = StateNotifierProvider.autoDispose
- .family<ExpenseCreateController, ExpenseCreateState, String?>((
- ref,
- editId,
- ) {
- final api = ref.watch(expenseApiProvider);
- return ExpenseCreateController(api);
- });
|