Files
fcs/lib/pages/package/model/package_model.dart
2024-09-22 16:49:59 +06:30

378 lines
11 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/constants.dart';
import 'package:fcs/domain/entities/package.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/domain/vo/delivery_address.dart';
import 'package:fcs/helpers/firebase_helper.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:fcs/pagination/paginator_listener.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as Path;
class PackageModel extends BaseModel {
final log = Logger('PackageModel');
PaginatorListener<Package>? packages;
PaginatorListener<Package>? customerPackages;
PaginatorListener<Package>? activePackages;
bool isLoading = false;
int selectedIndex = 1;
initData(int index, bool isCustomer) {
selectedIndex = index;
if (isCustomer) {
_loadPaginationCustomerPackages(selectedIndex == 2);
} else {
_loadPaginationPackages(selectedIndex == 2);
}
}
void privilegeChanged() {
if (user != null) {
_loadPaginationActivePackages();
}
}
@override
logout() async {
if (customerPackages != null) customerPackages!.close();
if (packages != null) packages!.close();
if (activePackages != null) activePackages!.close();
}
onChanged(int index, bool isCustomer) {
selectedIndex = index;
if (isCustomer) {
_loadPaginationCustomerPackages(selectedIndex == 2);
} else {
_loadPaginationPackages(selectedIndex == 2);
}
notifyListeners();
}
_loadPaginationPackages(bool isDelivered) {
if (user == null) return;
if (!((user!.hasPackages() ||
user!.hasReceiving() ||
user!.hasProcessing()))) return;
String path = "/$packages_collection";
Query col = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: isDelivered);
Query pageQuery = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: isDelivered)
.orderBy("update_time", descending: true);
packages?.close();
packages = PaginatorListener<Package>(
col, pageQuery, (data, id) => Package.fromMap(data, id),
rowPerLoad: 30);
}
_loadPaginationCustomerPackages(bool isDelivered) {
if (user == null) return;
String path = "/$packages_collection";
Query col = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: isDelivered)
.where("user_id", isEqualTo: user!.id);
Query pageQuery = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: isDelivered)
.where("user_id", isEqualTo: user!.id)
.orderBy("update_time", descending: true);
customerPackages?.close();
customerPackages = PaginatorListener<Package>(
col, pageQuery, (data, id) => Package.fromMap(data, id),
rowPerLoad: 30);
}
_loadPaginationActivePackages() {
if (user == null) return;
if (!((user!.hasPackages() ||
user!.hasReceiving() ||
user!.hasProcessing()))) return;
String path = "/$packages_collection";
Query col = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: false);
Query pageQuery = FirebaseFirestore.instance
.collection(path)
.where("is_delivered", isEqualTo: false)
.orderBy("update_time", descending: true);
activePackages?.close();
activePackages = PaginatorListener<Package>(
col, pageQuery, (data, id) => Package.fromMap(data, id),
rowPerLoad: 30);
}
Future<Package?> getPackage(String id) async {
if (user == null) return null;
String path = "/$packages_collection";
try {
DocumentSnapshot snap =
await FirebaseFirestore.instance.collection("$path").doc(id).get();
if (snap.exists) {
var package =
Package.fromMap(snap.data() as Map<String, dynamic>, snap.id);
return package;
}
} catch (e) {
log.warning("Error!! $e");
}
return null;
}
Future<Package?> getPackageByTrackingID(String trackingID) async {
if (user == null) return null;
String path = "/$packages_collection";
try {
var snaps = await FirebaseFirestore.instance
.collection("$path")
.where("tracking_id", isEqualTo: trackingID)
.where("is_deleted", isEqualTo: false)
.get(const GetOptions(source: Source.server));
if (snaps.docs.length == 1) {
var snap = snaps.docs[0];
var package = Package.fromMap(snap.data(), snap.id);
return package;
}
} catch (e) {
log.warning("Error!! $e");
}
return null;
}
Future<Package?> lookupPackage(String trackingID) async {
if (user == null) return null;
String path = "/$packages_collection";
try {
var qsnap = await FirebaseFirestore.instance
.collection("$path")
.where("tracking_id", isEqualTo: trackingID)
.where("has_user_id", isEqualTo: false)
.where("is_deleted", isEqualTo: false)
.get(const GetOptions(source: Source.server));
if (qsnap.docs.length > 0) {
var snap = qsnap.docs[0];
if (snap.exists) {
var package =
Package.fromMap(snap.data as Map<String, dynamic>, snap.id);
return package;
}
}
qsnap = await FirebaseFirestore.instance
.collection("$path")
.where("tracking_id", isEqualTo: trackingID)
.where("user_id", isEqualTo: user!.id)
.where("is_deleted", isEqualTo: false)
.get(const GetOptions(source: Source.server));
if (qsnap.docs.length > 0) {
var snap = qsnap.docs[0];
if (snap.exists) {
var package =
Package.fromMap(snap.data as Map<String, dynamic>, snap.id);
return package;
}
}
} catch (e) {
log.warning("Error!! $e");
}
return null;
}
Future<List<Package>> getPackages(String userID, List<String> status) async {
List<Package> packages = [];
try {
var snaps = await FirebaseFirestore.instance
.collection("/$packages_collection")
.where("status", whereIn: status)
.where("user_id", isEqualTo: userID)
.where("is_deleted", isEqualTo: false)
.get(const GetOptions(source: Source.server));
packages = snaps.docs.map((documentSnapshot) {
var p = Package.fromMap(documentSnapshot.data(), documentSnapshot.id);
return p;
}).toList();
} catch (e) {
log.warning("Error!! $e");
}
return packages;
}
Future<List<User>> searchUser(String term) {
return Services.instance.userService.searchUser(term);
}
Future<List<Package>> searchPackage(String term) async {
Future<List<Package>> packages =
Services.instance.packageService.searchPackage(term);
Future<List<Package>?> packagesFTS =
Services.instance.packageService.ftsSearchPackage(term);
// Package pkg = await getPackageByTrackingID(term);
// if (pkg != null && !packages.contains(pkg)) {
// packages.insert(0, pkg);
// }
List<Package> pkgs = await packages;
List<Package>? ftsPkgs = await packagesFTS;
pkgs.addAll(ftsPkgs!);
final seen = Set<Package>();
return pkgs.where((e) => seen.add(e)).toList();
}
Future<void> createPackages(User user, List<Package> packages) {
return Services.instance.packageService
.createPackages(packages, user.fcsID!);
}
Future<void> createReceiving(
User? user, Package package, List<File?>? files) async {
if (user != null) {
package.fcsID = user.fcsID;
}
if (files != null) {
if (files.length > uploadPhotoLimit) {
throw Exception("Exceed number of file upload");
}
package.photoUrls = package.photoUrls;
String path = Path.join(pkg_files_path);
List<String> urls = await uploadFiles(path, files);
package.photoUrls = urls;
}
try {
return Services.instance.packageService.createReceiving(package);
} catch (e) {
try {
// delete uploaded photos if create fails
deleteStorageFromUrls(package.photoUrls);
} catch (e) {}
throw e;
}
}
Future<void> updateReceiving(User? user, Package package, List<File?> files,
List<String?> deletedUrls) async {
if (user != null) {
package.fcsID = user.fcsID;
}
if (deletedUrls.isNotEmpty) {
for (String? url in deletedUrls) {
package.photoUrls.remove(url);
}
}
List<String> uploadedURL = [];
if (files.isNotEmpty) {
var count =
(package.photoUrls.length) + files.length - (deletedUrls.length);
if (count > uploadPhotoLimit)
throw Exception("Exceed number of file upload");
package.photoUrls = package.photoUrls;
String path = Path.join(pkg_files_path);
uploadedURL = await uploadFiles(path, files);
uploadedURL.forEach((url) {
package.photoUrls.add(url);
});
}
try {
await Services.instance.packageService.updateReceiving(package);
} catch (e) {
// delete newly uploaded photos if fails
try {
deleteStorageFromUrls(uploadedURL);
package.photoUrls.removeWhere((i) => uploadedURL.contains(i));
} catch (e) {}
throw e;
}
return deleteStorageFromUrls(deletedUrls);
}
Future<void> deleteReceiving(Package package) {
return Services.instance.packageService.deleteReceiving(package);
}
Future<void> updateProcessing(
Package package, List<File?> files, List<String?> deletedUrls) async {
if (deletedUrls.isNotEmpty) {
for (String? url in deletedUrls) {
package.photoUrls.remove(url);
}
}
List<String> uploadedURL = [];
if (files.isNotEmpty) {
var count =
(package.photoUrls.length) + files.length - (deletedUrls.length);
if (count > uploadPhotoLimit)
throw Exception("Exceed number of file upload");
package.photoUrls = package.photoUrls;
String path = Path.join(pkg_files_path);
uploadedURL = await uploadFiles(path, files);
uploadedURL.forEach((url) {
package.photoUrls.add(url);
});
package.photoUrls.removeWhere((e) => deletedUrls.contains(e));
}
try {
await Services.instance.packageService.updateProcessing(package);
} catch (e) {
// delete newly uploaded photos if fails
try {
deleteStorageFromUrls(uploadedURL);
package.photoUrls.removeWhere((i) => uploadedURL.contains(i));
} catch (e) {}
throw e;
}
return deleteStorageFromUrls(deletedUrls);
}
Future<void> deleteProcessing(Package package) {
return Services.instance.packageService.deleteProcessing(package);
}
Future<void> changeDeliveryAddress(
Package package, DeliveryAddress deliveryAddress) {
return Services.instance.packageService
.changeDeliveryAddress(package.id!, deliveryAddress.id!);
}
Future<void> packageReturn(Package package) {
return Services.instance.packageService.packageReturn(package.id!);
}
Future<List<Package>> getPackagesByIds(List<String> packageIds) async {
List<Package> packages = [];
try {
for (var e in packageIds) {
Package? p = await getPackage(e);
if (p != null) {
packages.add(p);
}
}
} catch (e) {
log.warning("Error!! $e");
}
return packages;
}
}