import 'dart:async'; import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/data/services/services.dart'; import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/payment.dart'; import 'package:fcs/helpers/firebase_helper.dart'; import 'package:fcs/helpers/paginator.dart'; import 'package:fcs/pages/main/model/base_model.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart' as Path; class InvoiceModel extends BaseModel { final log = Logger('InvoiceModel'); StreamSubscription>>? listener; List _invoices = []; List get invoices => _selectedIndex == 1 ? _invoices : List.from(_paginator.values); late Paginator _paginator; bool endOfPaidInvoices = false; bool isLoading = false; int _selectedIndex = 1; set selectedIndex(int index) { _selectedIndex = index; notifyListeners(); } int get selectedIndex => _selectedIndex; @override void privilegeChanged() { super.privilegeChanged(); } initData(bool forCustomer, bool isCanceled, bool isPaid) { _loadInvoices(forCustomer); if (_paginator != null) _paginator.close(); _paginator = _getPaginator(forCustomer, isCanceled, isPaid); _paginator.load(onFinished: () { notifyListeners(); }); } Future _loadInvoices(bool forCustomer) async { if (user == null) return; if (!forCustomer && !user.hasInvoices()) return; String path = "/$invoices_collection"; if (listener != null) listener!.cancel(); _invoices = []; try { var q = FirebaseFirestore.instance .collection("$path") .where("status", isEqualTo: invoice_issued_status) .where("is_deleted", isEqualTo: false); if (forCustomer) { q = q.where("user_id", isEqualTo: user.id); } listener = q.snapshots().listen((QuerySnapshot snapshot) { _invoices.clear(); _invoices = snapshot.docs.map((documentSnapshot) { var s = Invoice.fromMap(documentSnapshot.data as Map, documentSnapshot.id); return s; }).toList(); notifyListeners(); }); } catch (e) { log.warning("Error!! $e"); } } Paginator _getPaginator(bool isCustomer, bool isCanceled, bool isPaid) { if (!isCustomer) { if (user == null || !(user.hasInvoices())) throw "No privilege"; } var pageQuery = FirebaseFirestore.instance .collection("/$invoices_collection") .where("is_deleted", isEqualTo: false); if (isCustomer) { pageQuery = pageQuery.where("user_id", isEqualTo: user.id); } if (isCanceled) { pageQuery = pageQuery.where("status", isEqualTo: invoice_cancel_status); } if (isPaid) { pageQuery = pageQuery.where("status", isEqualTo: invoice_paid_status); } pageQuery = pageQuery.orderBy("created_at", descending: true); var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { return Invoice.fromMap(data, id); }); return paginator; } Future loadMore({bool? isCustomer}) async { if (_paginator.ended || _selectedIndex == 1) return; // when paid menu is not selected return isLoading = true; notifyListeners(); await _paginator.load(onFinished: () { isLoading = false; notifyListeners(); }); } Future refresh({bool? isCustomer}) async { if (_selectedIndex == 1) return; // when paid menu is not selected return await _paginator.refresh(onFinished: () { notifyListeners(); }); } void initUser(user) { super.initUser(user); } logout() async { if (_paginator != null) _paginator.close(); if (listener != null) await listener!.cancel(); _invoices = []; } Future getInvoice(String id) async { String path = "/$invoices_collection"; try { var ref = FirebaseFirestore.instance.collection("$path").doc(id); var snap = await ref.get(const GetOptions(source: Source.server)); if (snap.exists) { var s = Invoice.fromMap(snap.data as Map, snap.id); return s; } } catch (e) { log.warning("Error!! $e"); } return null; } Future pay(Payment payment, File file) async { String path = Path.join(receipt_labels_files_path, user.id); String url = await uploadStorage(path, file); payment.paymentReceiptURL = url; return Services.instance.invoiceService.pay(payment); } Future updatePaymentStatus(Payment payment) async { return Services.instance.invoiceService.updatPaymentStatus(payment); } Future createInvoice(Invoice invoice) async { return Services.instance.invoiceService.createInvoice(invoice); } Future updateInvoice(Invoice invoice) { return Services.instance.invoiceService.updateInvoice(invoice); } Future cancelInvoice(Invoice invoice) { return Services.instance.invoiceService.cancelInvoice(invoice); } }