import 'dart:async'; import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart' as Path; import 'package:fcs/model/constants.dart'; import 'package:fcs/pages/po/po_files.dart'; import 'package:fcs/vo/do.dart'; import 'package:fcs/vo/po.dart'; import 'package:fcs/vo/popup_menu.dart'; import 'base_model.dart'; import 'firebase_helper.dart'; class POSubmissionModel extends BaseModel { final log = Logger('POSubmissionModel'); StreamSubscription listener; List pos = []; List approvedPOs = []; PopupMenu popupMenu = new PopupMenu(index: 0); int dateIndex = 0; DateTime selectedDate = DateTime.now(); void initUser(user) async { super.initUser(user); _loadPOs(); _loadApprovedPOs(); } @override logout() async { if (listener != null) await listener.cancel(); pos = []; approvedPOs = []; } Future _loadPOs() async { String path; if (user.hasPO() || user.isOwnerAndAbove()) { path = "/$biz_collection/${setting.okEnergyId}/$pos_collection"; } if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection"; } var startDate = new DateTime( selectedDate.year, selectedDate.month, selectedDate.day, 0, 0, 0); var endDate = new DateTime( selectedDate.year, selectedDate.month, selectedDate.day, 23, 59, 59); listener = getFilterDateSnapshot(path, 'po_date', startDate, endDate, 'po_number') .listen((snaps) async { pos.clear(); snaps.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); notifyListeners(); }); } Future _loadApprovedPOs() async { if (!user.isBuyer()) { return; } approvedPOs.clear(); String path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection"; var docs = await Firestore.instance .collection(path) .where("status", isEqualTo: po_approved_status) .orderBy("po_approved_date", descending: false) .limit(1) .getDocuments(); Firestore.instance .collection(path) .where("status", isEqualTo: po_approved_status) .orderBy("po_approved_date", descending: false) .limit(10) .snapshots(includeMetadataChanges: true) .listen((snaps) async { List _approved = []; for (var d in snaps.documents) { if (d.metadata.isFromCache) continue; var po = POSubmission.fromMap(d.data, d.documentID); po.poLines = await loadPOLines(po.id); _approved.add(po); } approvedPOs.clear(); approvedPOs.addAll(_approved); notifyListeners(); }); } Future getPO(String id) async { String path = "/$biz_collection/${setting.okEnergyId}/$pos_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection"; } var poSnap = await getDocSnap(path, id); return POSubmission.fromMap(poSnap.data, poSnap.documentID); } Future> loadPOLines(String poID) async { String path = "/$biz_collection/${setting.okEnergyId}/$pos_collection/$poID/$po_product_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection/$poID/$product_collection"; } var snaps = await Firestore.instance.collection(path).getDocuments(); List poLines = snaps.documents.map((s) => POLine.fromMap(s.data)).toList(); return poLines; } Future loadDOs(POSubmission po) async { String path = "/$biz_collection/${setting.okEnergyId}/$dos_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$dos_collection"; } var snaps = await Firestore.instance .collection(path) .where("po_number", isEqualTo: po.poNumber) .orderBy('do_number', descending: true) .getDocuments(); po.dos = snaps.documents .map((s) => DOSubmission.fromMap(s.data, s.documentID)) .toList(); return po; } Future loadDOLines(DOSubmission doSub) async { String path = "/$biz_collection/${setting.okEnergyId}/$dos_collection/${doSub.id}/$product_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$dos_collection/${doSub.id}/$product_collection"; } var snaps = await getSnapshot(path); doSub.doLines = snaps.documents.map((s) => DOLine.fromMap(s.data)).toList(); return doSub; } Future createPO(POSubmission po, List files) async { if (files != null) { if (files.length > 5) throw Exception("Exceed number of file upload"); po.poReceiptUrls = []; for (File f in files) { String path = Path.join(po_files_path, user.docID); String url = await uploadStorage(path, f); po.poReceiptUrls.add(url); } } await request("/po", "POST", payload: po.toMap(), token: await getToken()); } Future updatePO( POSubmission po, List files, List deletedUrls) async { if (deletedUrls != null) for (String url in deletedUrls) { po.poReceiptUrls.remove(url); await deleteStorageFromUrl(url); } if (files != null) { if (files.length + po.poReceiptUrls.length > 5) throw Exception("Exceed number of file upload"); po.poReceiptUrls = po.poReceiptUrls == null ? [] : po.poReceiptUrls; for (File f in files) { String path = Path.join(po_files_path, user.docID); String url = await uploadStorage(path, f); po.poReceiptUrls.add(url); } } await request("/po", "PUT", payload: po.toMap(), token: await getToken()); } Future approvePO(POSubmission po) async { await request("/po/approved", "POST", payload: po.toMap(), token: await getToken()); } Future rejectPO(POSubmission po) async { await request("/po/rejected", "POST", payload: po.toMap(), token: await getToken()); } Future cancelPO(POSubmission po) async { await request("/po/canceled", "POST", payload: po.toMap(), token: await getToken()); } void filterData( String status, DateTime dateTime, int _selectedStatus, int _dateIndex) { pos.clear(); var startDate = new DateTime(dateTime.year, dateTime.month, dateTime.day, 0, 0, 0); var endDate = new DateTime(dateTime.year, dateTime.month, dateTime.day, 23, 59, 59); if (this.listener != null) { this.listener.cancel(); } this.popupMenu.index = _selectedStatus; this.dateIndex = _dateIndex; this.selectedDate = dateTime == null ? new DateTime( selectedDate.year, selectedDate.month, selectedDate.day, 0, 0, 0) : dateTime; String path = "/$biz_collection/${setting.okEnergyId}/$pos_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection"; } if (status != null && dateTime == null) { this.listener = getFilterStatusSnapshot(path, status, 'po_number') .listen((snaps) async { pos.clear(); snaps.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); notifyListeners(); }); } else if (dateTime != null && status == null) { this.listener = getFilterDateSnapshot( path, 'po_date', startDate, endDate, 'po_number') .listen((snaps) async { pos.clear(); snaps.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); notifyListeners(); }); } else if (status != null && dateTime != null) { this.listener = getFilterDataSnapshot( path, status, 'po_date', startDate, endDate, 'po_number') .listen((snaps) { pos.clear(); snaps.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); notifyListeners(); }); } else { this.listener = getQuerySnapshotByOrder(path, 'po_number').listen((snaps) async { pos.clear(); snaps.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); notifyListeners(); }); } } Future> getPOForRevenue(DateTime dateTime) async { List pos = []; String path = "/$biz_collection/${setting.okEnergyId}/$pos_collection"; if (user.isBuyer()) { path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$pos_collection"; } DateTime date = DateTime(dateTime.year, dateTime.month, dateTime.day); DateTime dateAddOne = date.add(Duration(days: 1)); QuerySnapshot snapshots = await Firestore.instance .collection(path) .where('status', whereIn: [po_approved_status, po_closed_status]) .where("po_approved_date", isGreaterThanOrEqualTo: date) .where("po_approved_date", isLessThan: dateAddOne) .orderBy("po_approved_date") .orderBy("user_name") .limit(100) .getDocuments(); snapshots.documents.forEach((d) { pos.add(POSubmission.fromMap(d.data, d.documentID)); }); return pos; } }