Merge branch 'master' of tzw/fcs into master

This commit is contained in:
2024-03-04 14:06:10 +06:30
committed by Gogs
24 changed files with 471 additions and 186 deletions

View File

@@ -403,14 +403,14 @@
"FCSshipment.process.btn":"Process this shipment",
"FCSshipment.arrive.btn":"Arrive this shipment",
"FCSshipment.invoiced.btn":"Invoice this shipment",
"FCSshipment.ship.confirm":"Confirm ship?",
"FCSshipment.ship.confirm":"Ship this shipment?",
"FCSshipment.cancel.btn":"Cancel this shipment",
"FCSshipment.cancel.confirm":"Cancel this shipment?",
"FCSshipment.carton":"Cartons",
"FCSshipment.package":"Packages",
"FCSshipment.process.confirm":"Confirm process?",
"FCSshipment.arrive.confirm":"Confirm arrive?",
"FCSshipment.invoice.confirm":"Confirm invoice?",
"FCSshipment.process.confirm":"Process this shipment?",
"FCSshipment.arrive.confirm":"Arrive this shipment?",
"FCSshipment.invoice.confirm":"Invoice this shipment?",
"FCS Shipment End ================================================================":"",
"Shipment Start ================================================================":"",

View File

@@ -403,7 +403,7 @@
"FCSshipment.process.btn":"လုပ်ဆောင်နေသည်",
"FCSshipment.arrive.btn":"ရောက်ရှိသည်",
"FCSshipment.invoiced.btn":"ပြေစာယူသည်",
"FCSshipment.ship.confirm":"Confirm ship?",
"FCSshipment.ship.confirm":"Ship this shipment?",
"FCSshipment.cancel.btn":"Cancel this shipment",
"FCSshipment.cancel.confirm":"Cancel this shipment?",
"FCSshipment.popupmenu.all":"All shipments",
@@ -413,7 +413,7 @@
"FCSshipment.package":"FCS အထုပ်",
"FCSshipment.process.confirm":"လုပ်ငန်းစဉ်ကို အတည်ပြုပါ ?",
"FCSshipment.arrive.confirm":"ရောက်ရှိကြောင်း အတည်ပြုပါ ?",
"FCSshipment.invoice.confirm":"ပြေစာအတည်ပြုပါ ?",
"FCSshipment.invoice.confirm":"Invoice this shipment ?",
"FCS Shipment End ================================================================":"",
"Shipment Start ================================================================":"",

View File

