diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 080c567..ac4eb8b 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -256,7 +256,7 @@ "box.width":"Width", "box.height":"Height", "box.shipment_info":"Shipment information", - "box.cargo_type":"Cargo types", + "box.cargo.type":"Cargos", "box.dimension":"Dimension", "box.delivery_address":"Delivery address", "box.fcs_shipment_num":"FCS shipment number", @@ -316,6 +316,10 @@ "FCSshipment.cargo_manifest":"Download cargo manifest", "FCSshipment.create":"Create FCS shipment", "FCSshipment.update":"Update FCS shipment", + "FCSshipment.ship.btn":"Ship", + "FCSshipment.ship.confirm":"Confirm ship?", + "FCSshipment.popupmenu.active":"Active FCS shipments", + "FCSshipment.popupmenu.delivered":"Delivered FCS shipments", "FCS Shipment End ================================================================":"", "Shipment Start ================================================================":"", @@ -323,22 +327,22 @@ "shipment.title": "Shipments", "shipment.number": "Shipment number", "shipment.new": "New shipment", - "shipment.new.title": "New Shipment", - "shipment.edit.title": "Edit Shipment", + "shipment.new.title": "New shipment", + "shipment.edit.title": "Edit shipment", "shipment.type": "Pickup/drop-off", "shipment.date": "Pickup date", - "shipment.date.time": "Pickup date/Time", + "shipment.date.time": "Pickup date/time", "shipment.time": "Pickup time", "shipment.location": "Pickup address", "shipment.location.dropoff": "Local dropoff address", "shipment.courier.dropoff":"Courier dropoff", - "shipment.location_time": "Pickup Location / Time", + "shipment.location_time": "Pickup location/time", "shipment.information": "Pickup information", "shipment.recipient_information": "Recipient informations", "shipment.from":"Ready time", "shipment.to":"Latest time available", "shipment.box.delivery":"Delivery address", - "shipment.handling.fee":"Handling fee/Courier fee", + "shipment.handling.fee":"Handling fee/courier fee", "shipment.box.cargo.type":"Cargo types", "shipment.box.dimemsion":"Dimension", "shipment.box.shipment.weight":"Shipment weight", @@ -346,13 +350,34 @@ "shipment.box.width":"Width", "shipment.box.height":"Height", "shipment.box.add":"Add carton", - "shipment.cargo.total":"Total Weight", - "shipment.popupmenu.active":"Active Shipments", - "shipment.popupmenu.delivered":"Delivered Shipments", + "shipment.cargo.total":"Total weight", + "shipment.cargo.count":"Carton count", + "shipment.popupmenu.active":"Active shipments", + "shipment.popupmenu.delivered":"Delivered shipments", + "shipment.popupmenu.mypickup":"My pickups", "shipment.create":"Create shipment", "shipment.update":"Update shipment", - "shipment.info":"Shipment Info", + "shipment.info":"Shipment info", "shipment.cancel.confirm":"Cancel this shipment?", + "shipment.assign.title":"Assign shipment", + "shipment.assign.for.pickup":"Assign for pickup", + "shipment.assign.btn":"Assign", + "shipment.assign.complete.btn":"Complete assign pickup", + "shipment.assign.complete.confirm":"Complete assign pickup?", + "shipment.staff":"Staff", + "shipment.pickup.complete.btn":"Complete pickup", + "shipment.pickup.complete.confirm":"Complete pickup?", + "shipment.pack.complete.btn":"Complete pack", + "shipment.pack.complete.confirm":"Complete pack?", + "shipment.pack.menuitem":"Pack shipment", + "shipment.pack.fcs.shipment":"FCS shipment", + "shipment.pack.btn":"Pack", + "shipment.confirm.menuitem":"Confirm shipment", + "shipment.confirm.btn":"Confirm", + "shipment.confirm.complete.btn":"Complete confirm", + "shipment.confirm.complete.confirm":"Complete confirm?", + "shipment.receive.complete.btn":"Complete receive", + "shipment.receive.complete.confirm":"Complete receive?", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index cf10d2e..877a894 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -8,7 +8,7 @@ "btn.approve":"အတည်ပြုရန်", "btn.delete":"ဖျက်ရန်", "btn.select":"ရွေးချယ်ပါ", - "btn.cancel":"မလုပ်နဲ့", + "btn.cancel":"ဖျက်သိမ်းမည်", "btn.ok": "အိုကေ", "feet":"ပေ", "inch":"လက်မ", @@ -256,7 +256,7 @@ "box.width":"အနံ", "box.height":"အမြင့်", "box.shipment_info":"တင်ပို့သတင်းအချက်အလက်", - "box.cargo_type":"ကုန်ပစ္စည်းအမျိုးအစားများ", + "box.cargo.type":"ကုန်ပစ္စည်းအမျိုးအစားများ", "box.dimension":"အရွယ်အစား", "box.delivery_address":"ပို့ဆောင်ရမည့်လိပ်စာ", "box.fcs_shipment_num":"FCS တင်ပို့နံပါတ်", @@ -316,6 +316,8 @@ "FCSshipment.cargo_manifest":"ကုန်ပစ္စည်းကိုဒေါင်းမည်", "FCSshipment.create":"FCS တင်ပို့ခြင်းပြုလုပ်မည်", "FCSshipment.update":"FCS တင်ပို့ခြင်းပြုပြင်မည်", + "FCSshipment.ship.btn":"Ship", + "FCSshipment.ship.confirm":"Confirm ship?", "FCS Shipment End ================================================================":"", "Shipment Start ================================================================":"", @@ -325,11 +327,11 @@ "shipment.new": "ပို့ဆောင်ခြင်း အသစ်", "shipment.new.title": "ပို့ဆောင်ခြင်း အသစ်", "shipment.edit.title": "ပို့ဆောင်ခြင်း ပြင်ဆင်ခြင်း", - "shipment.type": "Pickup/Drop-off", + "shipment.type": "Pickup/drop-off", "shipment.date": "Pickup နေ့စွဲ", "shipment.date.time": "Pickup နေ့စွဲ/အချိန်", "shipment.time": "Pickup အချိန်", - "shipment.location_time": "Pickup location / Time", + "shipment.location_time": "Pickup location/time", "shipment.location": "Pickup လိပ်စာ", "shipment.location.dropoff": "Local dropoff လိပ်စာ", "shipment.courier.dropoff":"Courier dropoff", @@ -338,7 +340,7 @@ "shipment.from":"အချိန်(မှ)", "shipment.to":"အချိန်(သို့)", "shipment.box.delivery":"ပို့ဆောင်ရမည့်လိပ်စာ", - "shipment.handling.fee":"Handling fee/Courier fee", + "shipment.handling.fee":"Handling fee/courier fee", "shipment.box.cargo.type":"ကုန်ပစ္စည်းအမျိုးအစားများ", "shipment.box.dimemsion":"အရွယ်အစား", "shipment.box.shipment.weight":"တင်ပို့အလေးချိန်", @@ -347,12 +349,33 @@ "shipment.box.height":"အမြင့်", "shipment.box.add":"သေတ္တာထည့်မည်", "shipment.cargo.total":"စုစုပေါင်း အလေးချိန်", + "shipment.cargo.count":"စုစုပေါင်း ပုံးအရေအတွက်", "shipment.popupmenu.active":"လာမည့် အထုပ်များ", "shipment.popupmenu.delivered":"ပို့ပြီးသော အထုပ်များ", + "shipment.popupmenu.mypickup":"ကျွန်ုပ်၏ သယ်ဆောင်ရန် အထုပ်များ", "shipment.create":"ပို့ဆောင်ခြင်း ပြုလုပ်မည်", "shipment.update":"ပို့ဆောင်ခြင်းပြုပြင်မည်", "shipment.info":"ပို့ဆောင်ခြင်း", "shipment.cancel.confirm":"ပို့ဆောင်ခြင်း ပိတ်သိမ်းမလား?", + "shipment.assign.title":"ပို့ဆောင်ခြင်း တာဝန်ပေးရန်", + "shipment.assign.for.pickup":"သယ်ဆောင်ရန် တာဝန်ပေးမည်", + "shipment.assign.btn":"တာဝန်ပေးမည်", + "shipment.assign.complete.btn":"တာဝန်ပေး ပြီးဆုံးမည်", + "shipment.assign.complete.confirm":"တာဝန်ပေး ပြီးဆုံးမလား?", + "shipment.staff":"ဝန်ထမ်း", + "shipment.pickup.complete.btn":"Complete pickup", + "shipment.pickup.complete.confirm":"Complete pickup?", + "shipment.pack.complete.btn":"Complete pack", + "shipment.pack.complete.confirm":"Complete pack?", + "shipment.pack.menuitem":"Pack shipment", + "shipment.pack.fcs.shipment":"FCS shipment", + "shipment.pack.btn":"Pack", + "shipment.confirm.menuitem":"Confirm shipment", + "shipment.confirm.btn":"Confirm", + "shipment.confirm.complete.btn":"Complete confirm", + "shipment.confirm.complete.confirm":"Complete confirm?", + "shipment.receive.complete.btn":"Complete receive", + "shipment.receive.complete.confirm":"Complete receive?", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/lib/data/provider/carton_data_provider.dart b/lib/data/provider/carton_data_provider.dart new file mode 100644 index 0000000..b127b13 --- /dev/null +++ b/lib/data/provider/carton_data_provider.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/api_helper.dart'; +import 'package:fcs/helpers/firebase_helper.dart'; +import 'package:logging/logging.dart'; + +class CartonDataProvider { + final log = Logger('CartonDataProvider'); + + static final CartonDataProvider instance = CartonDataProvider._(); + CartonDataProvider._(); + + Future createCarton(Carton carton) async { + return await requestAPI("/cartons", "POST", + payload: carton.toMap(), token: await getToken()); + } + + Future updateCarton(Carton carton) async { + return await requestAPI("/cartons", "PUT", + payload: carton.toMap(), token: await getToken()); + } + + Future deleteCarton(Carton carton) async { + return await requestAPI("/cartons", "DELETE", + payload: carton.toMap(), token: await getToken()); + } +} diff --git a/lib/data/provider/fcs_shipment_data_provider.dart b/lib/data/provider/fcs_shipment_data_provider.dart index ea415f7..530a85d 100644 --- a/lib/data/provider/fcs_shipment_data_provider.dart +++ b/lib/data/provider/fcs_shipment_data_provider.dart @@ -20,4 +20,9 @@ class FcsShipmentDataProvider { return await requestAPI("/fcs_shipments", "DELETE", payload: fcsShipment.toMap(), token: await getToken()); } + + Future ship(FcsShipment fcsShipment) async { + return await requestAPI("/fcs_shipments/ship", "PUT", + payload: fcsShipment.toMap(), token: await getToken()); + } } diff --git a/lib/data/provider/shipment_data_provider.dart b/lib/data/provider/shipment_data_provider.dart index 37cf72a..44479e3 100644 --- a/lib/data/provider/shipment_data_provider.dart +++ b/lib/data/provider/shipment_data_provider.dart @@ -26,8 +26,43 @@ class ShipmentDataProvider { payload: shipment.toMap(), token: await getToken()); } + Future assignShipment(Shipment shipment) async { + return await requestAPI("/shipments/assign", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future completeAssignShipment(Shipment shipment) async { + return await requestAPI("/shipments/assign/complete", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future completePickupShipment(Shipment shipment) async { + return await requestAPI("/shipments/pickup/complete", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future packShipment(Shipment shipment) async { + return await requestAPI("/shipments/pack", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future completePackShipment(Shipment shipment) async { + return await requestAPI("/shipments/pack/complete", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + Future confirmShipment(Shipment shipment) async { - return await requestAPI("/shipment_confirm", "PUT", + return await requestAPI("/shipments/confirm", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future completeConfirmShipment(Shipment shipment) async { + return await requestAPI("/shipments/confirm/complete", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future completeReceiveShipment(Shipment shipment) async { + return await requestAPI("/shipments/receive/complete", "PUT", payload: shipment.toMap(), token: await getToken()); } diff --git a/lib/data/services/carton_imp.dart b/lib/data/services/carton_imp.dart new file mode 100644 index 0000000..872da10 --- /dev/null +++ b/lib/data/services/carton_imp.dart @@ -0,0 +1,31 @@ +import 'package:fcs/data/provider/carton_data_provider.dart'; +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/connectivity.dart'; +import 'package:flutter/material.dart'; + +import 'carton_service.dart'; + +class CartonServiceImp implements CartonService { + CartonServiceImp({ + @required this.cartonDataProvider, + @required this.connectivity, + }); + + final Connectivity connectivity; + final CartonDataProvider cartonDataProvider; + + @override + Future createCarton(Carton carton) { + return cartonDataProvider.createCarton(carton); + } + + @override + Future deleteCarton(Carton carton) { + return cartonDataProvider.deleteCarton(carton); + } + + @override + Future updateCarton(Carton carton) { + return cartonDataProvider.updateCarton(carton); + } +} diff --git a/lib/data/services/carton_service.dart b/lib/data/services/carton_service.dart new file mode 100644 index 0000000..ddef9ce --- /dev/null +++ b/lib/data/services/carton_service.dart @@ -0,0 +1,7 @@ +import 'package:fcs/domain/entities/carton.dart'; + +abstract class CartonService { + Future createCarton(Carton carton); + Future updateCarton(Carton carton); + Future deleteCarton(Carton carton); +} diff --git a/lib/data/services/fcs_shipment_imp.dart b/lib/data/services/fcs_shipment_imp.dart index 648aaed..4eb5e94 100644 --- a/lib/data/services/fcs_shipment_imp.dart +++ b/lib/data/services/fcs_shipment_imp.dart @@ -28,4 +28,9 @@ class FcsShipmentServiceImp implements FcsShipmentService { Future deleteFcsShipment(FcsShipment fcsShipment) { return shipmentDataProvider.deleteFcsShipment(fcsShipment); } + + @override + Future ship(FcsShipment fcsShipment) { + return shipmentDataProvider.ship(fcsShipment); + } } diff --git a/lib/data/services/fcs_shipment_service.dart b/lib/data/services/fcs_shipment_service.dart index 32a67c4..46e4ba8 100644 --- a/lib/data/services/fcs_shipment_service.dart +++ b/lib/data/services/fcs_shipment_service.dart @@ -4,4 +4,5 @@ abstract class FcsShipmentService { Future createFcsShipment(FcsShipment fcsShipment); Future updateFcsShipment(FcsShipment fcsShipment); Future deleteFcsShipment(FcsShipment fcsShipment); + Future ship(FcsShipment fcsShipment); } diff --git a/lib/data/services/services.dart b/lib/data/services/services.dart index 57e39c1..70471d8 100644 --- a/lib/data/services/services.dart +++ b/lib/data/services/services.dart @@ -1,4 +1,5 @@ import 'package:fcs/data/provider/auth_fb.dart'; +import 'package:fcs/data/provider/carton_data_provider.dart'; import 'package:fcs/data/provider/common_data_provider.dart'; import 'package:fcs/data/provider/delivery_address_data_provider.dart'; import 'package:fcs/data/provider/fcs_shipment_data_provider.dart'; @@ -6,6 +7,8 @@ import 'package:fcs/data/provider/package_data_provider.dart'; import 'package:fcs/data/provider/rate_data_provider.dart'; import 'package:fcs/data/provider/shipment_data_provider.dart'; import 'package:fcs/data/provider/user_data_provider.dart'; +import 'package:fcs/data/services/carton_imp.dart'; +import 'package:fcs/data/services/carton_service.dart'; import 'package:fcs/data/services/delivery_address_imp.dart'; import 'package:fcs/data/services/delivery_address_service.dart'; import 'package:fcs/data/services/fcs_shipment_imp.dart'; @@ -38,6 +41,7 @@ class Services { DeliveryAddressService _deliveryAddressService; RateService _rateService; ShipmentService _shipmentService; + CartonService _cartonService; Services._() { _authService = AuthServiceImp( authFb: AuthFb.instance, @@ -59,6 +63,8 @@ class Services { _shipmentService = ShipmentServiceImp( shipmentDataProvider: ShipmentDataProvider.instance, connectivity: null); + _cartonService = CartonServiceImp( + cartonDataProvider: CartonDataProvider.instance, connectivity: null); } AuthService get authService => _authService; @@ -70,4 +76,5 @@ class Services { DeliveryAddressService get deliveryAddressService => _deliveryAddressService; RateService get rateService => _rateService; ShipmentService get shipmentService => _shipmentService; + CartonService get cartonService => _cartonService; } diff --git a/lib/data/services/shipment_imp.dart b/lib/data/services/shipment_imp.dart index 05d45b5..8aeb11d 100644 --- a/lib/data/services/shipment_imp.dart +++ b/lib/data/services/shipment_imp.dart @@ -1,16 +1,9 @@ -import 'package:fcs/data/provider/rate_data_provider.dart'; import 'package:fcs/data/provider/shipment_data_provider.dart'; import 'package:fcs/data/services/shipment_service.dart'; -import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/connectivity.dart'; -import 'package:fcs/domain/entities/discount_by_weight.dart'; -import 'package:fcs/domain/entities/custom_duty.dart'; -import 'package:fcs/domain/entities/rate.dart'; import 'package:fcs/domain/entities/shipment.dart'; import 'package:flutter/material.dart'; -import 'rate_service.dart'; - class ShipmentServiceImp implements ShipmentService { ShipmentServiceImp({ @required this.shipmentDataProvider, @@ -49,4 +42,39 @@ class ShipmentServiceImp implements ShipmentService { Future updateShipment(Shipment shipment) { return shipmentDataProvider.updateShipment(shipment); } + + @override + Future assignShipment(Shipment shipment) { + return shipmentDataProvider.assignShipment(shipment); + } + + @override + Future completeAssignShipment(Shipment shipment) { + return shipmentDataProvider.completeAssignShipment(shipment); + } + + @override + Future completePickupShipment(Shipment shipment) { + return shipmentDataProvider.completePickupShipment(shipment); + } + + @override + Future completePackShipment(Shipment shipment) { + return shipmentDataProvider.completePackShipment(shipment); + } + + @override + Future packShipment(Shipment shipment) { + return shipmentDataProvider.packShipment(shipment); + } + + @override + Future completeConfirmShipment(Shipment shipment) { + return shipmentDataProvider.completeConfirmShipment(shipment); + } + + @override + Future completeReceiveShipment(Shipment shipment) { + return shipmentDataProvider.completeReceiveShipment(shipment); + } } diff --git a/lib/data/services/shipment_service.dart b/lib/data/services/shipment_service.dart index 31b56ea..7761416 100644 --- a/lib/data/services/shipment_service.dart +++ b/lib/data/services/shipment_service.dart @@ -5,6 +5,13 @@ abstract class ShipmentService { Future updateShipment(Shipment shipment); Future cancelShipment(Shipment shipment); Future confirmShipment(Shipment shipment); + Future completeConfirmShipment(Shipment shipment); + Future completeReceiveShipment(Shipment shipment); Future pickupShipment(Shipment shipment); Future receiveShipment(Shipment shipment); + Future assignShipment(Shipment shipment); + Future completeAssignShipment(Shipment shipment); + Future completePickupShipment(Shipment shipment); + Future packShipment(Shipment shipment); + Future completePackShipment(Shipment shipment); } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index b461a54..672db0a 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -25,6 +25,7 @@ const user_disabled_status = "disabled"; const user_joined_status = "joined"; const pkg_files_path = "/packages"; +const shipment_labels_files_path = "/shipment_labels"; // Link page const page_payment_methods = "payment_methods"; @@ -75,7 +76,9 @@ const carton_mix_box = "Mix carton"; // shipment status const shipment_pending_status = "pending"; +const shipment_assigned_status = "assigned"; const shipment_confirmed_status = "confirmed"; +const shipment_received_status = "received"; const shipment_pickuped_status = "pickuped"; const shipment_packed_status = "packed"; const shipment_shipped_status = "shipped"; diff --git a/lib/domain/entities/carton.dart b/lib/domain/entities/carton.dart index 9302b5a..b10c3e8 100644 --- a/lib/domain/entities/carton.dart +++ b/lib/domain/entities/carton.dart @@ -28,6 +28,9 @@ class Carton { String cartonType; String fcsID; String userName; + String userID; + String fcsShipmentID; + String fcsShipmentNumber; int rate; int weight; @@ -36,6 +39,7 @@ class Carton { List photos; String remark; DateTime arrivedDate; + String cartonNumber; List packages; @@ -109,6 +113,7 @@ class Carton { this.isChecked = false, this.cartonType, this.fcsID, + this.userID, this.userName, this.rate = 0, this.weight = 0, @@ -121,13 +126,18 @@ class Carton { this.shipmentHistory, this.packages, this.cargoTypes, + this.cartonNumber, + this.fcsShipmentID, + this.fcsShipmentNumber, this.deliveryAddress}); Map toMap() { List _cargoTypes = cargoTypes.map((c) => c.toMap()).toList(); + List _packages = packages.map((c) => c.toJson()).toList(); return { "id": id, 'cargo_types': _cargoTypes, + 'packages': _packages, 'length': length, 'width': width, 'height': height, @@ -155,6 +165,10 @@ class Carton { userName: map['user_name'], fcsID: map['fcs_id'], cartonType: map['carton_type'], + cartonNumber: map['carton_number'], + status: map['status'], + fcsShipmentID: map['fcs_shipment_id'], + fcsShipmentNumber: map['fcs_shipment_number'], deliveryAddress: _da, cargoTypes: cargoTypes); } diff --git a/lib/domain/entities/package.dart b/lib/domain/entities/package.dart index 25679c6..311ff60 100644 --- a/lib/domain/entities/package.dart +++ b/lib/domain/entities/package.dart @@ -1,4 +1,5 @@ import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/domain/vo/shipment_status.dart'; class Package { @@ -13,7 +14,6 @@ class Package { List photoUrls; List shipmentHistory; String desc; - String deliveryAddressID; String status; String shipmentNumber; @@ -35,6 +35,7 @@ class Package { List photos; String remark; DateTime arrivedDate; + DeliveryAddress deliveryAddress; int get amount => rate != null && weight != null ? rate * weight : 0; @@ -71,17 +72,19 @@ class Package { this.currentStatusDate, this.photoUrls, this.desc, - this.deliveryAddressID, + this.deliveryAddress, this.isChecked = false}); factory Package.fromMap(Map map, String docID) { - var _currentStatusDate = (map['current_status_date'] as Timestamp); + var _currentStatusDate = (map['status_date'] as Timestamp); List _shipmentStatus = List.from(map['all_status']) .map((e) => ShipmentStatus.fromMap(Map.from(e))) .toList(); List _photoUrls = map['photo_urls'] == null ? [] : List.from(map['photo_urls']); + var da = map['delivery_address']; + var _da = da != null ? DeliveryAddress.fromMap(da, da["id"]) : null; return Package( id: docID, @@ -93,8 +96,8 @@ class Package { phoneNumber: map['phone_number'], remark: map['remark'], desc: map['desc'], - currentStatus: map['current_status'], - deliveryAddressID: map['delivery_address_id'], + currentStatus: map['status'], + deliveryAddress: _da, currentStatusDate: _currentStatusDate != null ? _currentStatusDate.toDate() : null, photoUrls: _photoUrls, @@ -118,8 +121,8 @@ class Package { market: json['market'], userName: json['user_name'], phoneNumber: json['phone_number'], - currentStatus: json['current_status'], - currentStatusDate: DateTime.parse(json['current_status_date'])); + currentStatus: json['status'], + currentStatusDate: DateTime.parse(json['status_date'])); } @override diff --git a/lib/domain/entities/shipment.dart b/lib/domain/entities/shipment.dart index d9c29cb..2b2094c 100644 --- a/lib/domain/entities/shipment.dart +++ b/lib/domain/entities/shipment.dart @@ -1,4 +1,5 @@ import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; @@ -15,13 +16,21 @@ class Shipment { String phoneNumber; int numberOfPackage; int weight; - int handlingFee; + double handlingFee; String address; - String currentStatus; + String status; bool isCourier; int radioIndex; List boxes; + String pickupUserID; + String pickupUserName; + String pickupUserPhoneNumber; + + String fcsShipmentID; + String fcsShipmentNumber; + String shipmentLabelUrl; + Shipment( {this.id, this.shipmentNumber, @@ -34,15 +43,31 @@ class Shipment { this.weight, this.handlingFee, this.address, - this.currentStatus, + this.status, this.pickupDate, this.isCourier = false, this.radioIndex = 1, this.pickupAddress, + this.pickupUserID, + this.pickupUserName, + this.pickupUserPhoneNumber, + this.fcsShipmentID, + this.fcsShipmentNumber, + this.shipmentLabelUrl, this.boxes}); int get last => DateTime.now().difference(pickupDate).inDays; + double get totalWeight => boxes?.fold(0, (p, e) => p + e.actualWeight); + int get totalCount => boxes?.length; + + bool get isPending => status == shipment_pending_status; + bool get isAssigned => status == shipment_assigned_status; + bool get isPickuped => status == shipment_pickuped_status; + bool get isPacked => status == shipment_packed_status; + bool get isConfirmed => status == shipment_confirmed_status; + bool get isReceived => status == shipment_received_status; + factory Shipment.fromMap(Map map, String id) { var pd = (map['pickup_date'] as Timestamp); var pa = map['pickup_address']; @@ -55,8 +80,15 @@ class Shipment { pickupDate: pd == null ? null : pd.toDate(), pickupTimeStart: map['pickup_time_start'], pickupTimeEnd: map['pickup_time_end'], - currentStatus: map['current_status'], + status: map['status'], shipmentType: map['shipment_type'], + pickupUserID: map['pickup_user_id'], + pickupUserName: map['pickup_user_name'], + pickupUserPhoneNumber: map['pickup_user_phone_number'], + handlingFee: map['handling_fee'], + fcsShipmentID: map['fcs_shipment_id'], + fcsShipmentNumber: map['fcs_shipment_number'], + shipmentLabelUrl: map['shipment_label_url'], pickupAddress: _pa); } @@ -71,11 +103,17 @@ class Shipment { "pickup_date": pickupDate?.toUtc()?.toIso8601String(), 'pickup_time_start': pickupTimeStart, 'pickup_time_end': pickupTimeEnd, + 'pickup_user_id': pickupUserID, + 'pickup_user_name': pickupUserName, + 'pickup_user_phone_number': pickupUserPhoneNumber, + 'handling_fee': handlingFee, + 'fcs_shipment_id': fcsShipmentID, + 'shipment_label_url': shipmentLabelUrl }; } @override String toString() { - return 'PickUp{id:$id, userName:$userName,phoneNumber:$phoneNumber,numberOfPackage:$numberOfPackage,weight:$weight,currentStatus:$currentStatus}'; + return 'PickUp{id:$id, userName:$userName,phoneNumber:$phoneNumber,numberOfPackage:$numberOfPackage,weight:$weight,status:$status}'; } } diff --git a/lib/pages/carton/cargo_type_editor.dart b/lib/pages/carton/cargo_type_editor.dart index e2e9cc7..8ef809d 100644 --- a/lib/pages/carton/cargo_type_editor.dart +++ b/lib/pages/carton/cargo_type_editor.dart @@ -66,6 +66,7 @@ class _CargoTypeEditorState extends State { _cargo = v; }); }, + labelKey: "cargo.type", iconData: Icons.text_format, selectedValue: _cargo, values: cargos, diff --git a/lib/pages/carton/box_editor.dart b/lib/pages/carton/carton_editor.dart similarity index 56% rename from lib/pages/carton/box_editor.dart rename to lib/pages/carton/carton_editor.dart index 09c6865..1d37caa 100644 --- a/lib/pages/carton/box_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -1,6 +1,7 @@ import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; @@ -8,6 +9,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; +import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart'; @@ -21,9 +23,11 @@ import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/length_picker.dart'; import 'package:fcs/pages/widgets/local_button.dart'; +import 'package:fcs/pages/widgets/local_dropdown.dart'; import 'package:fcs/pages/widgets/local_radio_buttons.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_title.dart'; +import 'package:fcs/pages/widgets/my_data_table.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -32,54 +36,38 @@ import 'package:provider/provider.dart'; import 'cargo_type_editor.dart'; import 'model/carton_model.dart'; -class BoxEditor extends StatefulWidget { +class CartonEditor extends StatefulWidget { final Carton box; - BoxEditor({this.box}); + CartonEditor({this.box}); @override - _BoxEditorState createState() => _BoxEditorState(); + _CartonEditorState createState() => _CartonEditorState(); } -class _BoxEditorState extends State { +class _CartonEditorState extends State { TextEditingController _widthController = new TextEditingController(); TextEditingController _heightController = new TextEditingController(); TextEditingController _lengthController = new TextEditingController(); Carton _box; bool _isLoading = false; - bool isNew; + bool _isNew; DeliveryAddress _deliveryAddress = new DeliveryAddress(); - User user; - String _selectShipmentNumber; + User _user; String _selectedCartonType; List _packages = []; - List _shipmentBoxes = []; List _mixBoxes = []; - List _cargoTypes = []; double volumetricRatio = 0; double shipmentWeight = 0; - Carton _selectedShipmentBox; + FcsShipment _fcsShipment; + List _fcsShipments; @override void initState() { super.initState(); - // for packages - var packageModel = Provider.of(context, listen: false); - _packages = [ - // packageModel.packages[0], - // packageModel.packages[1], - ]; - _packages.forEach((p) { - p.isChecked = false; - }); //for shipment boxes var boxModel = Provider.of(context, listen: false); - _shipmentBoxes = [ - boxModel.boxeList[0], - boxModel.boxeList[1], - boxModel.boxeList[2] - ]; //for mix boxes _mixBoxes = [ @@ -102,29 +90,72 @@ class _BoxEditorState extends State { if (widget.box != null) { _box = widget.box; _deliveryAddress = _box.deliveryAddress; - _cargoTypes = _box.cargoTypes; - _selectShipmentNumber = _box.shipmentNumber; _widthController.text = _box.width.toString(); _heightController.text = _box.height.toString(); _lengthController.text = _box.length.toString(); _selectedCartonType = _box.cartonType; - isNew = false; - user = User(fcsID: _box.fcsID, name: _box.userName); + _isNew = false; + _user = User(fcsID: _box.fcsID, name: _box.userName); } else { - _cargoTypes = [ - CargoType(id: "1", name: 'General', weight: 25), - CargoType(id: "2", name: 'Medicine', weight: 20), - CargoType(id: "3", name: 'Dangerous', weight: 30) - ]; - - var shipmentModel = - Provider.of(context, listen: false); - _deliveryAddress = shipmentModel.defalutAddress; - isNew = true; + _box = Carton(cargoTypes: []); + _lengthController.text = "12"; + _widthController.text = "12"; + _heightController.text = "12"; + _isNew = true; _selectedCartonType = carton_from_packages; + _loadFcsShipments(); } } + _loadFcsShipments() async { + FcsShipmentModel fcsShipmentModel = + Provider.of(context, listen: false); + var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); + var fcsShipment = fcsShipments.firstWhere((e) => e.id == _box.fcsShipmentID, + orElse: () => null); + setState(() { + _fcsShipments = fcsShipments; + _fcsShipment = fcsShipment; + }); + } + + _loadPackages() async { + if (_user == null) return; + PackageModel packageModel = + Provider.of(context, listen: false); + List packages = await packageModel.getPackages(_user.id); + String prevCompare; + packages.forEach((p) { + String compare = (p.deliveryAddress?.fullName ?? "") + + (p.deliveryAddress?.phoneNumber ?? ""); + if (prevCompare != null && compare == prevCompare) { + p.isChecked = true; + } else { + p.isChecked = false; + } + if (prevCompare == null) { + p.isChecked = true; + prevCompare = compare; + } + }); + + setState(() { + _packages = packages; + }); + _populateDeliveryAddress(); + } + + _populateDeliveryAddress() { + if (_packages == null) return; + var d = _packages + .firstWhere((p) => p.isChecked && p.deliveryAddress != null, + orElse: () => null) + ?.deliveryAddress; + setState(() { + _deliveryAddress = d; + }); + } + _calShipmentWeight() { double l = double.parse(_lengthController.text, (s) => 0); double w = double.parse(_widthController.text, (s) => 0); @@ -141,42 +172,26 @@ class _BoxEditorState extends State { @override Widget build(BuildContext context) { - var languageModel = Provider.of(context); var boxModel = Provider.of(context); - var shipmentBox = Container( - child: DropdownButtonFormField( - value: _selectShipmentNumber, - decoration: InputDecoration( - fillColor: Colors.white, - labelText: AppTranslations.of(context).text("box.fcs_shipment_num"), - labelStyle: languageModel.isEng - ? TextStyle(fontWeight: FontWeight.w500) - : TextStyle(fontWeight: FontWeight.w500, fontFamily: "Myanmar3"), - icon: Icon( - Ionicons.ios_airplane, - color: primaryColor, - )), - items: ["A204", "A203", "A201", "A202"] - .map((e) => DropdownMenuItem( - child: Text( - e, - style: TextStyle(color: primaryColor), - ), - value: e)) - .toList(), - onChanged: (value) { + var fcsShipmentsBox = LocalDropdown( + callback: (v) { setState(() { - _selectShipmentNumber = value; + _fcsShipment = v; }); }, - )); + labelKey: "shipment.pack.fcs.shipment", + iconData: MaterialCommunityIcons.worker, + display: (u) => u.shipmentNumber, + selectedValue: _fcsShipment, + values: _fcsShipments, + ); final fcsIDBox = Row( children: [ Expanded( child: DisplayText( - text: user != null ? user.fcsID : "", + text: _user?.fcsID ?? "", labelTextKey: "box.fcs.id", icon: FcsIDIcon(), )), @@ -184,20 +199,15 @@ class _BoxEditorState extends State { icon: Icon(Icons.search, color: primaryColor), onPressed: () => searchUser(context, callbackUserSelect: (u) { setState(() { - this.user = u; + this._user = u; + _loadPackages(); }); })), ], ); - final phoneNumberBox = DisplayText( - text: user != null ? user.phoneNumber : "", - labelTextKey: "box.phone", - iconData: Icons.phone, - ); - final namebox = DisplayText( - text: user != null ? user.name : "", + text: _user?.name ?? "", labelTextKey: "box.name", iconData: Icons.person, ); @@ -241,23 +251,42 @@ class _BoxEditorState extends State { value: p.value.isChecked, activeColor: primaryColor, onChanged: (bool check) { + if (check && + _deliveryAddress != null && + p.value.deliveryAddress?.id != _deliveryAddress.id) { + return; + } setState(() { p.value.isChecked = check; }); + _populateDeliveryAddress(); }), Expanded( - child: new Text( - p.value.trackingID, - style: textStyle, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + p.value.trackingID, + style: textStyle, + ), + Text( + p.value.deliveryAddress?.fullName ?? "", + style: textStyle, + ), + Text( + p.value.deliveryAddress?.phoneNumber ?? "", + style: textStyle, + ), + ], )), new Column( children: [ new Text( - p.value.desc == null ? "" : p.value.desc, + p.value?.desc ?? "", style: textStyle, ), new Text( - "(${p.value.market == null ? "" : p.value.market})", + "(${p.value?.market ?? ""})", style: textStyle, ) ], @@ -269,66 +298,6 @@ class _BoxEditorState extends State { }).toList(); } - final shipmentBoxTitle = Container( - padding: EdgeInsets.only(right: 10.0, top: 20), - child: Row( - children: [ - Container( - width: 30, - ), - Expanded( - child: - LocalText(context, 'box.shipment_number', color: Colors.grey), - ), - LocalText(context, 'box.shipment.desc', color: Colors.grey), - ], - ), - ); - - List getshipmentBoxRowList() { - return _shipmentBoxes.asMap().entries.map((s) { - return Container( - color: Colors.grey[50].withOpacity(0.2), - child: Container( - padding: - EdgeInsets.only(left: 0.0, right: 10.0, top: 3.0, bottom: 3.0), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: s.key == _shipmentBoxes.length - 1 - ? Colors.white - : Colors.grey[350], - width: 1), - ), - ), - child: Row( - children: [ - Radio( - activeColor: primaryColor, - groupValue: _selectedShipmentBox, - value: s.value, - onChanged: (value) { - setState(() { - _selectedShipmentBox = value; - }); - }, - ), - Expanded( - child: new Text( - s.value.shipmentNumber, - style: textStyle, - )), - new Text( - s.value.desc == null ? "" : s.value.desc, - style: textStyle, - ), - ], - ), - ), - ); - }).toList(); - } - final mixBoxTitle = Container( padding: EdgeInsets.only(right: 10.0, top: 20), child: Row( @@ -388,113 +357,6 @@ class _BoxEditorState extends State { }).toList(); } - final cargoTitle = Container( - padding: EdgeInsets.only(left: 15, right: 0.0, top: 20), - child: Row( - children: [ - Expanded( - child: LocalText(context, 'cargo.type', color: Colors.grey), - ), - Container( - padding: EdgeInsets.only(right: 20), - child: LocalText(context, 'cargo.weight', color: Colors.grey)), - ], - ), - ); - - List getCargoRowList() { - if (_cargoTypes == null) { - return []; - } - double total = 0; - - var rows = _cargoTypes.asMap().entries.map((c) { - total += c.value.weight; - return InkWell( - onTap: () async { - CargoType cargo = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => CargoTypeEditor(cargo: c.value)), - ); - _addCargo(cargo); - }, - child: Container( - color: Colors.grey[50].withOpacity(0.2), - child: Container( - padding: EdgeInsets.only( - left: 15.0, right: 0.0, top: 0.0, bottom: 0.0), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.grey[350], width: 1), - ), - ), - child: Row( - children: [ - Expanded( - child: new Text( - c.value.name, - style: textStyle, - )), - Row( - children: [ - new Text( - c.value.weight == null - ? "0" - : c.value.weight.toString(), - style: textStyle, - ), - IconButton( - icon: Icon( - Icons.remove_circle, - color: primaryColor, - ), - onPressed: () { - setState(() { - _cargoTypes.remove(c.value); - }); - }, - ) - ], - ) - ], - ), - ), - ), - ); - }).toList(); - - var totalRow = InkWell( - child: Container( - color: Colors.grey[50].withOpacity(0.2), - child: Container( - padding: - EdgeInsets.only(left: 15.0, right: 10.0, top: 15.0, bottom: 15.0), - child: Row( - children: [ - Expanded( - child: LocalText(context, "box.cargo.total", - color: Colors.black87, fontWeight: FontWeight.bold), - ), - Padding( - padding: const EdgeInsets.only(right: 40.0), - child: Align( - alignment: Alignment.centerRight, - child: new Text( - total.toString(), - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - )); - - rows.add(totalRow); - return rows; - } - final lengthBox = LengthPicker( controller: _lengthController, lableKey: "box.length", @@ -538,6 +400,15 @@ class _BoxEditorState extends State { final deliveryBtn = LocalButton( textKey: "box.deliver.btn", ); + final cartonTypeBox = LocalRadioButtons( + values: boxModel.cartonTypes, + selectedValue: _selectedCartonType, + callback: (v) { + print(v); + setState(() { + _selectedCartonType = v; + }); + }); return LocalProgress( inAsyncCall: _isLoading, @@ -565,34 +436,20 @@ class _BoxEditorState extends State { ), ), body: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.all(8.0), child: ListView( shrinkWrap: true, children: [ - widget.box == null - ? Container() - : Center(child: nameWidget(_box.packageNumber)), - SizedBox( - height: 10, - ), LocalTitle(textKey: "box.type.title"), - LocalRadioButtons( - values: boxModel.cartonTypes, - selectedValue: _selectedCartonType, - callback: (v) { - print(v); - setState(() { - _selectedCartonType = v; - }); - }), + cartonTypeBox, LocalTitle(textKey: "box.shipment_info"), - shipmentBox, + fcsShipmentsBox, SizedBox( height: 10, ), fcsIDBox, namebox, - _selectedCartonType == "From packages" + _selectedCartonType == carton_from_packages ? Column( children: [ LocalTitle(textKey: "box.packages"), @@ -605,35 +462,22 @@ class _BoxEditorState extends State { ), ], ) - : _selectedCartonType == "From shipments" + : _selectedCartonType == carton_mix_box ? Column( children: [ LocalTitle(textKey: "box.shipment.boxes"), - shipmentBoxTitle, + mixBoxTitle, Divider( color: Colors.grey[400], ), Column( - children: getshipmentBoxRowList(), - ), + children: getMixBoxRowList(), + ) ], ) - : _selectedCartonType == "Mix carton" - ? Column( - children: [ - LocalTitle(textKey: "box.shipment.boxes"), - mixBoxTitle, - Divider( - color: Colors.grey[400], - ), - Column( - children: getMixBoxRowList(), - ) - ], - ) - : Container(), + : Container(), LocalTitle( - textKey: "box.cargo_type", + textKey: "box.cargo.type", trailing: IconButton( icon: Icon( Icons.add_circle, @@ -641,43 +485,39 @@ class _BoxEditorState extends State { ), onPressed: () async { CargoType cargo = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => CargoTypeEditor()), - ); - + context, + CupertinoPageRoute( + builder: (context) => CargoTypeEditor())); _addCargo(cargo); }), ), - cargoTitle, - Divider( - color: Colors.grey[400], - ), - Column( - children: getCargoRowList(), + MyDataTable( + headingRowHeight: 40, + columns: [ + MyDataColumn( + label: LocalText( + context, + "cargo.type", + color: Colors.grey, + ), + ), + MyDataColumn( + label: LocalText( + context, + "cargo.weight", + color: Colors.grey, + ), + ), + ], + rows: getCargoRows(context), ), LocalTitle(textKey: "box.dimension"), dimBox, shipmentWeightBox, LocalTitle(textKey: "box.delivery_address"), DefaultDeliveryAddress( - deliveryAddress: _deliveryAddress, - labelKey: "box.delivery_address", - onTap: () async { - DeliveryAddress d = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => DeliveryAddressSelection( - deliveryAddress: _deliveryAddress, - )), - ); - if (d == null) return; - setState(() { - this._deliveryAddress = d; - }); - }), - SizedBox( - height: 10, + deliveryAddress: _deliveryAddress, + labelKey: "box.delivery_address", ), widget.box == null ? createBtn @@ -700,6 +540,75 @@ class _BoxEditorState extends State { ); } + List getCargoRows(BuildContext context) { + if (_box?.cargoTypes == null) { + return []; + } + double total = 0; + var rows = _box.cargoTypes.map((c) { + total += c.weight; + return MyDataRow( + onSelectChanged: (bool selected) async { + CargoType cargo = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CargoTypeEditor( + cargo: c, + ))); + _addCargo(cargo); + }, + cells: [ + MyDataCell(new Text( + c.name == null ? "" : c.name, + style: textStyle, + )), + MyDataCell( + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text(c.weight == null ? "0" : c.weight.toString(), + style: textStyle), + IconButton( + icon: Icon( + Icons.remove_circle, + color: primaryColor, + ), + onPressed: () => {_removeCargo(c)}, + ) + ], + ), + ), + ], + ); + }).toList(); + + var totalRow = MyDataRow( + onSelectChanged: (bool selected) {}, + cells: [ + MyDataCell(Align( + alignment: Alignment.centerRight, + child: LocalText( + context, + "shipment.cargo.total", + color: Colors.black87, + fontWeight: FontWeight.bold, + ), + )), + MyDataCell( + Padding( + padding: const EdgeInsets.only(right: 48.0), + child: Align( + alignment: Alignment.centerRight, + child: Text(total.toString(), + style: TextStyle(fontWeight: FontWeight.bold))), + ), + ), + ], + ); + rows.add(totalRow); + return rows; + } + List getAddressList( BuildContext context, List addresses) { return addresses.asMap().entries.map((s) { @@ -713,8 +622,49 @@ class _BoxEditorState extends State { _addCargo(CargoType cargo) { if (cargo == null) return; setState(() { - _cargoTypes.remove(cargo); - _cargoTypes.add(cargo); + _box.cargoTypes.remove(cargo); + _box.cargoTypes.add(cargo); }); } + + _removeCargo(CargoType cargo) { + setState(() { + _box.cargoTypes.remove(cargo); + }); + } + + _save() async { + _box.cartonType = _selectedCartonType; + _box.fcsShipmentID = _fcsShipment.id; + _box.userID = _user.id; + _box.packages = _packages.map((e) => e.isChecked ? e : null).toList(); + + double l = double.parse(_lengthController.text, (s) => 0); + double w = double.parse(_widthController.text, (s) => 0); + double h = double.parse(_heightController.text, (s) => 0); + _box.length = l; + _box.width = w; + _box.height = h; + _box.deliveryAddress = _deliveryAddress; + + setState(() { + _isLoading = true; + }); + try { + CartonModel cartonModel = + Provider.of(context, listen: false); + if (_isNew) { + await cartonModel.createCarton(_box); + } else { + await cartonModel.updateCarton(_box); + } + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/carton/box_info.dart b/lib/pages/carton/carton_info.dart similarity index 97% rename from lib/pages/carton/box_info.dart rename to lib/pages/carton/carton_info.dart index b491159..96425e7 100644 --- a/lib/pages/carton/box_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -21,20 +21,20 @@ import 'package:provider/provider.dart'; import 'package:timeline_list/timeline.dart'; import 'package:timeline_list/timeline_model.dart'; -import 'box_editor.dart'; +import 'carton_editor.dart'; import 'model/carton_model.dart'; final DateFormat dateFormat = DateFormat("d MMM yyyy"); -class BoxInfo extends StatefulWidget { +class CartonInfo extends StatefulWidget { final Carton box; - BoxInfo({this.box}); + CartonInfo({this.box}); @override - _BoxInfoState createState() => _BoxInfoState(); + _CartonInfoState createState() => _CartonInfoState(); } -class _BoxInfoState extends State { +class _CartonInfoState extends State { bool _isLoading = false; Carton _box; String _selectedCartonType; @@ -162,7 +162,7 @@ class _BoxInfoState extends State { SizedBox( width: 10, ), - Text(_selectedCartonType), + Text(_selectedCartonType ?? ""), ], ), ); @@ -469,7 +469,7 @@ class _BoxInfoState extends State { child: Padding( padding: const EdgeInsets.all(10.0), child: ListView(children: [ - Center(child: nameWidget(_box.packageNumber)), + // Center(child: nameWidget(_box.packageNumber)), SizedBox( height: 10, ), @@ -554,7 +554,7 @@ class _BoxInfoState extends State { _gotoEditor() async { Navigator.push( context, - CupertinoPageRoute(builder: (context) => BoxEditor(box: widget.box)), + CupertinoPageRoute(builder: (context) => CartonEditor(box: widget.box)), ); } } diff --git a/lib/pages/carton/box_list.dart b/lib/pages/carton/carton_list.dart similarity index 89% rename from lib/pages/carton/box_list.dart rename to lib/pages/carton/carton_list.dart index 7275279..bfece5b 100644 --- a/lib/pages/carton/box_list.dart +++ b/lib/pages/carton/carton_list.dart @@ -8,15 +8,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'box_editor.dart'; -import 'box_list_row.dart'; +import 'carton_editor.dart'; +import 'carton_list_row.dart'; -class BoxList extends StatefulWidget { +class CartonList extends StatefulWidget { @override - _BoxListState createState() => _BoxListState(); + _CartonListState createState() => _CartonListState(); } -class _BoxListState extends State { +class _CartonListState extends State { bool _isLoading = false; var _controller = ScrollController(); @@ -97,13 +97,15 @@ class _BoxListState extends State { controller: _controller, separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), shrinkWrap: true, itemCount: boxModel.boxes.length, itemBuilder: (BuildContext context, int index) { - return BoxListRow(box: boxModel.boxes[index]); + return CartonListRow( + key: ValueKey(boxModel.boxes[index].id), + box: boxModel.boxes[index]); }), onRefresh: () => boxModel.refresh(), ), @@ -131,7 +133,7 @@ class _BoxListState extends State { _newBox() { Navigator.push( context, - CupertinoPageRoute(builder: (context) => BoxEditor()), + CupertinoPageRoute(builder: (context) => CartonEditor()), ); } } diff --git a/lib/pages/carton/box_list_row.dart b/lib/pages/carton/carton_list_row.dart similarity index 70% rename from lib/pages/carton/box_list_row.dart rename to lib/pages/carton/carton_list_row.dart index f6d1fc6..b5b48ee 100644 --- a/lib/pages/carton/box_list_row.dart +++ b/lib/pages/carton/carton_list_row.dart @@ -1,19 +1,21 @@ import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; -import 'box_info.dart'; +import 'carton_info.dart'; -class BoxListRow extends StatefulWidget { +class CartonListRow extends StatefulWidget { final Carton box; - const BoxListRow({this.box}); + const CartonListRow({Key key, this.box}) : super(key: key); @override - _BoxListRowState createState() => _BoxListRowState(); + _CartonListRowState createState() => _CartonListRowState(); } -class _BoxListRowState extends State { +class _CartonListRowState extends State { final double dotSize = 15.0; Carton _box = new Carton(); final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); @@ -26,15 +28,15 @@ class _BoxListRowState extends State { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: InkWell( - onTap: () { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => BoxInfo(box: _box)), - ); - }, + return InkWell( + onTap: () { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => CartonInfo(box: _box)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), child: Row( children: [ Expanded( @@ -42,6 +44,14 @@ class _BoxListRowState extends State { padding: const EdgeInsets.symmetric(vertical: 16.0), child: new Row( children: [ + Container( + padding: EdgeInsets.only(left: 5, right: 10), + child: Icon( + MaterialCommunityIcons.package, + color: primaryColor, + size: 30, + ), + ), new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -49,9 +59,7 @@ class _BoxListRowState extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _box.packageNumber == null - ? '' - : _box.packageNumber, + _box.cartonNumber ?? "", style: new TextStyle( fontSize: 15.0, color: Colors.black), ), @@ -59,7 +67,7 @@ class _BoxListRowState extends State { Padding( padding: const EdgeInsets.only(left: 10.0, top: 10), child: new Text( - dateFormat.format(_box.arrivedDate), + _box.userName ?? "", style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), @@ -82,14 +90,7 @@ class _BoxListRowState extends State { child: Row( children: [ new Text( - _box.weight == null - ? '' - : _box.weight.toString() + 'lb - ', - style: - new TextStyle(fontSize: 15.0, color: Colors.grey), - ), - new Text( - _box.price == null ? "" : "\$ " + _box.price.toString(), + "${_box.actualWeight?.toString() ?? ''} lb", style: new TextStyle(fontSize: 15.0, color: Colors.grey), ), diff --git a/lib/pages/carton/model/carton_model.dart b/lib/pages/carton/model/carton_model.dart index d65e619..981bd01 100644 --- a/lib/pages/carton/model/carton_model.dart +++ b/lib/pages/carton/model/carton_model.dart @@ -1,6 +1,7 @@ import 'dart:async'; 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/carton.dart'; import 'package:fcs/domain/entities/cargo_type.dart'; @@ -312,11 +313,7 @@ class CartonModel extends BaseModel { }); } - List cartonTypes = [ - carton_from_packages, - carton_from_shipments, - carton_mix_box - ]; + List cartonTypes = [carton_from_packages, carton_mix_box]; set selectedIndex(int index) { _selectedIndex = index; @@ -430,4 +427,12 @@ class CartonModel extends BaseModel { .map((e) => Carton.fromMap(e.data, e.documentID)) .toList(); } + + Future createCarton(Carton carton) { + return Services.instance.cartonService.createCarton(carton); + } + + Future updateCarton(Carton carton) { + return Services.instance.cartonService.updateCarton(carton); + } } diff --git a/lib/pages/delivery/delivery_info.dart b/lib/pages/delivery/delivery_info.dart index ec58deb..58be46f 100644 --- a/lib/pages/delivery/delivery_info.dart +++ b/lib/pages/delivery/delivery_info.dart @@ -160,7 +160,7 @@ class _DeliveryInfoState extends State { SizedBox( width: 10, ), - Text(_selectedCartonType), + Text(_selectedCartonType ?? ""), ], ), ); @@ -467,7 +467,7 @@ class _DeliveryInfoState extends State { child: Padding( padding: const EdgeInsets.all(10.0), child: ListView(children: [ - Center(child: nameWidget(_box.packageNumber)), + // Center(child: nameWidget(_box.packageNumber)), SizedBox( height: 10, ), diff --git a/lib/pages/delivery/delivery_list.dart b/lib/pages/delivery/delivery_list.dart index 796e5bf..8e0d115 100644 --- a/lib/pages/delivery/delivery_list.dart +++ b/lib/pages/delivery/delivery_list.dart @@ -88,13 +88,14 @@ class _DeliverListState extends State { controller: _controller, separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), shrinkWrap: true, itemCount: deliveryModel.cartons.length, itemBuilder: (BuildContext context, int index) { return DeliveryListRow( + key: ValueKey(deliveryModel.cartons[index].id), box: deliveryModel.cartons[index]); }), onRefresh: () => deliveryModel.refresh(), diff --git a/lib/pages/delivery/delivery_list_row.dart b/lib/pages/delivery/delivery_list_row.dart index 84b7543..096b6e7 100644 --- a/lib/pages/delivery/delivery_list_row.dart +++ b/lib/pages/delivery/delivery_list_row.dart @@ -1,14 +1,16 @@ import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'delivery_info.dart'; class DeliveryListRow extends StatefulWidget { final Carton box; - const DeliveryListRow({this.box}); + const DeliveryListRow({Key key,this.box}):super(key:key); @override _DeliveryListRowState createState() => _DeliveryListRowState(); @@ -27,15 +29,15 @@ class _DeliveryListRowState extends State { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: InkWell( - onTap: () { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => DeliveryInfo(box: _box)), - ); - }, + return InkWell( + onTap: () { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DeliveryInfo(box: _box)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), child: Row( children: [ Expanded( @@ -43,6 +45,14 @@ class _DeliveryListRowState extends State { padding: const EdgeInsets.symmetric(vertical: 16.0), child: new Row( children: [ + Container( + padding: EdgeInsets.only(left: 5, right: 10), + child: Icon( + MaterialCommunityIcons.truck_fast, + color: primaryColor, + size: 30, + ), + ), new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -50,9 +60,7 @@ class _DeliveryListRowState extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _box.packageNumber == null - ? '' - : _box.packageNumber, + _box.cartonNumber ?? "", style: new TextStyle( fontSize: 15.0, color: Colors.black), ), @@ -60,7 +68,7 @@ class _DeliveryListRowState extends State { Padding( padding: const EdgeInsets.only(left: 10.0, top: 10), child: new Text( - dateFormat.format(_box.arrivedDate), + _box.userName ?? "", style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), @@ -83,14 +91,7 @@ class _DeliveryListRowState extends State { child: Row( children: [ new Text( - _box.weight == null - ? '' - : _box.weight.toString() + 'lb - ', - style: - new TextStyle(fontSize: 15.0, color: Colors.grey), - ), - new Text( - _box.price == null ? "" : "\$ " + _box.price.toString(), + "${_box.actualWeight?.toString() ?? ''} lb", style: new TextStyle(fontSize: 15.0, color: Colors.grey), ), diff --git a/lib/pages/discount/discount_list.dart b/lib/pages/discount/discount_list.dart index c21d749..0ecf773 100644 --- a/lib/pages/discount/discount_list.dart +++ b/lib/pages/discount/discount_list.dart @@ -1,5 +1,6 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/pages/discount/discount_list_row.dart'; import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -57,77 +58,14 @@ class _DiscountListState extends State { body: ListView.separated( separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), itemCount: discountModel.discounts.length, itemBuilder: (BuildContext context, int index) { var discount = discountModel.discounts[index]; - return InkWell( - onTap: () { - _selected - ? Navigator.pop(context, discount) - : Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => DiscountEditor( - discount: discount, - )), - ); - }, - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Text( - discount.code, - style: TextStyle( - color: primaryColor, - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - Row( - children: [ - Text( - discount.customerName, - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.normal, - fontSize: 15), - ), - ], - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Padding( - padding: - const EdgeInsets.only(left: 10.0, bottom: 5.0), - child: Text( - '\$ ${discount.amount.toString()}', - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 16), - ), - ), - getStatus(discount.status), - ], - ), - ], - ), - ), + return DiscountListRow( + key: ValueKey(discount.id), + discount: discount, ); }, ), diff --git a/lib/pages/discount/discount_list_row.dart b/lib/pages/discount/discount_list_row.dart new file mode 100644 index 0000000..376d46f --- /dev/null +++ b/lib/pages/discount/discount_list_row.dart @@ -0,0 +1,109 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/discount.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/discount/discount_editor.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; + +class DiscountListRow extends StatefulWidget { + final Discount discount; + const DiscountListRow({Key key, this.discount}) : super(key: key); + + @override + _DiscountListRowState createState() => _DiscountListRowState(); +} + +class _DiscountListRowState extends State { + final double dotSize = 15.0; + Discount _discount; + final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); + + @override + void initState() { + super.initState(); + _discount = widget.discount; + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => DiscountEditor(discount: _discount)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: new Row( + children: [ + Container( + padding: EdgeInsets.only(left: 5, right: 10), + child: Icon( + Entypo.price_ribbon, + color: primaryColor, + size: 30, + ), + ), + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: new Text( + _discount.code ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10.0, top: 10), + child: new Text( + _discount.customerName ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ) + ], + ), + ), + ], + ), + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.all(0), + child: Text(_discount.status), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), + child: Row( + children: [ + new Text( + "${_discount.amount ?? ''}", + style: + new TextStyle(fontSize: 15.0, color: Colors.grey), + ), + ], + ), + ), + ], + ) + ], + ), + ), + ); + } +} diff --git a/lib/pages/fcs_shipment/fcs_shipment_info.dart b/lib/pages/fcs_shipment/fcs_shipment_info.dart index d181032..8010f1b 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_info.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_info.dart @@ -1,6 +1,10 @@ +import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; +import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/display_text.dart'; +import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/popupmenu.dart'; import 'package:fcs/pages/widgets/progress.dart'; @@ -9,6 +13,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; import 'fcs_shipment_editor.dart'; @@ -110,6 +115,11 @@ class _FcsShipmentInfoState extends State { iconData: Icons.av_timer, ); + final shipBtn = LocalButton( + textKey: "FCSshipment.ship.btn", + callBack: _ship, + ); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( @@ -151,6 +161,9 @@ class _FcsShipmentInfoState extends State { portBox, destinationBox, statusBox, + _fcsShipment.status == fcs_shipment_confirmed_status + ? shipBtn + : Container(), SizedBox( height: 20, ) @@ -203,4 +216,28 @@ class _FcsShipmentInfoState extends State { }).toList(); }); } + + _ship() { + showConfirmDialog(context, "FCSshipment.ship.confirm", () { + _shipFcsShipment(); + }); + } + + _shipFcsShipment() async { + setState(() { + _isLoading = true; + }); + try { + FcsShipmentModel fcsShipmentModel = + Provider.of(context, listen: false); + await fcsShipmentModel.ship(_fcsShipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/fcs_shipment/fcs_shipment_list.dart b/lib/pages/fcs_shipment/fcs_shipment_list.dart index 8acd33d..0ef23f6 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_list.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_list.dart @@ -40,11 +40,11 @@ class _FcsShipmentListState extends State { popmenus: [ LocalPopupMenu( id: 1, - textKey: "package.popupmenu.active", + textKey: "FCSshipment.popupmenu.active", selected: shipmentModel.selectedIndex == 1), LocalPopupMenu( id: 2, - textKey: "package.popupmenu.delivered", + textKey: "FCSshipment.popupmenu.delivered", selected: shipmentModel.selectedIndex == 2) ], popupMenuCallback: (p) => this.setState(() { @@ -83,9 +83,9 @@ class _FcsShipmentListState extends State { controller: _controller, separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), shrinkWrap: true, itemCount: shipmentModel.fcsShipments.length, itemBuilder: (BuildContext context, int index) { diff --git a/lib/pages/fcs_shipment/fcs_shipment_list_row.dart b/lib/pages/fcs_shipment/fcs_shipment_list_row.dart index 7b5146d..020b304 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_list_row.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_list_row.dart @@ -14,13 +14,13 @@ class FcsShipmentListRow extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: InkWell( - onTap: () { - Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => FcsShipmentInfo(fcsShipment: shipment))); - }, + return InkWell( + onTap: () { + Navigator.of(context).push(CupertinoPageRoute( + builder: (context) => FcsShipmentInfo(fcsShipment: shipment))); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), child: Row( children: [ Expanded( diff --git a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart index bc45964..36f9dc7 100644 --- a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart +++ b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart @@ -75,7 +75,7 @@ class FcsShipmentModel extends BaseModel { .collection("/$fcs_shipment_collection") .where("is_delivered", isEqualTo: true) .where("is_deleted", isEqualTo: false) - .orderBy("current_status_date", descending: true); + .orderBy("status_date", descending: true); var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { return FcsShipment.fromMap(data, id); }); @@ -98,6 +98,24 @@ class FcsShipmentModel extends BaseModel { }); } + Future> getActiveFcsShipments() async { + List fcsShipments = []; + try { + var snaps = await Firestore.instance + .collection("/$fcs_shipment_collection") + .where("status", isEqualTo: fcs_shipment_confirmed_status) + .getDocuments(source: Source.server); + fcsShipments = snaps.documents.map((documentSnapshot) { + var fcs = FcsShipment.fromMap( + documentSnapshot.data, documentSnapshot.documentID); + return fcs; + }).toList(); + } catch (e) { + log.warning("Error!! $e"); + } + return fcsShipments; + } + void initUser(user) { super.initUser(user); } @@ -116,4 +134,8 @@ class FcsShipmentModel extends BaseModel { Future update(FcsShipment fcsShipment) { return Services.instance.fcsShipmentService.updateFcsShipment(fcsShipment); } + + Future ship(FcsShipment fcsShipment) { + return Services.instance.fcsShipmentService.ship(fcsShipment); + } } diff --git a/lib/pages/invoice/invoce_list.dart b/lib/pages/invoice/invoce_list.dart index 1f412e9..03e02e9 100644 --- a/lib/pages/invoice/invoce_list.dart +++ b/lib/pages/invoice/invoce_list.dart @@ -1,21 +1,14 @@ -import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/invoice/invoice_shipment_list.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart'; -import 'package:fcs/pages/package_search/package_serach.dart'; -import 'package:fcs/pages/shipment/shipment_list.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:flutter/material.dart'; import 'invoice_list_row.dart'; class InvoiceList extends StatefulWidget { @@ -36,7 +29,8 @@ class _InvoiceListState extends State { super.initState(); _controller.addListener(() async { if (_controller.position.pixels == _controller.position.maxScrollExtent) { - Provider.of(context, listen: false).loadMore(isCustomer: widget.forCustomer); + Provider.of(context, listen: false) + .loadMore(isCustomer: widget.forCustomer); } }); diff --git a/lib/pages/invoice/model/invoice_model.dart b/lib/pages/invoice/model/invoice_model.dart index 354f814..12550d6 100644 --- a/lib/pages/invoice/model/invoice_model.dart +++ b/lib/pages/invoice/model/invoice_model.dart @@ -122,7 +122,7 @@ class InvoiceModel extends BaseModel { if (isCustomer) { pageQuery = pageQuery.where("user_id", isEqualTo: user.id); } - pageQuery = pageQuery.orderBy("current_status_date", descending: true); + pageQuery = pageQuery.orderBy("status_date", descending: true); var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { return Invoice.fromMap(data, id); }); diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index 237784a..95bc12b 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -7,7 +7,7 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/shared_pref.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/transalation.dart'; -import 'package:fcs/pages/carton/box_list.dart'; +import 'package:fcs/pages/carton/carton_list.dart'; import 'package:fcs/pages/chat/message_detail.dart'; import 'package:fcs/pages/chat/model/message_model.dart'; import 'package:fcs/pages/customer/customer_list.dart'; @@ -241,8 +241,8 @@ class _HomePageState extends State { CupertinoPageRoute(builder: (context) => ProcessingList()))); final cartonBtn = TaskButton("boxes.name", icon: MaterialCommunityIcons.package, - btnCallback: () => Navigator.of(context) - .push(CupertinoPageRoute(builder: (context) => BoxList()))); + btnCallback: () => Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => CartonList()))); final shipmentBtn = TaskButton("shipment", icon: SimpleLineIcons.direction, diff --git a/lib/pages/main/util.dart b/lib/pages/main/util.dart index 502581d..a6ccd3f 100644 --- a/lib/pages/main/util.dart +++ b/lib/pages/main/util.dart @@ -188,7 +188,7 @@ Widget getStatus(String status) { ], ) : Text( - status, + status ?? "", style: TextStyle( color: primaryColor, fontSize: 18, diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 00ea5fc..1a8a037 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -85,7 +85,7 @@ class PackageModel extends BaseModel { if (isCustomer) { pageQuery = pageQuery.where("user_id", isEqualTo: user.id); } - pageQuery = pageQuery.orderBy("current_status_date", descending: true); + pageQuery = pageQuery.orderBy("status_date", descending: true); var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { return Package.fromMap(data, id); }); @@ -199,6 +199,27 @@ class PackageModel extends BaseModel { return null; } + Future> getPackages(String userID) async { + List packages = []; + try { + var snaps = await Firestore.instance + .collection("/$packages_collection") + .where("status", isEqualTo: package_processed_status) + .where("user_id", isEqualTo: userID) + .where("is_deleted", isEqualTo: false) + .where("is_delivered", isEqualTo: false) + .getDocuments(source: Source.server); + packages = snaps.documents.map((documentSnapshot) { + var p = + Package.fromMap(documentSnapshot.data, documentSnapshot.documentID); + return p; + }).toList(); + } catch (e) { + log.warning("Error!! $e"); + } + return packages; + } + Future> searchUser(String term) { return Services.instance.userService.searchUser(term); } diff --git a/lib/pages/package/package_editor.dart b/lib/pages/package/package_editor.dart index d54a79b..15f7568 100644 --- a/lib/pages/package/package_editor.dart +++ b/lib/pages/package/package_editor.dart @@ -1,12 +1,11 @@ import 'package:fcs/domain/entities/market.dart'; import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/market/market_editor.dart'; import 'package:fcs/pages/market/model/market_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/tracking_id_page.dart'; -import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; diff --git a/lib/pages/package/package_info.dart b/lib/pages/package/package_info.dart index 2857d18..81313d1 100644 --- a/lib/pages/package/package_info.dart +++ b/lib/pages/package/package_info.dart @@ -34,7 +34,6 @@ class PackageInfo extends StatefulWidget { class _PackageInfoState extends State { var dateFormatter = new DateFormat('dd MMM yyyy'); Package _package; - DeliveryAddress _deliveryAddress; bool _isLoading = false; MultiImgController multiImgController = MultiImgController(); @@ -49,12 +48,6 @@ class _PackageInfoState extends State { _package = package; multiImgController.setImageUrls = package.photoUrls; }); - if (!widget.isSearchResult) { - DeliveryAddressModel deliveryAddressModel = - Provider.of(context, listen: false); - _deliveryAddress = deliveryAddressModel - .getLocalDeliveryAddress(package.deliveryAddressID); - } } @override @@ -103,7 +96,7 @@ class _PackageInfoState extends State { title: "Receipt File", ); final deliveryAddressBox = DefaultDeliveryAddress( - deliveryAddress: _deliveryAddress, + deliveryAddress: _package.deliveryAddress, labelKey: "package.delivery.address", onTap: owner ? () async { @@ -111,7 +104,7 @@ class _PackageInfoState extends State { context, CupertinoPageRoute( builder: (context) => DeliveryAddressSelection( - deliveryAddress: _deliveryAddress, + deliveryAddress: _package.deliveryAddress, )), ); if (d == null) return; @@ -185,7 +178,7 @@ class _PackageInfoState extends State { var da = await deliveryAddressModel.getDeliveryAddress(deliveryAddress.id); setState(() { - _deliveryAddress = da; + _package.deliveryAddress = da; }); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/processing/processing_list.dart b/lib/pages/processing/processing_list.dart index 61517eb..9a1d5f0 100644 --- a/lib/pages/processing/processing_list.dart +++ b/lib/pages/processing/processing_list.dart @@ -2,9 +2,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/package_search/package_serach.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; @@ -70,9 +68,9 @@ class _ProcessingListState extends State { body: new ListView.separated( separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), shrinkWrap: true, itemCount: packageModel.packages.length, itemBuilder: (BuildContext context, int index) { diff --git a/lib/pages/processing/processing_list_row.dart b/lib/pages/processing/processing_list_row.dart index 9f1f414..75b75b9 100644 --- a/lib/pages/processing/processing_list_row.dart +++ b/lib/pages/processing/processing_list_row.dart @@ -1,9 +1,9 @@ import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/pages/package/package_info.dart'; +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'processing_info.dart'; @@ -21,20 +21,20 @@ class ProcessingListRow extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: InkWell( - onTap: () { - if (callbackPackageSelect != null) { - callbackPackageSelect(package); - return; - } - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ProcessingInfo(package: package)), - ); - }, + return InkWell( + onTap: () { + if (callbackPackageSelect != null) { + callbackPackageSelect(package); + return; + } + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ProcessingInfo(package: package)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), child: Row( children: [ Expanded( @@ -42,6 +42,14 @@ class ProcessingListRow extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 16.0), child: new Row( children: [ + Container( + padding: EdgeInsets.only(left: 5, right: 10), + child: Icon( + FontAwesome.dropbox, + color: primaryColor, + size: 30, + ), + ), new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/receiving/receiving_list.dart b/lib/pages/receiving/receiving_list.dart index 7bd2c02..4d6ecee 100644 --- a/lib/pages/receiving/receiving_list.dart +++ b/lib/pages/receiving/receiving_list.dart @@ -25,6 +25,7 @@ class _ReceivingListState extends State { @override void initState() { super.initState(); + Provider.of(context, listen: false).initData(false); } @override @@ -81,9 +82,9 @@ class _ReceivingListState extends State { body: new ListView.separated( separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), shrinkWrap: true, itemCount: packageModel.packages.length, itemBuilder: (BuildContext context, int index) { diff --git a/lib/pages/receiving/receiving_list_row.dart b/lib/pages/receiving/receiving_list_row.dart index a6ab0b0..8bdef16 100644 --- a/lib/pages/receiving/receiving_list_row.dart +++ b/lib/pages/receiving/receiving_list_row.dart @@ -1,8 +1,9 @@ import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'receiving_info.dart'; @@ -20,20 +21,20 @@ class ReceivingListRow extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: InkWell( - onTap: () { - if (callbackPackageSelect != null) { - callbackPackageSelect(package); - return; - } - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ReceivingInfo(package: package)), - ); - }, + return InkWell( + onTap: () { + if (callbackPackageSelect != null) { + callbackPackageSelect(package); + return; + } + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ReceivingInfo(package: package)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), child: Row( children: [ Expanded( @@ -41,6 +42,12 @@ class ReceivingListRow extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 16.0), child: new Row( children: [ + Padding( + padding: EdgeInsets.all(5.0), + child: Icon( + MaterialCommunityIcons.inbox_arrow_down, + color: primaryColor, + )), new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/shipment/box_row.dart b/lib/pages/shipment/box_row.dart index 1739616..3568be2 100644 --- a/lib/pages/shipment/box_row.dart +++ b/lib/pages/shipment/box_row.dart @@ -84,6 +84,13 @@ class BoxRow extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: new Text( + "${box.cartonNumber ?? ""}", + style: new TextStyle(fontSize: 15.0, color: Colors.black), + ), + ), Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( diff --git a/lib/pages/shipment/model/shipment_model.dart b/lib/pages/shipment/model/shipment_model.dart index ebc0aaf..9563553 100644 --- a/lib/pages/shipment/model/shipment_model.dart +++ b/lib/pages/shipment/model/shipment_model.dart @@ -1,4 +1,7 @@ import 'dart:async'; +import 'dart:io'; +import 'package:fcs/helpers/firebase_helper.dart'; +import 'package:path/path.dart' as Path; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/data/services/services.dart'; @@ -31,10 +34,10 @@ class ShipmentModel extends BaseModel { get menuSelectedIndex => _menuSelectedIndex; - initData(bool forCustomer) { + initData(bool forCustomer, {bool myPickup = false}) { logout(); _menuSelectedIndex = 1; - _loadShipments(forCustomer); + _loadShipments(forCustomer, myPickup); _delivered = _getDeliveredExample(forCustomer); _delivered.load(); } @@ -80,7 +83,7 @@ class ShipmentModel extends BaseModel { if (isCustomer) { pageQuery = pageQuery.where("user_id", isEqualTo: user.id); } - pageQuery = pageQuery.orderBy("current_status_date", descending: true); + pageQuery = pageQuery.orderBy("status_date", descending: true); var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { return Shipment.fromMap(data, id); }); @@ -99,14 +102,14 @@ class ShipmentModel extends BaseModel { return Shipment( id: m.id, shipmentNumber: m.message, - currentStatus: m.senderName, + status: m.senderName, pickupDate: m.date, ); }); return paginator; } - Future _loadShipments(bool forCustomer) async { + Future _loadShipments(bool forCustomer, bool myPickup) async { if (user == null) return; if (!forCustomer && !user.hasShipment()) return; String path = "/$shipments_collection"; @@ -123,6 +126,10 @@ class ShipmentModel extends BaseModel { if (forCustomer) { q = q.where("user_id", isEqualTo: user.id); } + if (myPickup) { + q = q.where("pickup_user_id", isEqualTo: user.id); + } + q = q.orderBy("created_at", descending: true); listener = q.snapshots().listen((QuerySnapshot snapshot) { _shipments.clear(); @@ -175,4 +182,39 @@ class ShipmentModel extends BaseModel { Future cancelShipment(Shipment shipment) { return Services.instance.shipmentService.cancelShipment(shipment); } + + Future assignShipment(Shipment shipment) { + return Services.instance.shipmentService.assignShipment(shipment); + } + + Future completeAssignShipment(Shipment shipment) { + return Services.instance.shipmentService.completeAssignShipment(shipment); + } + + Future completePickupShipment(Shipment shipment) { + return Services.instance.shipmentService.completePickupShipment(shipment); + } + + Future completePackShipment(Shipment shipment) { + return Services.instance.shipmentService.completePackShipment(shipment); + } + + Future packShipment(Shipment shipment) { + return Services.instance.shipmentService.packShipment(shipment); + } + + Future confirmShipment(Shipment shipment) async { + // String path = Path.join(shipment_labels_files_path); + // String url = await uploadStorage(path, file); + // shipment.shipmentLabelUrl = url; + return Services.instance.shipmentService.confirmShipment(shipment); + } + + Future completeConfirmShipment(Shipment shipment) { + return Services.instance.shipmentService.completeConfirmShipment(shipment); + } + + Future completeReceiveShipment(Shipment shipment) { + return Services.instance.shipmentService.completeReceiveShipment(shipment); + } } diff --git a/lib/pages/shipment/shipment_assign.dart b/lib/pages/shipment/shipment_assign.dart new file mode 100644 index 0000000..5d160b2 --- /dev/null +++ b/lib/pages/shipment/shipment_assign.dart @@ -0,0 +1,167 @@ +import 'package:fcs/domain/constants.dart'; +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:fcs/domain/entities/user.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/shipment/model/shipment_model.dart'; +import 'package:fcs/pages/staff/model/staff_model.dart'; +import 'package:fcs/pages/widgets/input_text.dart'; +import 'package:fcs/pages/widgets/local_button.dart'; +import 'package:fcs/pages/widgets/local_dropdown.dart'; +import 'package:fcs/pages/widgets/local_radio_buttons.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/local_title.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import 'widgets.dart'; + +class ShipmentAssign extends StatefulWidget { + final Shipment shipment; + ShipmentAssign({this.shipment}); + + @override + _ShipmentAssignState createState() => _ShipmentAssignState(); +} + +class _ShipmentAssignState extends State { + var dateFormatter = new DateFormat('dd MMM yyyy'); + var timeFormatter = new DateFormat('jm'); + + TextEditingController _fromTimeEditingController = + new TextEditingController(); + TextEditingController _toTimeEditingController = new TextEditingController(); + TextEditingController _pickupDate = new TextEditingController(); + TextEditingController _handlingFee = new TextEditingController(); + + Shipment _shipment; + bool _isLoading = false; + var now = new DateTime.now(); + + String _selectedShipmentType; + User _user; + List _users; + + @override + void initState() { + super.initState(); + + _shipment = widget.shipment; + _loadUsers(); + + _selectedShipmentType = _shipment.shipmentType; + _fromTimeEditingController.text = _shipment.pickupTimeStart; + _toTimeEditingController.text = _shipment.pickupTimeEnd; + _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now); + _handlingFee.text = _shipment.handlingFee?.toString() ?? "0"; + } + + _loadUsers() async { + StaffModel staffModel = Provider.of(context, listen: false); + var users = await staffModel.getPickupEmployees(); + var selectUser = users.firstWhere((e) => e.id == _shipment.pickupUserID, + orElse: () => null); + setState(() { + _users = users; + _user = selectUser; + }); + } + + @override + Widget build(BuildContext context) { + ShipmentModel pickupModel = Provider.of(context); + final shipmentNumberBox = getShipmentNumberStatus(context, _shipment); + bool isLocalPickup = _selectedShipmentType == shipment_local_pickup; + bool isCourierPickup = _selectedShipmentType == shipment_courier_pickup; + bool isLocalDropoff = _selectedShipmentType == shipment_local_dropoff; + bool isCourierDropoff = _selectedShipmentType == shipment_courier_dropoff; + + var usersBox = LocalDropdown( + callback: (v) { + setState(() { + _user = v; + }); + }, + labelKey: "shipment.staff", + iconData: MaterialCommunityIcons.worker, + display: (u) => u.name, + selectedValue: _user, + values: _users, + ); + + final assignBtn = LocalButton( + textKey: "shipment.assign.btn", + callBack: _save, + ); + final handlingFeeBox = InputText( + labelTextKey: "shipment.handling.fee", + controller: _handlingFee, + iconData: FontAwesome.truck, + ); + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon( + CupertinoIcons.back, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "shipment.assign.title", + fontSize: 20, + color: primaryColor, + ), + ), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( + children: [ + Center(child: shipmentNumberBox), + SizedBox( + height: 10, + ), + LocalTitle(textKey: "shipment.assign.for.pickup"), + usersBox, + handlingFeeBox, + SizedBox( + height: 10, + ), + assignBtn, + ], + ), + ), + ), + ); + } + + _save() async { + _shipment.pickupUserID = this._user.id; + _shipment.handlingFee = double.tryParse(_handlingFee.text) ?? 0; + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.assignShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/shipment/shipment_confirm.dart b/lib/pages/shipment/shipment_confirm.dart new file mode 100644 index 0000000..5017eed --- /dev/null +++ b/lib/pages/shipment/shipment_confirm.dart @@ -0,0 +1,114 @@ +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/shipment/model/shipment_model.dart'; +import 'package:fcs/pages/widgets/input_text.dart'; +import 'package:fcs/pages/widgets/local_button.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import 'widgets.dart'; + +class ShipmentConfirm extends StatefulWidget { + final Shipment shipment; + ShipmentConfirm({this.shipment}); + + @override + _ShipmentConfirmState createState() => _ShipmentConfirmState(); +} + +class _ShipmentConfirmState extends State { + var dateFormatter = new DateFormat('dd MMM yyyy'); + var timeFormatter = new DateFormat('jm'); + TextEditingController _handlingFee = new TextEditingController(); + + Shipment _shipment; + bool _isLoading = false; + var now = new DateTime.now(); + + @override + void initState() { + super.initState(); + + _shipment = widget.shipment; + _handlingFee.text = _shipment.handlingFee?.toString() ?? "0"; + } + + @override + Widget build(BuildContext context) { + final shipmentNumberBox = getShipmentNumberStatus(context, _shipment); + + final handlingFeeBox = InputText( + labelTextKey: "shipment.handling.fee", + controller: _handlingFee, + iconData: FontAwesome.truck, + ); + final confirmbtn = LocalButton( + textKey: "shipment.confirm.btn", + callBack: _save, + ); + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon( + CupertinoIcons.back, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "shipment.confirm.menuitem", + fontSize: 20, + color: primaryColor, + ), + ), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( + children: [ + Center(child: shipmentNumberBox), + SizedBox( + height: 10, + ), + SizedBox( + height: 10, + ), + handlingFeeBox, + confirmbtn, + ], + ), + ), + ), + ); + } + + _save() async { + _shipment.handlingFee = double.tryParse(_handlingFee.text) ?? 0; + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.confirmShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/shipment/shipment_info.dart b/lib/pages/shipment/shipment_info.dart index d453daa..d9075c3 100644 --- a/lib/pages/shipment/shipment_info.dart +++ b/lib/pages/shipment/shipment_info.dart @@ -6,11 +6,11 @@ import 'package:fcs/pages/carton/model/carton_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/shipment/model/shipment_model.dart'; +import 'package:fcs/pages/shipment/shipment_pack.dart'; import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_button.dart'; -import 'package:fcs/pages/widgets/local_dropdown.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_radio_buttons.dart'; @@ -21,18 +21,20 @@ import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'box_row.dart'; +import 'shipment_assign.dart'; +import 'shipment_confirm.dart'; import 'shipment_editor.dart'; import 'widgets.dart'; class ShipmentInfo extends StatefulWidget { + final bool isCustomer; final Shipment shipment; - ShipmentInfo({this.shipment}); + ShipmentInfo({this.shipment, this.isCustomer}); @override _ShipmentInfoState createState() => _ShipmentInfoState(); @@ -62,24 +64,22 @@ class _ShipmentInfoState extends State { Shipment _shipment; bool _isLoading = false; + bool _isCustomer; var now = new DateTime.now(); @override void initState() { super.initState(); _shipment = widget.shipment; + _isCustomer = widget.isCustomer; _loadCartons(_shipment.id); - if (widget.shipment != null) { - _addressEditingController.text = _shipment.address; - _fromTimeEditingController.text = _shipment.pickupTimeStart; - _toTimeEditingController.text = _shipment.pickupTimeEnd; - _noOfPackageEditingController.text = _shipment.numberOfPackage.toString(); - _weightEditingController.text = _shipment.weight.toString(); - _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now); - // _handlingFeeController.text = - // numberFormatter.format(_shipment.handlingFee); - } + _addressEditingController.text = _shipment.address; + _fromTimeEditingController.text = _shipment.pickupTimeStart; + _toTimeEditingController.text = _shipment.pickupTimeEnd; + _noOfPackageEditingController.text = _shipment.numberOfPackage.toString(); + _weightEditingController.text = _shipment.weight.toString(); + _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now); } _loadCartons(String shipmentID) async { @@ -90,6 +90,16 @@ class _ShipmentInfoState extends State { }); } + _loadShipment(String id) async { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + Shipment s = await shipmentModel.getShipment(id); + s.boxes = _shipment.boxes; + setState(() { + _shipment = s; + }); + } + @override void dispose() { super.dispose(); @@ -103,7 +113,56 @@ class _ShipmentInfoState extends State { bool isCourierPickup = _shipment.shipmentType == shipment_courier_pickup; bool isLocalDropoff = _shipment.shipmentType == shipment_local_dropoff; bool isCourierDropoff = _shipment.shipmentType == shipment_courier_dropoff; + bool isEditable = widget.isCustomer + ? (_shipment.isPending || _shipment.isAssigned) + : (_shipment.isPending || _shipment.isAssigned || _shipment.isPickuped); + bool canCancel = + _shipment.isPending || _shipment.isConfirmed || _shipment.isAssigned; + final popupMenu = LocalPopupMenuButton( + popmenus: [ + LocalPopupMenu( + enabled: _shipment.isPending && isLocalPickup, + id: 1, + textKey: "shipment.assign.for.pickup", + ), + LocalPopupMenu( + enabled: + (_shipment.isPickuped && isLocalPickup) || _shipment.isReceived, + id: 3, + textKey: "shipment.pack.menuitem", + ), + LocalPopupMenu( + enabled: _shipment.isPending && (isCourierPickup || isCourierDropoff), + id: 4, + textKey: "shipment.confirm.menuitem", + ), + LocalPopupMenu( + enabled: canCancel, + id: 2, + textKey: "btn.cancel", + ), + ], + selectable: false, + buttonIcon: Icons.more_vert, + popupMenuCallback: (p) => p.id == 1 + ? _gotoAssign() + : p.id == 2 + ? _cancel() + : p.id == 3 ? _gotoPack() : p.id == 4 ? _gotoConfirm() : null, + ); + final popupMenuCustomer = LocalPopupMenuButton( + popmenus: [ + LocalPopupMenu( + enabled: canCancel, + id: 2, + textKey: "btn.cancel", + ), + ], + selectable: false, + buttonIcon: Icons.more_vert, + popupMenuCallback: (p) => p.id == 2 ? _cancel() : null, + ); final shipmentNumberBox = getShipmentNumberStatus(context, _shipment); final fromTimeBox = DisplayText( @@ -136,7 +195,7 @@ class _ShipmentInfoState extends State { onPressed: _openCourierWebsite, icon: Icon(Icons.open_in_new, color: primaryColor), label: Text( - 'Visit courier websie \nfor nearest drop-off', + 'Visit courier website \nfor nearest drop-off', style: TextStyle(fontSize: 16, color: primaryColor), ), backgroundColor: Colors.white, @@ -146,14 +205,40 @@ class _ShipmentInfoState extends State { iconData: Icons.location_on, labelKey: "shipment.location", ); - var boxModel = Provider.of(context); + var usersBox = DisplayText( + labelTextKey: "shipment.staff", + text: _shipment.pickupUserName, + iconData: MaterialCommunityIcons.worker); var handlingFeeBox = DisplayText( labelTextKey: "shipment.handling.fee", - text: "10", - iconData: FontAwesomeIcons.moneyBill); - final cancelBtn = LocalButton( - textKey: "btn.cancel", - callBack: _cancel, + text: (_shipment.handlingFee ?? 0).toString(), + iconData: FontAwesome.truck); + + final assignCompleteBtn = LocalButton( + textKey: "shipment.assign.complete.btn", + callBack: _completeAssign, + ); + final completePickupBtn = LocalButton( + textKey: "shipment.pickup.complete.btn", + callBack: _pickup, + ); + final completePackBtn = LocalButton( + textKey: "shipment.pack.complete.btn", + callBack: _pack, + ); + final confirmCompleteBtn = LocalButton( + textKey: "shipment.confirm.complete.btn", + callBack: _confirm, + ); + + final fcsShipmentNumberBox = DisplayText( + text: _shipment.fcsShipmentNumber, + labelTextKey: "FCSshipment.number", + iconData: Ionicons.ios_airplane, + ); + final completeReceiveBtn = LocalButton( + textKey: "shipment.receive.complete.btn", + callBack: _receive, ); return LocalProgress( @@ -178,24 +263,23 @@ class _ShipmentInfoState extends State { ), actions: [ IconButton( - icon: Icon(Icons.edit, color: primaryColor), - onPressed: _edit, + icon: Icon(Icons.edit, + color: isEditable ? primaryColor : Colors.grey), + onPressed: isEditable ? _edit : null, ), + widget.isCustomer ? popupMenuCustomer : popupMenu, ]), body: Padding( padding: const EdgeInsets.all(10.0), child: ListView( children: [ shipmentNumberBox, - LocalTitle(textKey: "shipment.type"), LocalRadioButtons( readOnly: true, values: pickupModel.shipmentTypes, selectedValue: _shipment.shipmentType, ), - // handlingFeeBox, - // shipmentTypeBox, ...(isLocalDropoff ? [ LocalTitle(textKey: "shipment.location.dropoff"), @@ -218,17 +302,48 @@ class _ShipmentInfoState extends State { toTimeBox, ] : []), - // localDropoffAddress, - // curierDropoffAddress, LocalTitle( textKey: "boxes.name", + trailing: Text( + "${_shipment.totalCount} Cartons - ${_shipment.totalWeight} lb"), ), Column( children: getBoxList(context, _shipment.boxes), ), - _shipment.currentStatus == shipment_pending_status - ? cancelBtn - : Container() + !_isCustomer ? fcsShipmentNumberBox : Container(), + ...(_shipment.isAssigned || + _shipment.isConfirmed || + _shipment.isPending + ? [ + handlingFeeBox, + ] + : []), + ...(isLocalPickup + ? [ + LocalTitle(textKey: "shipment.assign.for.pickup"), + usersBox, + ] + : []), + ...(isLocalPickup && !_isCustomer + ? [ + _shipment.isPending ? assignCompleteBtn : Container(), + _shipment.isAssigned ? completePickupBtn : Container(), + _shipment.isPickuped ? completePackBtn : Container(), + ] + : []), + ...((isCourierPickup || isCourierDropoff) && !_isCustomer + ? [ + _shipment.isPending ? confirmCompleteBtn : Container(), + _shipment.isConfirmed ? completeReceiveBtn : Container(), + _shipment.isReceived ? completePackBtn : Container(), + ] + : []), + ...((isLocalDropoff) && !_isCustomer + ? [ + _shipment.isPending ? completeReceiveBtn : Container(), + _shipment.isReceived ? completePackBtn : Container(), + ] + : []), ], ), ), @@ -256,13 +371,8 @@ class _ShipmentInfoState extends State { )), ); if (updated ?? false) { - ShipmentModel shipmentModel = - Provider.of(context, listen: false); - Shipment s = await shipmentModel.getShipment(_shipment.id); - setState(() { - _shipment = s; - }); - await _loadCartons(s.id); + await _loadShipment(_shipment.id); + await _loadCartons(_shipment.id); } } @@ -294,4 +404,164 @@ class _ShipmentInfoState extends State { MainModel mainModel = Provider.of(context, listen: false); launch("${mainModel.setting.courierWebsite}"); } + + _gotoAssign() async { + bool assigned = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ShipmentAssign( + shipment: _shipment, + )), + ); + if (assigned ?? false) { + await _loadShipment(_shipment.id); + } + } + + _completeAssign() { + showConfirmDialog(context, "shipment.assign.complete.confirm", () { + _completeAssignShipment(); + }); + } + + _completeAssignShipment() async { + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.completeAssignShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + _pickup() { + showConfirmDialog(context, "shipment.pickup.complete.confirm", () { + _pickupShipment(); + }); + } + + _pickupShipment() async { + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.completePickupShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + _gotoPack() async { + bool assigned = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ShipmentPack( + shipment: _shipment, + )), + ); + if (assigned ?? false) { + await _loadShipment(_shipment.id); + await _loadCartons(_shipment.id); + } + } + + _pack() { + showConfirmDialog(context, "shipment.pack.complete.confirm", () { + _packShipment(); + }); + } + + _packShipment() async { + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.completePackShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + _gotoConfirm() async { + bool assigned = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ShipmentConfirm( + shipment: _shipment, + )), + ); + if (assigned ?? false) { + await _loadShipment(_shipment.id); + } + } + + _confirm() { + showConfirmDialog(context, "shipment.confirm.complete.confirm", () { + _confirmShipment(); + }); + } + + _confirmShipment() async { + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.completeConfirmShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + _receive() { + showConfirmDialog(context, "shipment.receive.complete.confirm", () { + _receiveShipment(); + }); + } + + _receiveShipment() async { + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.completeReceiveShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/shipment/shipment_list.dart b/lib/pages/shipment/shipment_list.dart index 5f3ad78..df6df97 100644 --- a/lib/pages/shipment/shipment_list.dart +++ b/lib/pages/shipment/shipment_list.dart @@ -25,10 +25,12 @@ class ShipmentList extends StatefulWidget { class _ShipmentListState extends State { bool _isLoading = false; var _controller = ScrollController(); + bool _forCustomer = true; @override void initState() { super.initState(); + _forCustomer = widget.forCustomer; _controller.addListener(() async { if (_controller.position.pixels == _controller.position.maxScrollExtent) { Provider.of(context, listen: false) @@ -36,7 +38,8 @@ class _ShipmentListState extends State { } }); - Provider.of(context, listen: false).initData(false); + Provider.of(context, listen: false) + .initData(widget.forCustomer); } @override @@ -48,13 +51,27 @@ class _ShipmentListState extends State { Widget build(BuildContext context) { ShipmentModel shipmentModel = Provider.of(context); final popupMenu = LocalPopupMenuButton( - popmenus: [ - LocalPopupMenu( - id: 1, textKey: "shipment.popupmenu.active", selected: true), - LocalPopupMenu(id: 2, textKey: "shipment.popupmenu.delivered") - ], + popmenus: _forCustomer + ? [ + LocalPopupMenu( + id: 1, textKey: "shipment.popupmenu.active", selected: true), + LocalPopupMenu(id: 2, textKey: "shipment.popupmenu.delivered"), + ] + : [ + LocalPopupMenu( + id: 1, textKey: "shipment.popupmenu.active", selected: true), + LocalPopupMenu(id: 2, textKey: "shipment.popupmenu.delivered"), + LocalPopupMenu(id: 3, textKey: "shipment.popupmenu.mypickup"), + ], popupMenuCallback: (p) => this.setState(() { shipmentModel.menuSelectedIndex = p.id; + if (p.id == 3) { + Provider.of(context, listen: false) + .initData(widget.forCustomer, myPickup: true); + } else if (p.id == 1) { + Provider.of(context, listen: false) + .initData(widget.forCustomer); + } }), ); return LocalProgress( @@ -72,18 +89,20 @@ class _ShipmentListState extends State { title: LocalText(context, "shipment", fontSize: 18, color: Colors.white), actions: [ - IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, - // onPressed: () => showPlacesSearch(context), - ), + widget.forCustomer + ? Container() + : IconButton( + icon: Icon( + Icons.search, + color: Colors.white, + ), + iconSize: 30, + // onPressed: () => showPlacesSearch(context), + ), popupMenu ], ), - floatingActionButton: shipmentModel.menuSelectedIndex == 1 + floatingActionButton: widget.forCustomer ? FloatingActionButton.extended( onPressed: () { _newPickup(); @@ -108,8 +127,10 @@ class _ShipmentListState extends State { itemCount: shipmentModel.shipments.length, itemBuilder: (BuildContext context, int index) { return ShipmentListRow( - key: ValueKey(shipmentModel.shipments[index].id), - pickUp: shipmentModel.shipments[index]); + key: ValueKey(shipmentModel.shipments[index].id), + pickUp: shipmentModel.shipments[index], + isCustomer: widget.forCustomer, + ); }), onRefresh: () => shipmentModel.refresh(isCustomer: widget.forCustomer), diff --git a/lib/pages/shipment/shipment_list_row.dart b/lib/pages/shipment/shipment_list_row.dart index 35bb9dd..c5b8ccf 100644 --- a/lib/pages/shipment/shipment_list_row.dart +++ b/lib/pages/shipment/shipment_list_row.dart @@ -9,14 +9,19 @@ import 'shipment_info.dart'; class ShipmentListRow extends StatelessWidget { final Shipment pickUp; - const ShipmentListRow({Key key, this.pickUp}) : super(key: key); + final bool isCustomer; + const ShipmentListRow({Key key, this.pickUp, this.isCustomer}) + : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => ShipmentInfo(shipment: pickUp))); + builder: (context) => ShipmentInfo( + shipment: pickUp, + isCustomer: isCustomer, + ))); }, child: Container( padding: EdgeInsets.only(left: 15, right: 15), @@ -46,7 +51,7 @@ class ShipmentListRow extends StatelessWidget { ), ), Padding( - padding: const EdgeInsets.only(left: 10.0, top: 10), + padding: const EdgeInsets.only(left: 10.0, top: 3), child: new Text( pickUp.id == null ? '' @@ -66,29 +71,25 @@ class ShipmentListRow extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.all(0), - child: getStatus(pickUp.currentStatus), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), - child: Row( - children: [ - new Text( - pickUp.weight == null - ? '' - : pickUp.weight.toString() + 'lb - ', - style: - new TextStyle(fontSize: 15.0, color: Colors.grey), - ), - new Text( - pickUp.numberOfPackage == null - ? "" - : pickUp.numberOfPackage.toString() + ' packages', - style: - new TextStyle(fontSize: 15.0, color: Colors.grey), - ), - ], - ), + child: getStatus(pickUp.status), ), + // Padding( + // padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), + // child: Row( + // children: [ + // new Text( + // "(${pickUp.totalWeight ?? "0"}) lb ", + // style: + // new TextStyle(fontSize: 15.0, color: Colors.grey), + // ), + // new Text( + // "(${pickUp.totalCount ?? "0"}) cartons ", + // style: + // new TextStyle(fontSize: 15.0, color: Colors.grey), + // ), + // ], + // ), + // ), ], ) ], diff --git a/lib/pages/shipment/shipment_pack.dart b/lib/pages/shipment/shipment_pack.dart new file mode 100644 index 0000000..245c1ff --- /dev/null +++ b/lib/pages/shipment/shipment_pack.dart @@ -0,0 +1,140 @@ +import 'package:fcs/domain/entities/fcs_shipment.dart'; +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/shipment/model/shipment_model.dart'; +import 'package:fcs/pages/widgets/local_button.dart'; +import 'package:fcs/pages/widgets/local_dropdown.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/local_title.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import 'widgets.dart'; + +class ShipmentPack extends StatefulWidget { + final Shipment shipment; + ShipmentPack({this.shipment}); + + @override + _ShipmentPackState createState() => _ShipmentPackState(); +} + +class _ShipmentPackState extends State { + var dateFormatter = new DateFormat('dd MMM yyyy'); + var timeFormatter = new DateFormat('jm'); + + Shipment _shipment; + bool _isLoading = false; + var now = new DateTime.now(); + + FcsShipment _fcsShipment; + List _fcsShipments; + + @override + void initState() { + super.initState(); + + _shipment = widget.shipment; + _loadFcsShipments(); + } + + _loadFcsShipments() async { + FcsShipmentModel fcsShipmentModel = + Provider.of(context, listen: false); + var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); + var fcsShipment = fcsShipments + .firstWhere((e) => e.id == _shipment.fcsShipmentID, orElse: () => null); + setState(() { + _fcsShipments = fcsShipments; + _fcsShipment = fcsShipment; + }); + } + + @override + Widget build(BuildContext context) { + final shipmentNumberBox = getShipmentNumberStatus(context, _shipment); + + var fcsShipmentsBox = LocalDropdown( + callback: (v) { + setState(() { + _fcsShipment = v; + }); + }, + labelKey: "shipment.pack.fcs.shipment", + iconData: MaterialCommunityIcons.worker, + display: (u) => u.shipmentNumber, + selectedValue: _fcsShipment, + values: _fcsShipments, + ); + + final packbtn = LocalButton( + textKey: "shipment.pack.btn", + callBack: _save, + ); + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon( + CupertinoIcons.back, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "shipment.pack.menuitem", + fontSize: 20, + color: primaryColor, + ), + ), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( + children: [ + Center(child: shipmentNumberBox), + SizedBox( + height: 10, + ), + LocalTitle(textKey: "shipment.pack.fcs.shipment"), + fcsShipmentsBox, + SizedBox( + height: 10, + ), + packbtn, + ], + ), + ), + ), + ); + } + + _save() async { + _shipment.fcsShipmentID = this._fcsShipment.id; + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + await shipmentModel.packShipment(_shipment); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/shipment/widgets.dart b/lib/pages/shipment/widgets.dart index 175f116..ab3ed24 100644 --- a/lib/pages/shipment/widgets.dart +++ b/lib/pages/shipment/widgets.dart @@ -1,5 +1,7 @@ import 'package:fcs/domain/entities/shipment.dart'; import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; +import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:flutter/material.dart'; @@ -17,7 +19,7 @@ Widget getShipmentNumberStatus(BuildContext context, Shipment shipment) { ), Padding( padding: const EdgeInsets.only(left: 8.0), - child: Chip(label: Text(shipment.currentStatus ?? "")), + child: Chip(label: Text(shipment.status ?? "")), ), ], ); diff --git a/lib/pages/staff/model/staff_model.dart b/lib/pages/staff/model/staff_model.dart index 79f92df..cadb5a4 100644 --- a/lib/pages/staff/model/staff_model.dart +++ b/lib/pages/staff/model/staff_model.dart @@ -85,4 +85,29 @@ class StaffModel extends BaseModel { Future findUser(String phoneNumber) { return Services.instance.userService.findUser(phoneNumber); } + + Future> getPickupEmployees() async { + if (user == null || !user.hasShipment()) return []; + return _getUsers(privilege_shipment); + } + + Future> _getUsers(String privilege) async { + List users = []; + try { + var snaps = await Firestore.instance + .collection("/$user_collection") + .where("is_employee", isEqualTo: true) + .where("is_sys_admin", isEqualTo: false) + .where("privileges", arrayContains: privilege) + .getDocuments(source: Source.server); + users = snaps.documents.map((documentSnapshot) { + var user = + User.fromMap(documentSnapshot.data, documentSnapshot.documentID); + return user; + }).toList(); + } catch (e) { + log.warning("Error!! $e"); + } + return users; + } } diff --git a/lib/pages/staff/staff_list.dart b/lib/pages/staff/staff_list.dart index a799876..fabcc6c 100644 --- a/lib/pages/staff/staff_list.dart +++ b/lib/pages/staff/staff_list.dart @@ -1,7 +1,6 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/staff/model/staff_model.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; @@ -55,9 +54,9 @@ class _StaffListState extends State { body: new ListView.separated( separatorBuilder: (context, index) => Divider( color: Colors.black, + height: 1, ), scrollDirection: Axis.vertical, - padding: EdgeInsets.only(left: 5, right: 5, top: 5), shrinkWrap: true, itemCount: staffModel.employees.length, itemBuilder: (BuildContext context, int index) { @@ -69,56 +68,52 @@ class _StaffListState extends State { } Widget _item(User user) { - return Stack( - children: [ - InkWell( - onTap: () { - Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => StaffEditor(staff: user))); - }, - child: Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: new Row( - children: [ - new Padding( - padding: new EdgeInsets.symmetric( - horizontal: 32.0 - dotSize / 2), - child: Icon( - MaterialCommunityIcons.worker, - color: primaryColor, - size: 40, - ), - ), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Text( - user.name, - style: new TextStyle(fontSize: 15.0), - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: new Text( - user.phoneNumber, - style: new TextStyle( - fontSize: 15.0, color: Colors.grey), - ), - ), - ], - ), - ), - ], + return InkWell( + onTap: () { + Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => StaffEditor(staff: user))); + }, + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.symmetric( + horizontal: 32.0 - dotSize / 2), + child: Icon( + MaterialCommunityIcons.worker, + color: primaryColor, + size: 40, + ), ), - ), + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + user.name, + style: new TextStyle(fontSize: 15.0), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: new Text( + user.phoneNumber, + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ), + ], + ), + ), + ], ), - ], + ), ), - ), - ], + ], + ), ); } } diff --git a/lib/pages/widgets/defalut_delivery_address.dart b/lib/pages/widgets/defalut_delivery_address.dart index e8ffbc5..649abcf 100644 --- a/lib/pages/widgets/defalut_delivery_address.dart +++ b/lib/pages/widgets/defalut_delivery_address.dart @@ -27,10 +27,12 @@ class DefaultDeliveryAddress extends StatelessWidget { Row( children: [ Expanded( - child: DisplayText( - labelTextKey: this.labelKey ?? "delivery_address", - iconData: iconData ?? MaterialCommunityIcons.truck_fast, - ), + child: this.labelKey == null + ? Container() + : DisplayText( + labelTextKey: this.labelKey, + iconData: iconData ?? MaterialCommunityIcons.truck_fast, + ), ), onTap == null ? Container() diff --git a/lib/pages/widgets/local_dropdown.dart b/lib/pages/widgets/local_dropdown.dart index 5e74dec..b61c3b8 100644 --- a/lib/pages/widgets/local_dropdown.dart +++ b/lib/pages/widgets/local_dropdown.dart @@ -9,9 +9,17 @@ class LocalDropdown extends StatelessWidget { final IconData iconData; final T selectedValue; final List values; + final Function(T) display; + final String labelKey; const LocalDropdown( - {Key key, this.callback, this.iconData, this.selectedValue, this.values}) + {Key key, + this.callback, + this.iconData, + this.selectedValue, + this.values, + this.labelKey, + this.display}) : super(key: key); @override @@ -32,7 +40,7 @@ class LocalDropdown extends StatelessWidget { padding: const EdgeInsets.only(right: 18.0), child: LocalText( context, - "shipment.type", + labelKey, color: Colors.black54, fontSize: 16, ), @@ -49,14 +57,21 @@ class LocalDropdown extends StatelessWidget { callback(newValue); }, isExpanded: true, - items: values.map>((T value) { - return DropdownMenuItem( - value: value, - child: Text(value==null? "":value.toString(), - overflow: TextOverflow.ellipsis, - style: TextStyle(color: primaryColor)), - ); - }).toList(), + items: values == null + ? [] + : values.map>((T value) { + return DropdownMenuItem( + value: value, + child: Text( + value == null + ? "" + : display != null + ? display(value) + : value.toString(), + overflow: TextOverflow.ellipsis, + style: TextStyle(color: primaryColor)), + ); + }).toList(), ), ], ), diff --git a/lib/pages/widgets/local_popup_menu_button.dart b/lib/pages/widgets/local_popup_menu_button.dart index 90f2d90..2a29681 100644 --- a/lib/pages/widgets/local_popup_menu_button.dart +++ b/lib/pages/widgets/local_popup_menu_button.dart @@ -10,6 +10,7 @@ class LocalPopupMenuButton extends StatefulWidget { final PopupMenuCallback popupMenuCallback; final List popmenus; final bool multiSelect; + final bool selectable; final IconData buttonIcon; const LocalPopupMenuButton( @@ -17,6 +18,7 @@ class LocalPopupMenuButton extends StatefulWidget { this.popupMenuCallback, this.popmenus, this.buttonIcon, + this.selectable = true, this.multiSelect = false}) : super(key: key); @@ -39,25 +41,27 @@ class _LocalPopupMenuButtonState extends State { return PopupMenuButton( elevation: 3.2, onSelected: (selected) { - if (!widget.multiSelect) { - setState(() { - popmenus.forEach((e) { - if (e.id != selected.id) - e.selected = false; - else - e.selected = true; + if (widget.selectable) { + if (!widget.multiSelect) { + setState(() { + popmenus.forEach((e) { + if (e.id != selected.id) + e.selected = false; + else + e.selected = true; + }); }); - }); - selected.selected = true; - } else { - setState(() { - popmenus.forEach((e) { - if (e.id == selected.id) e.selected = !e.selected; + selected.selected = true; + } else { + setState(() { + popmenus.forEach((e) { + if (e.id == selected.id) e.selected = !e.selected; + }); }); - }); - selected.selected = !selected.selected; + selected.selected = !selected.selected; + } } - if (widget.popupMenuCallback != null) + if (selected.enabled && widget.popupMenuCallback != null) widget.popupMenuCallback(selected); }, icon: Container( @@ -92,11 +96,14 @@ class _LocalPopupMenuButtonState extends State { )), itemBuilder: (BuildContext context) { return popmenus.map((LocalPopupMenu choice) { + if (choice == null) return null; return PopupMenuItem( value: choice, child: Row( children: [ - LocalText(context, choice.textKey, color: primaryColor), + LocalText(context, choice.textKey, + color: + choice?.enabled ?? true ? primaryColor : Colors.grey), SizedBox( width: 10, ), @@ -115,6 +122,7 @@ class _LocalPopupMenuButtonState extends State { bool _needHighlight() { popmenus.forEach((e) { + if (e == null) return false; if (e.selected && e.highlight) return true; }); return false; diff --git a/lib/pages/widgets/local_popupmenu.dart b/lib/pages/widgets/local_popupmenu.dart index 7029c58..d3778ee 100644 --- a/lib/pages/widgets/local_popupmenu.dart +++ b/lib/pages/widgets/local_popupmenu.dart @@ -3,6 +3,11 @@ class LocalPopupMenu { String textKey; bool selected; bool highlight; + bool enabled; LocalPopupMenu( - {this.id, this.textKey, this.selected = false, this.highlight = false}); + {this.id, + this.textKey, + this.selected = false, + this.highlight = false, + this.enabled = true}); }