import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/api/api_client.dart'; import '../core/auth/auth_state.dart'; import '../core/config/app_constants.dart'; import '../core/models/page_result.dart'; import '../models/finance.dart'; import '../models/partner.dart'; import '../repositories/partner_repository.dart'; import 'connectivity_provider.dart'; import 'finance_provider.dart'; final partnerRepositoryProvider = Provider((ref) { return PartnerRepository(ref.watch(apiClientProvider)); }); // Supplier list provider for dropdowns final supplierListProvider = AsyncNotifierProvider>( () => PartnerListNotifier(type: 'supplier'), ); // Customer list provider final customerListProvider = AsyncNotifierProvider>( () => PartnerListNotifier(type: 'customer'), ); /// 工具栏/详细搜索的往来单位下拉专用:不分 supplier/customer、一次取全部。 /// 说明:历史 partner 的 type 多为默认 'supplier'(customer 常为空), /// 按 type 过滤会漏项甚至空列表;下拉按「全部往来单位」呈现最稳。 final allPartnersProvider = AsyncNotifierProvider>( () => PartnerListNotifier(type: null, pageSize: 1000), ); /// 往来单位屏专用:单表 + 类型 chips(原型无分页控件,一页取全)。 final partnersScreenProvider = AsyncNotifierProvider>( () => PartnerListNotifier(type: null, pageSize: 1000), ); /// 应收/应付余额(原型 recv/pay 两列):/finance/summary 按 partner 聚合的未结清额。 /// 返回 partner_id → (recv 应收, pay 应付)。 final partnerBalancesProvider = FutureProvider>((ref) async { ref.watch(authStateProvider.select((s) => s.user?.shopId)); final rows = await ref.read(financeRepositoryProvider).partnerSummary(); final map = {}; for (final r in rows) { final id = r.partnerId; if (id == null) continue; final cur = map[id] ?? (recv: 0.0, pay: 0.0); map[id] = r.type == 'receivable' ? (recv: cur.recv + r.totalAmount, pay: cur.pay) : (recv: cur.recv, pay: cur.pay + r.totalAmount); } return map; }); /// 详情抽屉「近期单据」:该往来单位最近的财务流水(应收/应付/收款/付款, /// 已覆盖入库、出库与收付款的单据轨迹)。 final partnerRecentDocsProvider = FutureProvider.family, int>((ref, partnerId) async { final page = await ref .read(financeRepositoryProvider) .listRecords(partnerId: partnerId, pageSize: 8); return page.data; }); class PartnerListNotifier extends AsyncNotifier> { String? type; int _page = 1; int _pageSize; String _keyword = ''; PageResult? _cache; PartnerListNotifier({this.type, int pageSize = AppConstants.defaultPageSize}) : _pageSize = pageSize; @override Future> build() async { ref.watch(authStateProvider.select((s) => s.user?.shopId)); ref.watch(networkRecoveryCountProvider); try { final result = await _fetch(); _cache = result; return result; } catch (_) { if (_cache != null) return _cache!; rethrow; } } Future> _fetch() { return ref.read(partnerRepositoryProvider).list( type: type, keyword: _keyword.isEmpty ? null : _keyword, page: _page, pageSize: _pageSize, ); } void setPage(int page) { _page = page; reload(); } void setPageSize(int pageSize) { _pageSize = pageSize; _page = 1; reload(); } void setKeyword(String keyword) { _keyword = keyword; _page = 1; reload(); } /// 类型筛选(往来单位屏 chips):null=全部 / 'supplier' / 'customer'。 /// 后端 FIND_IN_SET 语义:选「供应商」自动含「两者」,与原型一致。 void setType(String? t) { if (t == type) return; type = t; _page = 1; reload(); } void reload() { state = const AsyncValue.loading(); _fetch().then((result) { _cache = result; state = AsyncValue.data(result); }, onError: (e, st) { if (_cache != null) { state = AsyncValue.data(_cache!); } else { state = AsyncValue.error(e, st); } }); } Future createPartner(Map data) async { await ref.read(partnerRepositoryProvider).create(data); reload(); } Future updatePartner(int id, Map data) async { await ref.read(partnerRepositoryProvider).update(id, data); reload(); } Future deletePartner(int id) async { await ref.read(partnerRepositoryProvider).delete(id); reload(); } }