@@ -33,6 +33,7 @@ import 'pages/carton/model/carton_selection_model.dart';
import 'pages/carton/model/consignee_selection_model.dart';
import 'pages/carton/model/package_selection_model.dart';
import 'pages/carton/model/sender_selection_model.dart';
import 'pages/carton/model/shipment_selection_model.dart';
import 'pages/delivery/model/delivery_model.dart';
class App extends StatefulWidget {
@@ -72,6 +73,8 @@ class _AppState extends State<App> {
final ConsigneeSelectionModel consigneeSelectionModel =
new ConsigneeSelectionModel();
final SenderSelectionModel senderSelectionModel = new SenderSelectionModel();
final ShipmentSelectionModel shipmentSelectionModel =
new ShipmentSelectionModel();
late AppTranslationsDelegate _newLocaleDelegate;
@@ -98,7 +101,8 @@ class _AppState extends State<App> {
..addModel(cartonSelectionModel)
..addModel(packageSelectionModel)
..addModel(consigneeSelectionModel)
..addModel(senderSelectionModel);
..addModel(senderSelectionModel)
..addModel(shipmentSelectionModel);
_newLocaleDelegate = AppTranslationsDelegate(
newLocale: Translation().supportedLocales().first);
@@ -151,6 +155,7 @@ class _AppState extends State<App> {
ChangeNotifierProvider.value(value: packageSelectionModel),
ChangeNotifierProvider.value(value: consigneeSelectionModel),
ChangeNotifierProvider.value(value: senderSelectionModel),
ChangeNotifierProvider.value(value: shipmentSelectionModel),
],
child: Consumer<LanguageModel>(
builder: (context, value, child) {

View File

@@ -28,7 +28,7 @@ class FcsShipmentDataProvider {
}
Future<void> cancelFcsShipment(String id) async {
return await requestAPI("/fcs_shipments/cancel", "PUT",
return await requestAPI("/fcs_shipments/cancel", "POST",
payload: {"id": id}, token: await getToken());
}

View File

@@ -1,4 +1,5 @@
const uploadPhotoLimit = 10;
const shipmentCountForCartonFilter = 10;
const config_collection = "configs";
const user_collection = "users";
@@ -117,6 +118,7 @@ const carton_invoiced_status = "invoiced";
const carton_canceled_status = "canceled";
const all_status = "All stauts";
const all = "All";
const see_all ="See All";
// shipment status
const shipment_pending_status = "pending";

View File

@@ -7,7 +7,7 @@ class FcsShipment {
String? shipmentNumber;
DateTime? cutoffDate;
String? shipmentTypeId;
String? shipType;
String? shipTypeName;
DateTime? arrivalDate;
DateTime? departureDate;
String? consignee;
@@ -21,7 +21,7 @@ class FcsShipment {
this.shipmentNumber,
this.cutoffDate,
this.shipmentTypeId,
this.shipType,
this.shipTypeName,
this.status,
this.arrivalDate,
this.departureDate,
@@ -42,7 +42,7 @@ class FcsShipment {
cutoffDate: _cutoffDate != null ? _cutoffDate.toDate() : null,
arrivalDate: _arrivalDate != null ? _arrivalDate.toDate() : null,
shipmentNumber: map['shipment_number'],
shipType: map['shipment_type'],
shipTypeName: map['shipment_type_name'],
shipmentTypeId: map['shipment_type_id'] ?? "",
status: map['status'],
consignee: map['consignee'],
@@ -53,10 +53,10 @@ class FcsShipment {
Map<String, dynamic> toMap() {
return {
"id": id,
'id': id,
'shipment_number': shipmentNumber,
'shipment_type_id': shipmentTypeId,
'cutoff_date': cutoffDate?.toUtc().toIso8601String(),
'shipment_type': shipType,
'arrival_date': arrivalDate?.toUtc().toIso8601String(),
'consignee': consignee,
'port': port,

View File

@@ -1,10 +1,10 @@
class ShipmentType {
String id;
String desc;
String name;
ShipmentType({required this.id, required this.desc});
ShipmentType({required this.id, required this.name});
factory ShipmentType.fromMap(Map<String, dynamic> map, String id) {
return ShipmentType(id: id, desc: map['desc'] ?? "");
return ShipmentType(id: id, name: map['name'] ?? "");
}
}

View File

@@ -11,8 +11,9 @@ import 'package:path_provider/path_provider.dart';
import '../config.dart';
import 'dev_info.dart';
import 'firebase_helper.dart';
import 'dart:developer' as log;
final log = Logger('requestAPI');
final logger = Logger('requestAPI');
// request makes http request
// if token is null
@@ -21,7 +22,7 @@ Future<dynamic> requestAPI(String path, method,
DevInfo devInfo = await DevInfo.getDevInfo();
String deviceName = "${devInfo.model}(${devInfo.id})";
log.info("device:${devInfo.deviceID},deviceName:$deviceName");
logger.info("device:${devInfo.deviceID},deviceName:$deviceName");
Map<String, dynamic> headers = {};
if (token != null) {
@@ -39,8 +40,20 @@ Future<dynamic> requestAPI(String path, method,
receiveTimeout: Duration(milliseconds: networkTimeout ?? 50000),
headers: headers,
);
log.info("baseUrl:${options.baseUrl}, path:$path");
log.info("payload:$payload");
logger.info("baseUrl:${options.baseUrl}, path:$path, method:$method");
logger.info("payload:$payload");
List<String> list = [];
headers.forEach((key, value) {
var r = '-H $key:$value ';
list.add(r);
});
String curlPath =
"curl -X $method ${list.join("")}${payload != null ? '-d $payload ' : ''}${options.baseUrl}$path";
log.log(curlPath);
try {
Dio dio = new Dio(options);
@@ -55,7 +68,7 @@ Future<dynamic> requestAPI(String path, method,
throw Exception(data.message);
}
} catch (e) {
log.warning("path:$path, api:$e");
logger.warning("path:$path, api:$e");
throw e;
}
}
@@ -67,7 +80,7 @@ Future<dynamic> requestDownloadAPI(String path, method,
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
String deviceName = "${androidInfo.model}(${androidInfo.id})";
log.info("device:${androidInfo.id},deviceName:$deviceName");
logger.info("device:${androidInfo.id},deviceName:$deviceName");
var bytes = utf8.encode(payload);
var base64Str = base64.encode(bytes);
@@ -75,7 +88,7 @@ Future<dynamic> requestDownloadAPI(String path, method,
try {
String baseUrl = url == null ? Config.instance.apiURL : url;
log.info("Path:$baseUrl$path");
logger.info("Path:$baseUrl$path");
HttpClient client = new HttpClient();
var _downloadData = StringBuffer();
var fileSave = new File(filePath!);
@@ -96,7 +109,7 @@ Future<dynamic> requestDownloadAPI(String path, method,
fileSave.writeAsString(_downloadData.toString());
});
} catch (e) {
log.warning("path:$path, api:$e");
logger.warning("path:$path, api:$e");
throw e;
}
}
@@ -108,7 +121,7 @@ Future<dynamic> requestDownloadPDFAPI(String path, method,
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
String deviceName = "${androidInfo.model}(${androidInfo.id})";
log.info("device:${androidInfo.id},deviceName:$deviceName");
logger.info("device:${androidInfo.id},deviceName:$deviceName");
var bytes = utf8.encode(payload);
var base64Str = base64.encode(bytes);
@@ -116,7 +129,7 @@ Future<dynamic> requestDownloadPDFAPI(String path, method,
try {
String baseUrl = url == null ? Config.instance.apiURL : url;
log.info("Path:$baseUrl$path");
logger.info("Path:$baseUrl$path");
HttpClient client = new HttpClient();
// var _downloadData = StringBuffer();
var fileSave = new File(filePath!);
@@ -140,7 +153,7 @@ Future<dynamic> requestDownloadPDFAPI(String path, method,
// fileSave.writeAsString(_downloadData.toString());
// });
} catch (e) {
log.warning("path:$path, api:$e");
logger.warning("path:$path, api:$e");
throw e;
}
}
@@ -157,7 +170,7 @@ Future<dynamic> requestDownload(String path, method,
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
String deviceName = "${androidInfo.model}(${androidInfo.id})";
log.info("device:${androidInfo.id},deviceName:$deviceName");
logger.info("device:${androidInfo.id},deviceName:$deviceName");
var bytes = utf8.encode(payload);
var base64Str = base64.encode(bytes);
@@ -165,7 +178,7 @@ Future<dynamic> requestDownload(String path, method,
try {
String baseUrl = url == null ? Config.instance.apiURL : url;
log.info("Path:$baseUrl$path");
logger.info("Path:$baseUrl$path");
HttpClient client = new HttpClient();
// var _downloadData = StringBuffer();
var request = await client.postUrl(Uri.parse("$baseUrl$path"));
@@ -207,7 +220,7 @@ Future<dynamic> requestDownload(String path, method,
});
} catch (e) {
e.toString();
log.warning("path:$path, api:$e");
logger.warning("path:$path, api:$e");
throw e;
}
}
@@ -218,7 +231,7 @@ Future<File> downloadPDF(
final directory = await getApplicationSupportDirectory();
String path = ('${directory.path}');
log.info("download file path:$path");
logger.info("download file path:$path");
var data = {"template_name": templateName, "data": values};
print("payload:$data");

View File

@@ -16,7 +16,7 @@ Future<void> main() async {
flavor: Flavor.DEV,
color: Colors.blue,
apiURL: "https://asia-northeast1-fcs-dev1.cloudfunctions.net/API12",
reportURL: "http://petrok.mokkon.com:8091",
reportURL: "http://petrok.mokkon.com:7071",
reportProjectID: "fcs-dev",
bucketName: "gs://fcs-dev1-us",
level: Level.ALL);

View File

@@ -63,17 +63,6 @@ class _CartonEditorState extends State<CartonEditor> {
_isNew = true;
_selectedCartonType = carton_from_packages;
_cartons = [];
_sender = User(
name: "ptd-phyo44 kaelone",
fcsID: "FCS-8X6V",
phoneNumber: "+959444444444",
id: "48u_4s-HiQeW-HwSqeRd9TSMWh3mLZfSk5rpaUEh_zw");
_consignee = User(
id: "HsIwG88K-0_HSazgEy5QR27kcjkOvfv7_Sr1JP18Q1A",
name: "One One",
phoneNumber: "+959111111111",
fcsID: "FCS-EFRF");
}
if (mounted) {
setState(() {});

View File

@@ -3,11 +3,14 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../domain/constants.dart';
import '../../domain/entities/fcs_shipment.dart';
import '../../domain/entities/user.dart';
import '../../helpers/theme.dart';
import '../../localization/app_translations.dart';
import '../main/util.dart';
import '../widgets/local_text.dart';
import 'model/shipment_selection_model.dart';
import 'widget/shipment_result.dart';
import 'widget/user_search_result.dart';
import 'model/carton_model.dart';
import 'model/consignee_selection_model.dart';
@@ -24,6 +27,8 @@ class _CartonFilterState extends State<CartonFilter> {
String? _selectedStatus;
User? _selectedSender;
User? _selectedConsignee;
FcsShipment? _selectedShipment;
bool _isLoadMoreShipment = false;
List<String> statusList = [
all_status,
@@ -48,11 +53,13 @@ class _CartonFilterState extends State<CartonFilter> {
_selectedStatus = model.filterByStatus ?? all_status;
_selectedConsignee = model.filterByConsingee ?? User(id: all, name: "All");
_selectedSender = model.filterBySender ?? User(id: all, name: "All");
_selectedShipment = model.shipment ?? model.defaultShipment;
init();
super.initState();
}
init() async {
_initShipment();
_initConsignee();
_initSender();
if (mounted) {
@@ -60,6 +67,13 @@ class _CartonFilterState extends State<CartonFilter> {
}
}
_initShipment() async {
await context.read<ShipmentSelectionModel>().refresh();
if (mounted) {
setState(() {});
}
}
_initConsignee() {
var model = context.read<ConsigneeSelectionModel>();
_consigneeCtl.text = model.query;
@@ -109,6 +123,21 @@ class _CartonFilterState extends State<CartonFilter> {
});
}
Future<void> _loadMoreShipment() async {
if (_isLoadMoreShipment) return;
var model = context.read<ShipmentSelectionModel>();
if (model.ended) return;
setState(() {
_isLoadMoreShipment = true;
});
await model.loadMoreData();
setState(() {
_isLoadMoreShipment = false;
});
}
Future<void> _loadMoreSender() async {
if (_isLoadMoreSender) return;
var model = context.read<SenderSelectionModel>();
@@ -130,9 +159,11 @@ class _CartonFilterState extends State<CartonFilter> {
@override
Widget build(BuildContext context) {
var consigneeModel = context.watch<ConsigneeSelectionModel>();
List<User> consignees = consigneeModel.getConsginees;
var senderModel = context.watch<SenderSelectionModel>();
var shipmentModel = context.watch<ShipmentSelectionModel>();
List<User> consignees = consigneeModel.getConsginees;
List<User> senders = senderModel.getSenders;
List<FcsShipment> shipments = shipmentModel.getShipments;
final _titleWidget = SizedBox(
height: 30,
@@ -144,6 +175,9 @@ class _CartonFilterState extends State<CartonFilter> {
labelPadding: const EdgeInsets.all(0),
indicatorPadding: const EdgeInsets.all(0),
tabs: [
Tab(
text: AppTranslations.of(context)?.text("box.fcs_shipment_num"),
),
Tab(
text: AppTranslations.of(context)?.text("box.consignee.title"),
),
@@ -157,6 +191,30 @@ class _CartonFilterState extends State<CartonFilter> {
),
);
final _shipmentWidget = Column(
children: [
Expanded(
child: ShipmentResult(
searchResults: shipments,
isLoading: shipmentModel.isLoading,
noDataLabelKey: 'user.no_consignee',
selectedUser: _selectedShipment,
controller: widget.controller,
isLoadingMore: _isLoadMoreShipment,
onLoadMore: _loadMoreShipment,
onRefresh: () async {
_initShipment();
},
onTap: (a) async {
setState(() {
_selectedShipment = a;
});
},
),
)
],
);
final _consingeeWidget = Column(
children: [
const SizedBox(height: 15),
@@ -335,13 +393,14 @@ class _CartonFilterState extends State<CartonFilter> {
),
Expanded(
child: DefaultTabController(
length: 3,
length: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_titleWidget,
Expanded(
child: TabBarView(children: <Widget>[
_shipmentWidget,
_consingeeWidget,
_senderWidget,
_statusWidget
@@ -427,15 +486,15 @@ class _CartonFilterState extends State<CartonFilter> {
}
_clearFilter() async {
await context.read<CartonModel>().filterCarton(
User(id: all, name: "All"), User(id: all, name: "All"), all_status);
Navigator.pop(context);
var model = context.read<CartonModel>();
await model.filterCarton(model.defaultShipment, User(id: all, name: "All"),
User(id: all, name: "All"), all_status);
Navigator.pop(context, true);
}
_filter() async {
await context
.read<CartonModel>()
.filterCarton(_selectedConsignee, _selectedSender, _selectedStatus);
Navigator.pop(context);
await context.read<CartonModel>().filterCarton(_selectedShipment,
_selectedConsignee, _selectedSender, _selectedStatus);
Navigator.pop(context, true);
}
}

View File

@@ -8,7 +8,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:provider/provider.dart';
import '../../domain/constants.dart';
import '../../domain/entities/carton.dart';
import '../../pagination/paginator_listview.dart';
@@ -38,10 +37,14 @@ class _CartonListState extends State<CartonList> {
_init() async {
var model = context.read<CartonModel>();
_shipments = await context.read<FcsShipmentModel>().getAllShipments();
_shipments.insert(0, FcsShipment(shipmentNumber: "All Shipments", id: all));
_selectedShipment =
model.shipment ?? FcsShipment(shipmentNumber: "All Shipments", id: all);
_shipments = await context.read<FcsShipmentModel>().getShipments();
_shipments.insert(0, model.defaultShipment);
if (_shipments.length > shipmentCountForCartonFilter) {
_shipments.insert(_shipments.length,
FcsShipment(shipmentNumber: "See All", id: see_all));
}
_selectedShipment = model.shipment ?? model.defaultShipment;
model.loadPaginationCartons();
if (mounted) {
@@ -69,18 +72,22 @@ class _CartonListState extends State<CartonList> {
child: ActionChip(
shape: StadiumBorder(
side: BorderSide(
color: _selectedShipment?.id == g.id
? primaryColor
: Colors.grey.shade300)),
color: g.id == see_all
? Colors.transparent
: _selectedShipment?.id == g.id
? primaryColor
: Colors.grey.shade300)),
padding: const EdgeInsets.all(8),
onPressed: () {
_filterShipment(g);
},
label: Text(g.shipmentNumber ?? "",
style: TextStyle(
color: _selectedShipment?.id == g.id
color: g.id == see_all
? primaryColor
: labelColor,
: _selectedShipment?.id == g.id
? primaryColor
: labelColor,
fontWeight: FontWeight.normal,
fontSize: 14,
fontFamily: "Poppins")),
@@ -292,7 +299,8 @@ class _CartonListState extends State<CartonList> {
),
model.filterByStatus != null ||
model.filterBySender != null ||
model.filterByConsingee != null
model.filterByConsingee != null ||
model.shipment != null
? Positioned(
bottom: 15,
right: 0,
@@ -308,25 +316,38 @@ class _CartonListState extends State<CartonList> {
: Container()
],
),
onPressed: () async {
await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(top: Radius.circular(10))),
builder: (ctx) => DraggableScrollableSheet(
initialChildSize: 0.6,
minChildSize: 0.6,
expand: false,
builder: (_, controller) =>
CartonFilter(controller: controller)));
onPressed: () {
_showFilter();
});
}
_showFilter() async {
bool? updated = await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(10))),
builder: (ctx) => DraggableScrollableSheet(
initialChildSize: 0.6,
minChildSize: 0.6,
expand: false,
builder: (_, controller) => CartonFilter(controller: controller)));
var model = context.read<CartonModel>();
if (updated ?? false) {
setState(() {
_selectedShipment = model.shipment ?? model.defaultShipment;
});
}
}
_filterShipment(FcsShipment shipment) async {
if (shipment.id == see_all) {
_showFilter();
return;
}
setState(() {
_selectedShipment = shipment;
});

View File

@@ -17,6 +17,8 @@ import 'package:path/path.dart' as Path;
class CartonModel extends BaseModel {
final log = Logger('CartonModel');
var defaultShipment =FcsShipment(shipmentNumber: "All shipments", id: all);
PaginatorListener<Carton>? cartonsByFilter;
PaginatorListener<Carton>? getBoxes;
@@ -56,7 +58,8 @@ class CartonModel extends BaseModel {
_loadPaginationCartons();
}
filterCarton(User? consignee, User? sender, String? status) async {
filterCarton(FcsShipment? fcsShipment, User? consignee, User? sender,
String? status) async {
filterByStatus = status;
if (status == all_status) {
@@ -77,6 +80,12 @@ class CartonModel extends BaseModel {
filterBySender = sender;
}
if (fcsShipment?.id == all) {
shipment = null;
} else {
shipment = fcsShipment;
}
loadPaginationCartons();
notifyListeners();
}

View File

@@ -0,0 +1,75 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:logging/logging.dart';
import '../../../domain/constants.dart';
import '../../main/model/base_model.dart';
class ShipmentSelectionModel extends BaseModel {
final log = Logger("ShipmentSelectionModel");
List<FcsShipment> _shipments = [];
List<FcsShipment> get getShipments {
var list = new List<FcsShipment>.from(_shipments);
return list
..insert(0, FcsShipment(id: all, shipmentNumber: "All shipments"));
}
bool isLoading = false;
DocumentSnapshot? _lastDocument;
bool ended = false;
Future<void> refresh() async {
_shipments.clear();
_lastDocument = null;
ended = false;
await loadMoreData();
notifyListeners();
}
Future<void> loadMoreData() async {
int rowPerPage = 20;
try {
isLoading = true;
String path = "/$fcs_shipment_collection";
Query query = FirebaseFirestore.instance
.collection(path)
.where("status", whereIn: [
fcs_shipment_processing_status,
fcs_shipment_shipped_status,
fcs_shipment_arrived_status,
fcs_shipment_invoiced_status
])
.where("is_deleted", isEqualTo: false)
.orderBy("update_time", descending: true);
if (_lastDocument != null) {
query = query.startAfterDocument(_lastDocument!);
}
QuerySnapshot querySnap = await query.limit(rowPerPage).get();
if (querySnap.docs.isEmpty) return;
_lastDocument = querySnap.docs[querySnap.docs.length - 1];
List<FcsShipment> list = querySnap.docs.map((documentSnapshot) {
var p = FcsShipment.fromMap(
documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return p;
}).toList();
_shipments.addAll(list);
if (list.length < rowPerPage) ended = true;
notifyListeners();
} catch (e) {
log.warning("error:$e");
} finally {
isLoading = false;
}
}
}

View File

@@ -13,7 +13,6 @@ import '../widgets/continue_button.dart';
import '../widgets/display_text.dart';
import '../widgets/local_title.dart';
import '../widgets/previous_button.dart';
import 'model/carton_selection_model.dart';
import 'model/package_selection_model.dart';
import 'package_selection_result.dart';
@@ -63,25 +62,26 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
_init() {
var searchModel = context.read<PackageSelectionModel>();
searchModel.addDefaultPackages(
shipmentId: widget.shipment.id!,
consigneeId: widget.consignee.id!,
senderId: widget.sender.id!);
searchModel.addSelectedPackage(widget.packages);
_controller.text = searchModel.query;
_query = searchModel.query;
if (mounted) {
setState(() {});
}
}
@override
void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
_init();
super.didUpdateWidget(oldWidget);
}
// @override
// void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
// _init();
// super.didUpdateWidget(oldWidget);
// }
Future<void> _loadMoreData() async {
if (_isLoadMore) return;
@@ -278,7 +278,7 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
isLoadingMore: _isLoadMore,
onLoadMore: _loadMoreData,
onRefresh: () async {
_init();
_search();
setState(() {
_down = true;
});
@@ -330,9 +330,11 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
_search({bool imm = false}) async {
try {
await context
.read<CartonSelectionModel>()
.search(_query, imm: imm, shipmentId: widget.shipment.id!);
await context.read<PackageSelectionModel>().search(_query,
imm: imm,
shipmentId: widget.shipment.id!,
senderId: widget.sender.id!,
consigneeId: widget.consignee.id!);
} catch (e) {
showMsgDialog(context, 'Error', e.toString());
}

View File

@@ -0,0 +1,97 @@
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/material.dart';
import '../../../../helpers/theme.dart';
typedef OnAction = Future<void> Function();
class ShipmentResult extends StatelessWidget {
final bool isLoadingMore;
final OnAction onLoadMore;
final OnAction onRefresh;
final Function(FcsShipment)? onTap;
final ScrollController controller;
final FcsShipment? selectedUser;
final List<FcsShipment> searchResults;
final String? noDataLabelKey;
final bool isLoading;
const ShipmentResult(
{super.key,
required this.isLoadingMore,
required this.onLoadMore,
required this.onRefresh,
this.onTap,
required this.controller,
this.selectedUser,
this.searchResults = const [],
this.noDataLabelKey,
this.isLoading = false});
bool _scrollNotification(ScrollNotification scrollInfo) {
if (!isLoadingMore &&
scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
onLoadMore();
}
return true;
}
@override
Widget build(BuildContext context) {
return searchResults.isEmpty && !isLoading
? noDataLabelKey == null
? const SizedBox()
: Center(
child: LocalText(context, noDataLabelKey!,
color: Colors.black, fontSize: 15))
: Column(children: [
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: _scrollNotification,
child: RefreshIndicator(
color: primaryColor,
onRefresh: () => onRefresh(),
child: ListView.builder(
controller: controller,
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
FcsShipment user = searchResults[index];
return ListTile(
onTap: () {
if (onTap != null) {
onTap!(user);
}
},
title: Row(
children: [
Text(user.shipmentNumber ?? "",
style: const TextStyle(
fontSize: 15, color: Colors.black)),
const SizedBox(
width: 20,
),
selectedUser?.id == user.id
? const Icon(
Icons.check,
color: Colors.grey,
)
: const SizedBox()
],
),
);
},
itemCount: searchResults.length)),
)),
Container(
height: isLoadingMore ? 50.0 : 0,
color: Colors.transparent,
child: const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(primaryColor)),
)),
]);
}
}

View File

@@ -64,7 +64,11 @@ class _FcsShipmentEditorState extends State<FcsShipmentEditor> {
_portController.text = _shipment.port ?? "";
_destinationController.text = _shipment.destination ?? "";
// _currentShipmentType = model.shipmentTypes.where((e) => e.id == _shipment.shipmentTypeId).first;
List<ShipmentType> list = model.shipmentTypes
.where((e) => e.id == _shipment.shipmentTypeId)
.toList();
_currentShipmentType = list.isNotEmpty ? list.first : null;
} else {
_currentShipmentType = model.shipmentTypes[0];
}
@@ -175,7 +179,7 @@ class _FcsShipmentEditorState extends State<FcsShipmentEditor> {
icon: Icon(Ionicons.ios_airplane, color: primaryColor)),
items: shipmentTypes
.map((e) =>
DropdownMenuItem(child: Text(e.desc), value: e))
DropdownMenuItem(child: Text(e.name), value: e))
.toList(),
onChanged: (selected) => {
setState(() {
@@ -209,7 +213,7 @@ class _FcsShipmentEditorState extends State<FcsShipmentEditor> {
FcsShipment fcsShipment = FcsShipment();
fcsShipment.id = _shipment.id;
fcsShipment.shipmentNumber = _shipmentNumberController.text;
fcsShipment.shipmentTypeId = _currentShipmentType?.id;
fcsShipment.shipmentTypeId = _currentShipmentType?.id ?? "";
fcsShipment.consignee = _consigneeController.text;
fcsShipment.port = _portController.text;
fcsShipment.destination = _destinationController.text;
@@ -230,9 +234,8 @@ class _FcsShipmentEditorState extends State<FcsShipmentEditor> {
setState(() {
_isLoading = true;
});
var shipmentModel = Provider.of<FcsShipmentModel>(context, listen: false);
try {
await shipmentModel.create(fcsShipment);
await context.read<FcsShipmentModel>().create(fcsShipment);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
@@ -250,9 +253,9 @@ class _FcsShipmentEditorState extends State<FcsShipmentEditor> {
setState(() {
_isLoading = true;
});
var shipmentModel = Provider.of<FcsShipmentModel>(context, listen: false);
try {
await shipmentModel.update(fcsShipment);
await context.read<FcsShipmentModel>().update(fcsShipment);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());

View File

@@ -59,7 +59,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
if (_fcsShipment?.departureDate != null)
_departureDateControler.text =
dateFormatter.format(_fcsShipment!.departureDate!);
_shipmentTypeControler.text = _fcsShipment!.shipType ?? "";
_shipmentTypeControler.text = _fcsShipment!.shipTypeName ?? "";
_consigneeController.text = _fcsShipment!.consignee ?? "";
_portController.text = _fcsShipment!.port ?? "";
_destinationController.text = _fcsShipment!.destination ?? "";
@@ -148,7 +148,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
final invoiceBtn = Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: LocalButton(
textKey: "FCSshipment.invoice.btn",
textKey: "FCSshipment.invoiced.btn",
callBack: _invoice,
),
);
@@ -194,19 +194,17 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
Row(mainAxisAlignment: MainAxisAlignment.end, children: [
Expanded(
child: cutoffDateDBox,
flex: 2,
),
Flexible(
child: etaBox,
// flex: 2,
),
Flexible(child: etaBox),
]),
Row(
children: [
Expanded(
child: cartonBox,
flex: 2,
// flex: 2,
),
Flexible(child: packageBox),
Flexible(child: packageBox)
],
),
shipTypeBox,
@@ -296,9 +294,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
_isLoading = true;
});
try {
FcsShipmentModel fcsShipmentModel =
Provider.of<FcsShipmentModel>(context, listen: false);
await fcsShipmentModel.process(_fcsShipment!.id!);
await context.read<FcsShipmentModel>().process(_fcsShipment!.id!);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
@@ -320,9 +316,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
_isLoading = true;
});
try {
FcsShipmentModel fcsShipmentModel =
Provider.of<FcsShipmentModel>(context, listen: false);
await fcsShipmentModel.ship(_fcsShipment!.id!);
await context.read<FcsShipmentModel>().ship(_fcsShipment!.id!);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
@@ -344,9 +338,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
_isLoading = true;
});
try {
FcsShipmentModel fcsShipmentModel =
Provider.of<FcsShipmentModel>(context, listen: false);
await fcsShipmentModel.arrive(_fcsShipment!.id!);
await context.read<FcsShipmentModel>().arrive(_fcsShipment!.id!);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
@@ -368,9 +360,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
_isLoading = true;
});
try {
FcsShipmentModel fcsShipmentModel =
Provider.of<FcsShipmentModel>(context, listen: false);
await fcsShipmentModel.invoice(_fcsShipment!.id!);
await context.read<FcsShipmentModel>().invoice(_fcsShipment!.id!);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
@@ -386,9 +376,7 @@ class _FcsShipmentInfoState extends State<FcsShipmentInfo> {
_isLoading = true;
});
try {
FcsShipmentModel fcsShipmentModel =
Provider.of<FcsShipmentModel>(context, listen: false);
await fcsShipmentModel.cancel(_fcsShipment!.id!);
await context.read<FcsShipmentModel>().cancel(_fcsShipment!.id!);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());

View File

@@ -87,7 +87,7 @@ class FcsShipmentModel extends BaseModel {
try {
var snaps = await FirebaseFirestore.instance
.collection("/$fcs_shipment_collection")
// .where("status", isEqualTo: fcs_shipment_confirmed_status)
.where("status", isEqualTo: fcs_shipment_processing_status)
.get(const GetOptions(source: Source.server));
fcsShipments = snaps.docs.map((documentSnapshot) {
var fcs =
@@ -199,12 +199,20 @@ class FcsShipmentModel extends BaseModel {
return Services.instance.fcsShipmentService.report(fcsShipment);
}
Future<List<FcsShipment>> getAllShipments() async {
Future<List<FcsShipment>> getShipments() async {
List<FcsShipment> fcsShipments = [];
try {
var snaps = await FirebaseFirestore.instance
.collection("/$fcs_shipment_collection")
.where("status", whereIn: [
fcs_shipment_processing_status,
fcs_shipment_shipped_status,
fcs_shipment_arrived_status,
fcs_shipment_invoiced_status
])
.where("is_deleted", isEqualTo: false)
.orderBy("update_time", descending: true)
.limit(shipmentCountForCartonFilter)
.get(const GetOptions(source: Source.server));
fcsShipments = snaps.docs.map((documentSnapshot) {
var fcs =

View File

@@ -86,14 +86,18 @@ class PackageSearchDelegate extends SearchDelegate<Package> {
}
return Container(
padding: EdgeInsets.only(top: 15),
child: ListView(
children: snapshot.data!
.map((u) => PackageListRow(
package: u,
callbackPackageSelect: callbackPackageSelect,
))
.toList(),
),
child: ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1, color: dividerColor),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return Column(children: [
PackageListRow(
package: snapshot.data![index],
callbackPackageSelect: callbackPackageSelect,
)
]);
}),
);
} else if (snapshot.hasError) {
return Container(

View File

@@ -87,14 +87,18 @@ class PackageSearchDelegate extends SearchDelegate<Pickup> {
}
return Container(
padding: EdgeInsets.only(top: 15),
child: ListView(
children: snapshot.data!.map((e) {
return PickupListRow(
pickup: e,
callbackPickupSelect: callbackPickupSelect,
);
}).toList(),
),
child: ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1, color: dividerColor),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return Column(children: [
PickupListRow(
pickup: snapshot.data![index],
callbackPickupSelect: callbackPickupSelect,
)
]);
}),
);
} else if (snapshot.hasError) {
return Container(

View File

@@ -21,48 +21,51 @@ class UserListRow extends StatelessWidget {
onTap: () {
if (onUserRowSelect != null) onUserRowSelect!(user);
},
child: Row(
children: <Widget>[
Expanded(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.symmetric(
horizontal: 32.0 - dotSize / 2),
child: Icon(
Icons.perm_identity,
color: primaryColor,
size: 50,
)),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
user.name ?? "",
style: new TextStyle(
fontSize: 15.0, color: Colors.black),
),
new Text(
user.fcsID ?? "",
style: new TextStyle(
fontSize: 13.0, color: Colors.grey),
),
new Text(
user.phoneNumber ?? "",
style: new TextStyle(
fontSize: 13.0, color: Colors.grey),
),
],
child: Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Row(
children: <Widget>[
Expanded(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 13.0),
child: new Row(
children: <Widget>[
Icon(
Icons.perm_identity,
color: primaryColor,
size: 30,
),
),
],
new Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
user.name ?? "",
style: new TextStyle(
fontSize: 15.0, color: Colors.black),
),
new Text(
user.fcsID ?? "",
style: new TextStyle(
fontSize: 14.0, color: Colors.grey),
),
new Text(
user.phoneNumber ?? "",
style: new TextStyle(
fontSize: 14.0, color: Colors.grey),
),
],
),
),
),
],
),
),
),
),
],
],
),
),
),
),

View File

@@ -6,6 +6,8 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/services/services.dart';
typedef OnUserSelect(User suer);
typedef OnUserRowSelect(User suer);
@@ -124,9 +126,10 @@ class UserSearchDelegate extends SearchDelegate<User> {
);
}
_onUserRowSelect(BuildContext context, User user) {
_onUserRowSelect(BuildContext context, User user) async {
User? u = await Services.instance.userService.getUser(user.id ?? "");
if (onUserSelect != null) {
onUserSelect!(user);
onUserSelect!(u ?? user);
}
if (popPage) {
Navigator.pop(context);

View File

@@ -14,11 +14,11 @@ dependencies:
cupertino_icons: ^1.0.3
firebase_core: ^2.17.0
firebase_auth: ^4.10.1
cloud_firestore: ^4.9.3
firebase_storage: ^11.5.6
firebase_messaging: ^14.6.9
firebase_core: ^2.25.5
firebase_auth: ^4.17.6
cloud_firestore: ^4.15.6
firebase_storage: ^11.6.7
firebase_messaging: ^14.7.17
provider: ^6.0.0
image_picker: ^1.0.6
@@ -49,7 +49,7 @@ dependencies:
timeline_list: ^0.0.5
barcode_scan2: ^4.1.4
flutter_pdfview: ^1.2.1
flutter_local_notifications: ^16.3.0
flutter_local_notifications: ^16.3.2
share: ^2.0.4
cached_network_image: ^3.3.1
flutter_cache_manager: ^3.1.2