From e5540c54910b7f4b42bfdf7e02194cdeb08cf2d6 Mon Sep 17 00:00:00 2001 From: Sai Naw Wun Date: Thu, 22 Oct 2020 04:14:53 +0630 Subject: [PATCH] fix errors --- assets/local/localization_en.json | 4 + assets/local/localization_mu.json | 4 + lib/domain/constants.dart | 1 + lib/domain/entities/cargo_type.dart | 3 + lib/domain/entities/carton.dart | 9 +- lib/domain/entities/custom_duty.dart | 6 + lib/domain/entities/invoice.dart | 88 +- lib/domain/entities/shipment.dart | 4 + lib/pages/carton/carton_editor.dart | 6 +- lib/pages/carton/carton_list.dart | 12 +- lib/pages/carton/model/carton_model.dart | 15 + lib/pages/customer/model/customer_model.dart | 19 + lib/pages/delivery/delivery_list.dart | 12 +- lib/pages/discount/discount_list.dart | 100 ++- lib/pages/discount/discount_list_row.dart | 13 +- lib/pages/discount/model/discount_model.dart | 62 +- .../model/fcs_shipment_model.dart | 20 +- lib/pages/invoice/invoce_list.dart | 7 +- lib/pages/invoice/invoice_cargo_table.dart | 342 ++++++++ lib/pages/invoice/invoice_carton_table.dart | 113 +++ lib/pages/invoice/invoice_custom_table.dart | 107 +++ lib/pages/invoice/invoice_customer_list.dart | 66 +- lib/pages/invoice/invoice_editor.dart | 788 +++--------------- lib/pages/invoice/invoice_shipment_list.dart | 30 +- .../invoice/invoice_shipment_list_row.dart | 6 +- lib/pages/invoice/model/invoice_model.dart | 4 +- lib/pages/main/model/main_model.dart | 4 +- lib/pages/package/package_info.dart | 7 +- lib/pages/package/package_list.dart | 1 + lib/pages/package/package_list_row.dart | 9 +- lib/pages/profile/profile_page.dart | 4 +- lib/pages/shipment/shipment_list.dart | 14 +- 32 files changed, 1069 insertions(+), 811 deletions(-) create mode 100644 lib/pages/invoice/invoice_cargo_table.dart create mode 100644 lib/pages/invoice/invoice_carton_table.dart create mode 100644 lib/pages/invoice/invoice_custom_table.dart diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 2226bad..0ae209d 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -457,6 +457,8 @@ "invoice.shipment_weight":"Shipment weight", "invoice.popupmenu.pending":"Pending", "invoice.popupmenu.paid":"Paid", + "invoice.shipment.title":"Select FCS shipment", + "invoice.customer.title":"Select Customer", "Invoices End ================================================================":"", "Discount Start ================================================================":"", @@ -469,6 +471,8 @@ "discount.amount":"Amount", "discount.status":"Status", "discount.edit.delete.confirm":"Delete this discount?", + "discount.popupmenu.available":"Available discounts", + "discount.popupmenu.used":"Used discounts", "Discount End ================================================================":"", "delivery_addresses Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 69c0ce4..2e9273c 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -457,6 +457,8 @@ "invoice.shipment_weight":"Shipment weight", "invoice.popupmenu.pending":"Pending", "invoice.popupmenu.paid":"Paid", + "invoice.shipment.title":"Select FCS shipment", + "invoice.customer.title":"Select Customer", "Invoices End ================================================================":"", "Discount Start ================================================================":"", @@ -469,6 +471,8 @@ "discount.amount":"ပမာဏ", "discount.status":"အခြေအနေ", "discount.edit.delete.confirm":"လျှော့စျေးကို ဖျက်မလား?", + "discount.popupmenu.available":"Available discounts", + "discount.popupmenu.used":"Used discounts", "Discount End ================================================================":"", "delivery_addresses Start ================================================================":"", diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 1c084cc..fb283bf 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -13,6 +13,7 @@ const custom_duties_collection = "custom_duties"; const discounts_by_weights_collection = "discounts_by_weight"; const shipments_collection = "shipments"; const cartons_collection = "cartons"; +const discounts_collection = "discounts"; // docs const setting_doc_id = "setting"; diff --git a/lib/domain/entities/cargo_type.dart b/lib/domain/entities/cargo_type.dart index a61a45a..0a5efa9 100644 --- a/lib/domain/entities/cargo_type.dart +++ b/lib/domain/entities/cargo_type.dart @@ -9,6 +9,9 @@ class CargoType { int shipmentWeight; double amount; + double calRate; + double calWeight; + factory CargoType.fromMap(Map map, String id) { return CargoType( id: id, diff --git a/lib/domain/entities/carton.dart b/lib/domain/entities/carton.dart index a402a42..609ed70 100644 --- a/lib/domain/entities/carton.dart +++ b/lib/domain/entities/carton.dart @@ -43,10 +43,9 @@ class Carton { String remark; DateTime arrivedDate; String cartonNumber; + List packageIDs; - List packages; - List cargoTypes; List cartons; @@ -193,4 +192,10 @@ class Carton { deliveryAddress: _da, cargoTypes: cargoTypes); } + + @override + bool operator ==(Object other) => other is Carton && other.id == id; + + @override + int get hashCode => id.hashCode; } diff --git a/lib/domain/entities/custom_duty.dart b/lib/domain/entities/custom_duty.dart index 05b6daf..d5eba6a 100644 --- a/lib/domain/entities/custom_duty.dart +++ b/lib/domain/entities/custom_duty.dart @@ -22,4 +22,10 @@ class CustomDuty { 'fee': fee, }; } + + @override + bool operator ==(Object other) => other is CustomDuty && other.id == id; + + @override + int get hashCode => id.hashCode; } diff --git a/lib/domain/entities/invoice.dart b/lib/domain/entities/invoice.dart index 15125c2..9f7e36a 100644 --- a/lib/domain/entities/invoice.dart +++ b/lib/domain/entities/invoice.dart @@ -1,3 +1,10 @@ +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/custom_duty.dart'; +import 'package:fcs/domain/entities/discount.dart'; +import 'package:fcs/domain/entities/discount_by_weight.dart'; +import 'package:fcs/domain/entities/rate.dart'; + import 'package.dart'; import 'receipt.dart'; @@ -8,13 +15,89 @@ class Invoice { String customerName; String customerPhoneNumber; double amount; - String discount; String status; String paymentAttachment; + double handlingFee; + double deliveryFee; + double paidAmount; List packages; List receipts; List receiptPhotos; + List customDuties; + List cartons; + Discount discount; + + List getCargoTypes(Rate rate) { + List cargoTypes = []; + double actualWeight = 0; + double shipmentWeight = 0; + cartons.forEach((c) { + c.cargoTypes.forEach((tc) { + if (cargoTypes.contains(tc)) { + CargoType existing = cargoTypes.firstWhere((wc) => wc.id == tc.id); + existing.weight += tc.weight; + } else { + cargoTypes.add(tc); + } + actualWeight += tc.weight; + }); + double volume = (c.length ?? 0) * (c.width ?? 0) * (c.height ?? 0); + double sw = volume / rate.volumetricRatio ?? 0; + shipmentWeight += sw; + }); + + DiscountByWeight discountByWeight = rate.getDiscountByWeight( + shipmentWeight > actualWeight ? shipmentWeight : actualWeight); + + cargoTypes.forEach((e) { + print(actualWeight > shipmentWeight); + double cargoWeight = actualWeight > shipmentWeight + ? e.weight + : e.weight / actualWeight * shipmentWeight; + double r = + e.rate - (discountByWeight != null ? discountByWeight.discount : 0); + double amount = cargoWeight * r; + e.calRate = r; + e.calWeight = cargoWeight; + e.amount = amount; + }); + return cargoTypes; + } + + double getTotal(Rate rate) { + List cargoTypes = getCargoTypes(rate); + var total = cargoTypes.fold(0.0, (p, c) => c.amount + p); + return total; + } + + double getNetAmount(Rate rate) { + List cargoTypes = getCargoTypes(rate); + var total = cargoTypes.fold(0.0, (p, c) => c.amount + p); + total += getCustomFee(); + total += getDeliveryFee(); + total += getHandlingFee(); + total -= getDiscount(); + return total; + } + + double getTotalBalance(Rate rate) { + return getNetAmount(rate) - (paidAmount ?? 0); + } + + double getCustomFee() { + return customDuties == null ? 0 : customDuties.fold(0, (p, d) => p + d.fee); + } + + double getHandlingFee() { + return handlingFee == null ? 0 : handlingFee; + } + + double getDeliveryFee() { + return deliveryFee == null ? 0 : deliveryFee; + } + + double getDiscount() => discount == null ? 0 : discount.amount; Invoice( {this.id, @@ -28,6 +111,9 @@ class Invoice { this.paymentAttachment, this.packages, this.receiptPhotos, + this.customDuties, + this.cartons, + this.handlingFee, this.receipts}); double get getAmount => packages.fold(0, (p, e) => (e.rate * e.weight) + p); diff --git a/lib/domain/entities/shipment.dart b/lib/domain/entities/shipment.dart index 2b2094c..3a71a72 100644 --- a/lib/domain/entities/shipment.dart +++ b/lib/domain/entities/shipment.dart @@ -13,6 +13,7 @@ class Shipment { String pickupTimeEnd; String userName; + String userID; String phoneNumber; int numberOfPackage; int weight; @@ -35,6 +36,7 @@ class Shipment { {this.id, this.shipmentNumber, this.shipmentType, + this.userID, this.userName, this.phoneNumber, this.pickupTimeStart, @@ -75,6 +77,7 @@ class Shipment { return Shipment( id: id, userName: map['user_name'], + userID: map['user_id'], shipmentNumber: map['shipment_number'], phoneNumber: map['phone_number'], pickupDate: pd == null ? null : pd.toDate(), @@ -97,6 +100,7 @@ class Shipment { return { "id": id, + 'user_id': userID, 'cartons': _boxes, 'shipment_type': shipmentType, 'pickup_address': pickupAddress.toMap(), diff --git a/lib/pages/carton/carton_editor.dart b/lib/pages/carton/carton_editor.dart index 5638b50..331016b 100644 --- a/lib/pages/carton/carton_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -490,7 +490,7 @@ class _CartonEditorState extends State { showMsgDialog(context, "Error", "Invalid delivery address"); return; } - if (isSmallBag && _mixCarton == null) { + if (isSmallBag && _mixCarton == null && _isNew) { showMsgDialog(context, "Error", "Invalid mix carton"); return; } @@ -507,7 +507,9 @@ class _CartonEditorState extends State { carton.width = w; carton.height = h; carton.deliveryAddress = _deliveryAddress; - carton.cartons = _carton.cartons.where((c) => c.isChecked).toList(); + carton.cartons = _carton.cartons == null + ? [] + : _carton.cartons.where((c) => c.isChecked).toList(); setState(() { _isLoading = true; }); diff --git a/lib/pages/carton/carton_list.dart b/lib/pages/carton/carton_list.dart index bfece5b..544dba6 100644 --- a/lib/pages/carton/carton_list.dart +++ b/lib/pages/carton/carton_list.dart @@ -68,17 +68,7 @@ class _CartonListState extends State { backgroundColor: primaryColor, title: LocalText(context, "boxes.name", color: Colors.white, fontSize: 20), - actions: [ - IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, onPressed: () {}, - // onPressed: () => showPlacesSearch(context), - ), - popupMenu - ], + actions: [popupMenu], ), floatingActionButton: FloatingActionButton.extended( onPressed: () { diff --git a/lib/pages/carton/model/carton_model.dart b/lib/pages/carton/model/carton_model.dart index 49ba78e..c4f40fc 100644 --- a/lib/pages/carton/model/carton_model.dart +++ b/lib/pages/carton/model/carton_model.dart @@ -174,6 +174,21 @@ class CartonModel extends BaseModel { .toList(); } + Future> getCartonsForInvoice( + String fcsShipmentID, String userID) async { + String path = "/$cartons_collection"; + var querySnap = await Firestore.instance + .collection(path) + // .where("fcs_shipment_id", isEqualTo: fcsShipmentID) + .where("user_id", isEqualTo: userID) + .where("is_deleted", isEqualTo: false) + .where("is_invoiced", isEqualTo: false) + .getDocuments(); + return querySnap.documents + .map((e) => Carton.fromMap(e.data, e.documentID)) + .toList(); + } + Future> getMixCartonsByFcsShipment(String fcsShipmentID) async { String path = "/$cartons_collection"; var querySnap = await Firestore.instance diff --git a/lib/pages/customer/model/customer_model.dart b/lib/pages/customer/model/customer_model.dart index dcf2acd..1413f3a 100644 --- a/lib/pages/customer/model/customer_model.dart +++ b/lib/pages/customer/model/customer_model.dart @@ -96,6 +96,25 @@ class CustomerModel extends BaseModel { return User.fromMap(snap.data, snap.documentID); } + Future> getInvoiceUsers(String fcsShipmentID) async { + List users = []; + try { + var snaps = await Firestore.instance + .collection( + "/$fcs_shipment_collection/$fcsShipmentID/$user_collection") + .where("pending_invoice_carton_count", isGreaterThan: 0) + .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; + } + Future enableUser(User user, bool enabled) { return Services.instance.userService.enableUser(user.id, enabled); } diff --git a/lib/pages/delivery/delivery_list.dart b/lib/pages/delivery/delivery_list.dart index 8e0d115..2e148b7 100644 --- a/lib/pages/delivery/delivery_list.dart +++ b/lib/pages/delivery/delivery_list.dart @@ -67,17 +67,7 @@ class _DeliverListState extends State { backgroundColor: primaryColor, title: LocalText(context, "delivery", color: Colors.white, fontSize: 20), - actions: [ - IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, - // onPressed: () => showPlacesSearch(context), - ), - popupMenu - ], + actions: [popupMenu], ), body: Column( children: [ diff --git a/lib/pages/discount/discount_list.dart b/lib/pages/discount/discount_list.dart index 0ecf773..e8cf374 100644 --- a/lib/pages/discount/discount_list.dart +++ b/lib/pages/discount/discount_list.dart @@ -3,6 +3,8 @@ 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_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'; @@ -12,29 +14,48 @@ import 'package:provider/provider.dart'; import 'discount_editor.dart'; class DiscountList extends StatefulWidget { - final bool selected; + final bool selectionMode; - const DiscountList({Key key, this.selected}) : super(key: key); + const DiscountList({Key key, this.selectionMode}) : super(key: key); @override _DiscountListState createState() => _DiscountListState(); } class _DiscountListState extends State { bool _isLoading = false; - bool _selected = false; + var _controller = ScrollController(); @override void initState() { super.initState(); - if (widget.selected != null) { - _selected = widget.selected; - } + _controller.addListener(() async { + if (_controller.position.pixels == _controller.position.maxScrollExtent) { + Provider.of(context, listen: false).loadMore(); + } + }); + Provider.of(context, listen: false).initData(); } @override Widget build(BuildContext context) { var discountModel = Provider.of(context); - print('discounts => ${discountModel.discounts}'); + + final popupMenu = LocalPopupMenuButton( + popmenus: [ + LocalPopupMenu( + id: 1, + textKey: "discount.popupmenu.available", + selected: discountModel.selectedIndex == 1), + LocalPopupMenu( + id: 2, + textKey: "discount.popupmenu.used", + selected: discountModel.selectedIndex == 2) + ], + popupMenuCallback: (p) => this.setState(() { + discountModel.selectedIndex = p.id; + }), + ); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( @@ -48,26 +69,53 @@ class _DiscountListState extends State { onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, - actions: [ - IconButton( - icon: Icon(Icons.search), - onPressed: () {}, - ) - ], + actions: [popupMenu], ), - 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 DiscountListRow( - key: ValueKey(discount.id), - discount: discount, - ); - }, + body: Column( + children: [ + Expanded( + child: ListView.separated( + separatorBuilder: (context, index) => Divider( + color: Colors.black, + height: 1, + ), + controller: _controller, + itemCount: discountModel.discounts.length, + itemBuilder: (BuildContext context, int index) { + var discount = discountModel.discounts[index]; + return DiscountListRow( + key: ValueKey(discount.id), + discount: discount, + onSelect: (d) { + if (widget.selectionMode) { + Navigator.pop(context, discount); + return; + } + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + DiscountEditor(discount: discount)), + ); + }, + ); + }, + ), + ), + discountModel.isLoading + ? Container( + padding: EdgeInsets.all(8), + color: primaryColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Loading...", + style: TextStyle(color: Colors.white)), + ], + ), + ) + : Container(), + ], ), floatingActionButton: FloatingActionButton.extended( onPressed: () { diff --git a/lib/pages/discount/discount_list_row.dart b/lib/pages/discount/discount_list_row.dart index 1bdd912..9047f3b 100644 --- a/lib/pages/discount/discount_list_row.dart +++ b/lib/pages/discount/discount_list_row.dart @@ -8,9 +8,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; +typedef OnSelect(Discount discount); + class DiscountListRow extends StatelessWidget { + final OnSelect onSelect; final Discount discount; - DiscountListRow({Key key, this.discount}) : super(key: key); + DiscountListRow({Key key, this.discount, this.onSelect}) : super(key: key); final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); @@ -18,11 +21,9 @@ class DiscountListRow extends StatelessWidget { Widget build(BuildContext context) { return InkWell( onTap: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => DiscountEditor(discount: discount)), - ); + if (onSelect != null) { + onSelect(discount); + } }, child: Container( padding: EdgeInsets.only(left: 15, right: 15), diff --git a/lib/pages/discount/model/discount_model.dart b/lib/pages/discount/model/discount_model.dart index 13ce253..1c425b6 100644 --- a/lib/pages/discount/model/discount_model.dart +++ b/lib/pages/discount/model/discount_model.dart @@ -2,7 +2,9 @@ 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/discount.dart'; +import 'package:fcs/helpers/paginator.dart'; import 'package:fcs/pages/main/model/base_model.dart'; import 'package:logging/logging.dart'; @@ -11,7 +13,28 @@ class DiscountModel extends BaseModel { StreamSubscription listener; - List discounts = []; + List _discounts = []; + List get discounts => + _selectedIndex == 1 ? _discounts : List.from(_used.values); + + Paginator _used; + bool isLoading = false; + int _selectedIndex = 1; + set selectedIndex(int index) { + _selectedIndex = index; + notifyListeners(); + } + + get selectedIndex => _selectedIndex; + + initData() { + _selectedIndex = 1; + _load(); + + if (_used != null) _used.close(); + _used = _getUsed(); + _used.load(); + } void initUser(user) { super.initUser(user); @@ -22,7 +45,7 @@ class DiscountModel extends BaseModel { if (listener != null) listener.cancel(); try { listener = Firestore.instance - .collection("/discounts") + .collection("/$discounts_collection") .orderBy("code", descending: false) .snapshots() .listen((snaps) { @@ -37,9 +60,42 @@ class DiscountModel extends BaseModel { } } + Paginator _getUsed() { + if (user == null || !user.hasFcsShipments()) return null; + + var pageQuery = Firestore.instance + .collection("/$discounts_collection") + .where("status", isEqualTo: fcs_shipment_shipped_status) + .orderBy("code", descending: false); + var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { + return Discount.fromMap(data, id); + }); + return paginator; + } + + Future loadMore() async { + if (_used.ended || _selectedIndex == 1) return; + isLoading = true; + notifyListeners(); + await _used.load(onFinished: () { + isLoading = false; + notifyListeners(); + }); + } + + Future refresh() async { + if (_selectedIndex == 1) return; + await _used.refresh(onFinished: () { + notifyListeners(); + }); + } + @override logout() async { - discounts = []; + if (listener != null) await listener.cancel(); + if (_used != null) _used.close(); + + _discounts = []; } Future addDiscount(Discount discount) async { diff --git a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart index f48a5d1..6d60365 100644 --- a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart +++ b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart @@ -83,7 +83,7 @@ class FcsShipmentModel extends BaseModel { } Future loadMore() async { - if (_shipped.ended && _selectedIndex == 1) return; + if (_shipped.ended || _selectedIndex == 1) return; isLoading = true; notifyListeners(); await _shipped.load(onFinished: () { @@ -132,6 +132,24 @@ class FcsShipmentModel extends BaseModel { return null; } + Future> getInvoiceFcsShipments() async { + List fcsShipments = []; + try { + var snaps = await Firestore.instance + .collection("/$fcs_shipment_collection") + .where("pending_invoice_user_count", isGreaterThan: 0) + .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); } diff --git a/lib/pages/invoice/invoce_list.dart b/lib/pages/invoice/invoce_list.dart index 03e02e9..2406a8d 100644 --- a/lib/pages/invoice/invoce_list.dart +++ b/lib/pages/invoice/invoce_list.dart @@ -77,12 +77,7 @@ class _InvoiceListState extends State { backgroundColor: primaryColor, title: LocalText(context, 'invoices.title', color: Colors.white, fontSize: 20), - actions: [ - IconButton( - icon: Icon(Icons.search, color: Colors.white), - onPressed: () {}), - popupMenu - ], + actions: [popupMenu], ), floatingActionButton: owner ? FloatingActionButton.extended( diff --git a/lib/pages/invoice/invoice_cargo_table.dart b/lib/pages/invoice/invoice_cargo_table.dart new file mode 100644 index 0000000..3ddb236 --- /dev/null +++ b/lib/pages/invoice/invoice_cargo_table.dart @@ -0,0 +1,342 @@ +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/discount.dart'; +import 'package:fcs/domain/entities/invoice.dart'; +import 'package:fcs/domain/entities/rate.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/discount/discount_list.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +typedef OnDiscountSelected(Discount discount); +typedef OnDeliveryFeeSelected(bool selected); + +class InvoiceCargoTable extends StatelessWidget { + final Invoice invoice; + final Rate rate; + final OnDiscountSelected discountSelected; + final OnDeliveryFeeSelected deliveryFeeSelected; + + const InvoiceCargoTable( + {Key key, + this.invoice, + this.discountSelected, + this.deliveryFeeSelected, + this.rate}) + : super(key: key); + @override + Widget build(BuildContext context) { + return Column(children: getRows(context)); + } + + getRows(BuildContext context) { + List _cargoTypes = invoice.getCargoTypes(rate); + double total = 0; + List dataRow = _cargoTypes.map((cargo) { + var amount = cargo.calWeight * cargo.calRate; + total += amount; + return Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.grey))), + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), + child: Row( + children: [ + Expanded(flex: 2, child: Text('${cargo.name}')), + Expanded( + flex: 2, + child: Text('${cargo.calWeight} x ${cargo.calRate}', + textAlign: TextAlign.center)), + Expanded( + child: Text('\$ $amount', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ))) + ], + ), + ); + }).toList(); + dataRow.insert( + 0, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.grey))), + child: Row( + children: [ + Expanded( + flex: 2, + child: Text(getLocalString(context, 'invoice.box.cargo_type'), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.grey))), + Expanded( + flex: 2, + child: Text( + getLocalString(context, 'cargo.weight') + + ' x ' + + getLocalString(context, 'cargo.rate'), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.grey))), + Expanded( + child: Text(getLocalString(context, 'invoice.amount'), + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.grey))) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerRight, + child: LocalText( + context, + 'invoice.total', + color: Colors.black, + ), + ), + ), + SizedBox(width: 40), + Expanded( + child: Text( + '\$ $total', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + textAlign: TextAlign.end, + )) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only(left: 5.0, right: 5.0, top: 0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerRight, + child: LocalText( + context, + 'invoice.discount_value', + color: Colors.black, + ), + ), + ), + new IconButton( + icon: Icon(Icons.search, color: primaryColor), + onPressed: () async { + Discount discount = await Navigator.of(context).push( + CupertinoPageRoute( + builder: (context) => + DiscountList(selectionMode: true))); + if (discountSelected != null) { + discountSelected(discount); + } + }), + Expanded( + child: Text('\$ ( ${invoice.getDiscount()} )', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ))) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 10.0, bottom: 0.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerRight, + child: LocalText( + context, + 'invoice.custom_fee', + color: Colors.black, + ), + ), + ), + SizedBox(width: 40), + Expanded( + child: Text('\$ ${invoice.getCustomFee()}', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + )), + ), + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only(left: 5.0, right: 5.0, top: 20.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerRight, + child: LocalText( + context, + 'invoice.handling_fee', + color: Colors.black, + ), + ), + ), + SizedBox(width: 50), + Expanded( + child: Text('\$ ${invoice.handlingFee?.toString() ?? ""}', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ))) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerRight, + child: LocalText( + context, + 'invoice.delivery_fee', + color: Colors.black, + ), + )), + Switch( + value: (invoice.deliveryFee ?? 0) > 0, + onChanged: (value) { + if (deliveryFeeSelected != null) { + deliveryFeeSelected(value); + } + }, + activeTrackColor: primaryColor.withOpacity(0.8), + activeColor: primaryColor, + ), + Expanded( + child: Text('\$ ${invoice.getDeliveryFee()}', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ))) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + child: Row( + children: [ + Expanded(child: Text('')), + Expanded( + flex: 2, + child: Divider( + thickness: 3, + )), + ], + ))); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), + child: Row( + children: [ + Expanded( + flex: 2, + child: Center( + child: LocalText( + context, + 'invoice.net_amount', + color: Colors.black, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + child: Text('\$ ${invoice.getNetAmount(rate)}', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: primaryColor))) + ], + ), + )); + + dataRow.insert( + dataRow.length, + Container( + padding: const EdgeInsets.only( + left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), + child: Row( + children: [ + Expanded( + flex: 2, + child: Center( + child: LocalText( + context, + 'invoice.balance', + color: Colors.black, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + child: Text('\$ ${invoice.getTotalBalance(rate)}', + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: primaryColor))) + ], + ), + )); + + return dataRow; + } +} diff --git a/lib/pages/invoice/invoice_carton_table.dart b/lib/pages/invoice/invoice_carton_table.dart new file mode 100644 index 0000000..d9915e6 --- /dev/null +++ b/lib/pages/invoice/invoice_carton_table.dart @@ -0,0 +1,113 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/local_title.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +typedef OnSelect = Function(Carton carton, bool checked); + +class InvoiceCartonTable extends StatelessWidget { + final List cartons; + final OnSelect onSelect; + + const InvoiceCartonTable({Key key, this.cartons, this.onSelect}) + : super(key: key); + + @override + Widget build(BuildContext context) { + final tableTitle = Container( + padding: EdgeInsets.only(right: 10.0, top: 20), + child: Row( + children: [ + SizedBox( + width: 50, + ), + SizedBox( + width: 150, + child: LocalText(context, 'invoice.box.number', color: Colors.grey), + ), + LocalText(context, 'invoice.shipment_weight', color: Colors.grey), + ], + ), + ); + + final rows = cartons == null + ? [Container()] + : cartons.asMap().entries.map((p) { + return Container( + color: p.value.isChecked + ? Colors.grey.withOpacity(0.2) + : 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: p.key == cartons.length - 1 + ? Colors.white + : Colors.grey[350], + width: 1), + ), + ), + child: Row( + children: [ + onSelect == null + ? p.value.isChecked + ? SizedBox( + child: Icon(Icons.check, color: primaryColor), + width: 30) + : SizedBox(width: 30) + : Checkbox( + value: p.value.isChecked, + activeColor: primaryColor, + onChanged: (bool check) { + if (onSelect != null) onSelect(p.value, check); + }), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + p.value.cartonNumber, + style: textStyle, + ), + Text( + p.value.shipmentNumber ?? "", + style: textStyle, + ), + ], + )), + Flexible( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + "${p.value?.length ?? ""} x ${p.value?.width ?? ""} x ${p.value?.height ?? ""}", + style: textStyle, + ), + ], + ), + ) + ], + ), + ), + ); + }).toList(); + + return Column( + children: [ + LocalTitle(textKey: "invoice.box_info"), + tableTitle, + Divider( + color: Colors.grey[400], + ), + Column( + children: rows, + ), + ], + ); + } +} diff --git a/lib/pages/invoice/invoice_custom_table.dart b/lib/pages/invoice/invoice_custom_table.dart new file mode 100644 index 0000000..cd80426 --- /dev/null +++ b/lib/pages/invoice/invoice_custom_table.dart @@ -0,0 +1,107 @@ +import 'package:fcs/domain/entities/custom_duty.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/my_data_table.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +typedef OnAdd(CustomDuty customDuty); +typedef OnRemove(CustomDuty customDuty); + +class InvoiceCustomTable extends StatelessWidget { + final List customDuties; + final OnAdd onAdd; + final OnRemove onRemove; + + const InvoiceCustomTable( + {Key key, this.customDuties, this.onAdd, this.onRemove}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return MyDataTable( + headingRowHeight: 40, + columns: [ + MyDataColumn( + label: LocalText( + context, + "rate.cutom.product_type", + color: Colors.grey, + ), + ), + MyDataColumn( + label: LocalText( + context, + "rate.custom.fee", + color: Colors.grey, + ), + ), + ], + rows: getRows(context), + ); + } + + List getRows(BuildContext context) { + if (customDuties == null) { + return []; + } + double total = 0; + var rows = customDuties.map((c) { + total += c.fee; + return MyDataRow( + cells: [ + MyDataCell(new Text( + c.productType == null ? "" : c.productType, + style: textStyle, + )), + MyDataCell( + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text(c.fee == null ? "0" : c.fee.toString(), style: textStyle), + onRemove == null + ? SizedBox( + width: 50, + ) + : IconButton( + icon: Icon( + Icons.remove_circle, + color: primaryColor, + ), + onPressed: () { + if (onRemove != null) onRemove(c); + }) + ], + ), + ), + ], + ); + }).toList(); + + var totalRow = MyDataRow( + onSelectChanged: (bool selected) {}, + cells: [ + MyDataCell(Align( + alignment: Alignment.centerRight, + child: LocalText( + context, + "invoice.total_custom_fee", + 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; + } +} diff --git a/lib/pages/invoice/invoice_customer_list.dart b/lib/pages/invoice/invoice_customer_list.dart index 5a92f12..95a4361 100644 --- a/lib/pages/invoice/invoice_customer_list.dart +++ b/lib/pages/invoice/invoice_customer_list.dart @@ -1,6 +1,6 @@ +import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/customer/customer_editor.dart'; import 'package:fcs/pages/customer/model/customer_model.dart'; import 'package:fcs/pages/invoice/invoice_editor.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -11,6 +11,10 @@ import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; class InvoiceCustomerList extends StatefulWidget { + final FcsShipment fcsShipment; + + const InvoiceCustomerList({Key key, this.fcsShipment}) : super(key: key); + @override _InvoiceCustomerListState createState() => _InvoiceCustomerListState(); } @@ -19,11 +23,24 @@ class _InvoiceCustomerListState extends State { var dateFormatter = new DateFormat('dd MMM yyyy - hh:mm:ss a'); final double dotSize = 15.0; bool _isLoading = false; + List _users = []; + @override + void initState() { + super.initState(); + _load(); + } + + _load() async { + CustomerModel customerModel = + Provider.of(context, listen: false); + var users = await customerModel.getInvoiceUsers(widget.fcsShipment.id); + setState(() { + _users = users; + }); + } @override Widget build(BuildContext context) { - var customerModel = Provider.of(context); - return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( @@ -51,9 +68,9 @@ class _InvoiceCustomerListState extends State { ), scrollDirection: Axis.vertical, shrinkWrap: true, - itemCount: customerModel.customers.length, + itemCount: _users.length, itemBuilder: (BuildContext context, int index) { - User customer = customerModel.customers[index]; + User customer = _users[index]; return _item(customer); }), ), @@ -67,7 +84,10 @@ class _InvoiceCustomerListState extends State { return InkWell( onTap: () { Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => InvoiceEditor(customer: customer))); + builder: (context) => InvoiceEditor( + customer: customer, + fcsShipment: widget.fcsShipment, + ))); }, child: Padding( padding: const EdgeInsets.only(left: 12.0, right: 12), @@ -78,21 +98,18 @@ class _InvoiceCustomerListState extends State { padding: const EdgeInsets.symmetric(vertical: 2.0), child: new Row( children: [ - InkWell( - onTap: () => _select(customer), - child: Padding( - padding: const EdgeInsets.all(5.0), - child: Container( - padding: const EdgeInsets.only( - left: 10.0, right: 10, top: 6, bottom: 6), - decoration: BoxDecoration( - color: primaryColor, - borderRadius: - BorderRadius.all(Radius.circular(35.0))), - child: Text( - customer.initial, - style: TextStyle(fontSize: 30, color: Colors.white), - ), + Padding( + padding: const EdgeInsets.all(5.0), + child: Container( + padding: const EdgeInsets.only( + left: 10.0, right: 10, top: 6, bottom: 6), + decoration: BoxDecoration( + color: primaryColor, + borderRadius: + BorderRadius.all(Radius.circular(35.0))), + child: Text( + customer.initial, + style: TextStyle(fontSize: 30, color: Colors.white), ), ), ), @@ -113,7 +130,7 @@ class _InvoiceCustomerListState extends State { Padding( padding: const EdgeInsets.only(top: 2.0), child: new Text( - customer.getLastMessage, + customer.phoneNumber, style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), @@ -140,9 +157,4 @@ class _InvoiceCustomerListState extends State { ), ); } - - _select(User customer) { - Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => CustomerEditor(customer: customer))); - } } diff --git a/lib/pages/invoice/invoice_editor.dart b/lib/pages/invoice/invoice_editor.dart index 840d4fd..4dcbb32 100644 --- a/lib/pages/invoice/invoice_editor.dart +++ b/lib/pages/invoice/invoice_editor.dart @@ -1,32 +1,28 @@ -import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/custom_duty.dart'; import 'package:fcs/domain/entities/discount.dart'; +import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/payment_method.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/carton/model/carton_model.dart'; import 'package:fcs/pages/discount/discount_list.dart'; import 'package:fcs/pages/discount/model/discount_model.dart'; -import 'package:fcs/pages/main/model/language_model.dart'; +import 'package:fcs/pages/invoice/invoice_cargo_table.dart'; +import 'package:fcs/pages/invoice/invoice_carton_table.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/payment_methods/model/payment_method_model.dart'; import 'package:fcs/pages/rates/custom_list.dart'; import 'package:fcs/pages/rates/model/shipment_rate_model.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/discount_dropdown.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; -import 'package:fcs/pages/widgets/input_text.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/multi_img_controller.dart'; -import 'package:fcs/pages/widgets/multi_img_file.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'; @@ -35,10 +31,13 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; +import 'invoice_custom_table.dart'; + class InvoiceEditor extends StatefulWidget { final Invoice invoice; final User customer; - InvoiceEditor({this.invoice, this.customer}); + final FcsShipment fcsShipment; + InvoiceEditor({this.invoice, this.customer, this.fcsShipment}); @override _InvoiceEditorState createState() => _InvoiceEditorState(); @@ -63,31 +62,27 @@ class _InvoiceEditorState extends State { Invoice _invoice; bool _isLoading = false; - List _boxes = []; + List _cartons = []; bool isSwitched = false; int deliveryfee = 0; double customFee = 10.0; double handlingFee = 10.0; // it will get from shipment double total = 0; Discount _discount; - bool isNew = false; + bool _isNew = false; Discount selectedDiscount; int selectedDiscountAmt; - PaymentMethod paymentMethod; + PaymentMethod _paymentMethod; double volumetricRatio = 0; List selectedBoxes = []; List customs = []; - List _cargoTypes = [ - CargoType(name: 'General Cargo', weight: 33, rate: 6), - CargoType(name: 'Medicine', weight: 33, rate: 7), - CargoType(name: 'Dangerous Cargo', weight: 33, rate: 8) - ]; - - List _receipts = [ - "assets/buying_online_with_first_last_name.png", - ]; + // List _cargoTypes = [ + // CargoType(name: 'General Cargo', weight: 33, rate: 6), + // CargoType(name: 'Medicine', weight: 33, rate: 7), + // CargoType(name: 'Dangerous Cargo', weight: 33, rate: 8) + // ]; @override void initState() { @@ -98,6 +93,7 @@ class _InvoiceEditorState extends State { .volumetricRatio; if (widget.invoice != null) { + _isNew = false; _invoice = widget.invoice; _invoiceNumberController.text = _invoice.invoiceNumber; _dateController.text = dateFormatter.format(_invoice.invoiceDate); @@ -114,67 +110,33 @@ class _InvoiceEditorState extends State { (_invoice.amount - _invoice.receipts[0].amount).toString(); // _boxes = _invoice.packages; } else { + _isNew = true; _dateController.text = dateFormatter.format(DateTime.now()); _amountController.text = '0'; _handlingFeeController.text = '0'; _customFeeController.text = '0'; _descriptionController.text = ''; _balanceController.text = '0'; + _invoice = Invoice(customDuties: [], cartons: []); } if (widget.customer != null && widget.invoice == null) { user = widget.customer; setState(() { - isNew = true; + _isNew = true; }); } - _boxes = [ - Carton( - shipmentNumber: "A202", - receiverNumber: "3", - receiverName: "Ko Myo Min", - boxNumber: "1", - rate: 7, - packageType: "General", - weight: 75, - status: "Packed", - receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', - cargoDesc: "Clothes", - arrivedDate: DateTime(2020, 6, 1), - width: 10, - height: 10, - length: 10, - // packages: packages, - // statusHistory: statusHistory, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Carton( - shipmentNumber: "A202", - receiverNumber: "3", - receiverName: "Ko Myo Min", - boxNumber: "2", - rate: 7, - packageType: "General", - weight: 75, - status: "Packed", - cargoDesc: "Clothes", - arrivedDate: DateTime(2020, 6, 1), - width: 10, - height: 10, - length: 10, - // statusHistory: statusHistory, - // packages: packages, - receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]) - ]; + _loadCartons(); + } + + _loadCartons() async { + CartonModel cartonModel = Provider.of(context, listen: false); + List cartons = await cartonModel.getCartonsForInvoice( + widget.fcsShipment.id, widget.customer.id); + setState(() { + _cartons = cartons; + }); } @override @@ -187,6 +149,8 @@ class _InvoiceEditorState extends State { var mainModel = Provider.of(context); var discountModel = Provider.of(context); var paymentMethodModel = Provider.of(context); + var rateModel = Provider.of(context); + var rate = rateModel.rate; final nameBox = DisplayText( iconData: Feather.user, @@ -203,6 +167,64 @@ class _InvoiceEditorState extends State { labelTextKey: "box.fcs.id", icon: FcsIDIcon(), ); + final cartonTable = InvoiceCartonTable( + cartons: _cartons, + onSelect: (c, checked) { + setState(() { + c.isChecked = checked; + }); + if (checked) { + _invoice.cartons.add(c); + } else { + _invoice.cartons.remove(c); + } + }, + ); + final customTableHeaderBox = LocalTitle( + textKey: "invoice.custom_fee", + trailing: IconButton( + icon: Icon(Icons.add_circle, color: primaryColor), + onPressed: () async { + CustomDuty customDuty = await Navigator.of(context).push( + CupertinoPageRoute( + builder: (context) => CustomList(selected: true))); + _addCustom(customDuty); + })); + final customTableBox = InvoiceCustomTable( + customDuties: _invoice.customDuties, + onAdd: (c) => _addCustom(c), + onRemove: (c) => _removeCustom(c), + ); + var paymentTypesBox = LocalDropdown( + callback: (v) { + setState(() { + _paymentMethod = v; + }); + }, + labelKey: "invoice.payment_method", + iconData: FontAwesome.money, + display: (u) => u.name, + selectedValue: _paymentMethod, + values: paymentMethodModel.paymentMethods, + ); + final cargoTypeTableBox = InvoiceCargoTable( + invoice: _invoice, + rate: rate, + deliveryFeeSelected: (selected) { + setState(() { + if (selected) { + _invoice.deliveryFee = rate.deliveryFee; + } else { + _invoice.deliveryFee = 0; + } + }); + }, + discountSelected: (discount) { + setState(() { + _invoice.discount = discount; + }); + }, + ); return LocalProgress( inAsyncCall: _isLoading, @@ -235,59 +257,19 @@ class _InvoiceEditorState extends State { text: _invoiceNumberController.text), fcsIDBox, nameBox, - isNew ? Container() : statusBox, + _isNew ? Container() : statusBox, SizedBox(height: 20), - LocalTitle(textKey: "invoice.box_info"), - Center(child: Column(children: getCartonRows(context))), - SizedBox(height: 20), - LocalTitle( - textKey: "invoice.custom_fee", - trailing: IconButton( - icon: Icon(Icons.add_circle, color: primaryColor), - onPressed: () async { - CustomDuty custom = await Navigator.of(context).push( - CupertinoPageRoute( - builder: (context) => - CustomList(selected: true))); - setState(() { - if (custom != null) customs.add(custom); - }); - })), - Column(children: getCustomFeeRows(context)), + customTableHeaderBox, + customTableBox, SizedBox(height: 20), + cartonTable, LocalTitle(textKey: "invoice.cargo_type"), - Column(children: getCargoTableByBox(context)), + cargoTypeTableBox, + // Column(children: getCargoTableByBox(context)), SizedBox(height: 20), - Container( - padding: EdgeInsets.only(top: 5, left: 18), - child: Row( - children: [ - Expanded( - child: LocalText(context, 'invoice.payment_method', - fontSize: 16, - color: Colors.grey, - fontWeight: FontWeight.bold), - ), - Container( - width: 150.0, - child: DropdownButtonFormField( - icon: Icon( - Icons.edit, - color: primaryColor, - ), - value: paymentMethod, - items: paymentMethodModel.paymentMethods - .map((e) => DropdownMenuItem( - child: Text(e.name), value: e.name)) - .toList(), - onChanged: (selected) => {}, - ), - ), - ], - ), - ), + paymentTypesBox, SizedBox(height: 20), - isNew + _isNew ? Container() : LocalTitle( textKey: "invoice.payment_attachment", @@ -306,7 +288,7 @@ class _InvoiceEditorState extends State { getLocalString(context, 'invoice.btn_save')) ], )), - isNew + _isNew ? Container() : fcsButton(context, getLocalString(context, 'invoice.btn_payment_receipt')) @@ -317,493 +299,6 @@ class _InvoiceEditorState extends State { ); } - getCartonRows(BuildContext context) { - List dataRow = []; - - dataRow = _boxes.map((box) { - return Container( - height: 50, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - padding: - const EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0, bottom: 5.0), - child: Row( - children: [ - Container( - width: 35, - child: Checkbox( - value: true, onChanged: (v) {}, activeColor: primaryColor), - ), - Expanded( - flex: 1, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(box.packageNumber), - Text(box.shipmentNumber), - ], - )), - Expanded( - flex: 2, - child: Text( - box.length == null - ? "" - : box.length.toString() + - ' x ' + - box.length.toString() + - ' x ' + - box.height.toString(), - textAlign: TextAlign.center)), - Expanded( - flex: 2, - child: Center( - child: Text( - box.getShipmentWeight(volumetricRatio).toString()))), - ], - ), - ); - }).toList(); - - dataRow.insert( - 0, - Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 5.0, bottom: 15.0), - child: Row( - children: [ - Container(width: 33), - Expanded( - flex: 1, - child: Center( - child: LocalText( - context, - "invoice.box.number", - color: Colors.grey, - ), - )), - Expanded( - flex: 2, - child: Center( - child: Text('L x W x H', - style: TextStyle(color: Colors.grey)))), - Expanded( - flex: 2, - child: Center( - child: LocalText( - context, - "invoice.shipment_weight", - color: Colors.grey, - ), - )), - ], - ), - )); - - return dataRow; - } - - getCustomFeeRows(BuildContext context) { - customFee = 0; - List dataRow = []; - - dataRow = customs.map((custom) { - customFee += custom.fee; - return Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - padding: - const EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0, bottom: 5.0), - child: Row( - children: [ - Expanded(flex: 2, child: Text('${custom.productType}')), - Expanded( - flex: 1, - child: Text('\$ ${custom.fee}', textAlign: TextAlign.center)), - Expanded( - child: IconButton( - icon: Icon(Icons.remove_circle, color: primaryColor), - onPressed: () { - customs.remove(custom); - })) - ], - ), - ); - }).toList(); - - dataRow.insert( - 0, - Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), - child: Row( - children: [ - Expanded( - flex: 2, - child: Text('Product', style: TextStyle(color: Colors.grey))), - Expanded( - flex: 1, - child: Text('Fee', - textAlign: TextAlign.center, - style: TextStyle(color: Colors.grey))), - Expanded(flex: 1, child: Container()) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), - child: Row( - children: [ - Expanded( - flex: 2, - child: Center( - child: LocalText( - context, - 'invoice.total_custom_fee', - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - Expanded( - flex: 1, - child: Center( - child: Text('\$ $customFee', - textAlign: TextAlign.center, - style: TextStyle(fontWeight: FontWeight.bold)))), - Expanded( - child: Container(), - ) - ], - ), - )); - return dataRow; - } - - getCargoTableByBox(BuildContext context) { - var discountModel = Provider.of(context); - total = 0; - List dataRow = _cargoTypes.map((cargo) { - var amount = cargo.weight * cargo.rate; - total += amount; - return Container( - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), - child: Row( - children: [ - Expanded(flex: 2, child: Text('${cargo.name}')), - Expanded( - flex: 2, - child: Text('${cargo.weight} x ${cargo.rate}', - textAlign: TextAlign.center)), - Expanded( - child: Text('\$ $amount', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ))) - ], - ), - ); - }).toList(); - dataRow.insert( - 0, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey))), - child: Row( - children: [ - Expanded( - flex: 2, - child: Text(getLocalString(context, 'invoice.box.cargo_type'), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.grey))), - Expanded( - flex: 2, - child: Text( - getLocalString(context, 'cargo.weight') + - ' x ' + - getLocalString(context, 'cargo.rate'), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.grey))), - Expanded( - child: Text(getLocalString(context, 'invoice.amount'), - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.grey))) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerRight, - child: LocalText( - context, - 'invoice.total', - color: Colors.black, - ), - ), - ), - SizedBox(width: 40), - Expanded( - child: Text( - '\$ $total', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - textAlign: TextAlign.end, - )) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only(left: 5.0, right: 5.0, top: 0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerRight, - child: LocalText( - context, - 'invoice.discount_value', - color: Colors.black, - ), - ), - ), - new IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () async { - Discount discount = await Navigator.of(context).push( - CupertinoPageRoute( - builder: (context) => - DiscountList(selected: true))); - setState(() { - if (discount != null) _discount = discount; - }); - }), - Expanded( - child: Text( - '\$ ( ${_discount != null ? _discount.amount.toInt() : 0} )', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ))) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 10.0, bottom: 0.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerRight, - child: LocalText( - context, - 'invoice.custom_fee', - color: Colors.black, - ), - ), - ), - SizedBox(width: 40), - Expanded( - child: Text('\$ ${customFee}', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - )), - ), - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only(left: 5.0, right: 5.0, top: 20.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerRight, - child: LocalText( - context, - 'invoice.handling_fee', - color: Colors.black, - ), - ), - ), - SizedBox(width: 50), - Expanded( - child: Text('\$ ${handlingFee.toString()}', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ))) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), - child: Row( - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerRight, - child: LocalText( - context, - 'invoice.delivery_fee', - color: Colors.black, - ), - )), - Switch( - value: isSwitched, - onChanged: (value) { - setState(() { - isSwitched = value; - if (value) { - deliveryfee = 5; - } else { - deliveryfee = 0; - } - print(isSwitched); - }); - }, - activeTrackColor: primaryColor.withOpacity(0.8), - activeColor: primaryColor, - ), - Expanded( - child: Text('\$ $deliveryfee', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - ))) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - child: Row( - children: [ - Expanded(child: Text('')), - Expanded( - flex: 2, - child: Divider( - thickness: 3, - )), - ], - ))); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), - child: Row( - children: [ - Expanded( - flex: 2, - child: Center( - child: LocalText( - context, - 'invoice.net_amount', - color: Colors.black, - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ), - Expanded( - child: Text('\$ ${getTotalBalance(total)}', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: primaryColor))) - ], - ), - )); - - dataRow.insert( - dataRow.length, - Container( - padding: const EdgeInsets.only( - left: 5.0, right: 5.0, top: 10.0, bottom: 10.0), - child: Row( - children: [ - Expanded( - flex: 2, - child: Center( - child: LocalText( - context, - 'invoice.balance', - color: Colors.black, - fontSize: 15, - fontWeight: FontWeight.bold, - ), - ), - ), - Expanded( - child: Text('\$ ${getTotalBalance(total)}', - textAlign: TextAlign.end, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: primaryColor))) - ], - ), - )); - - return dataRow; - } - getTotalBalance(total) { double balance = 0; double custom = customFee != 0 ? customFee.toDouble() : 0; @@ -813,78 +308,19 @@ class _InvoiceEditorState extends State { return balance; } - List getBoxRow(BuildContext context) { - return _boxes.map((p) { - p.cargoTypes.map((cargo) { - _cargoTypes.asMap().map((index, _cargo) { - if (_cargo.id == cargo.id) { - setState(() { - _cargoTypes[index].weight += cargo.weight; - }); - } - }); - }); - return MyDataRow( - onSelectChanged: (bool selected) {}, - cells: [ - MyDataCell(Checkbox( - value: true, - onChanged: (value) { - selectedBoxes.add(p); - }, - )), - MyDataCell(new Text( - p.boxNumber == null - ? "" - : '${p.shipmentNumber}-${p.receiverNumber} #${p.boxNumber}', - style: textStyle, - )), - MyDataCell(new Text( - p.length == null - ? "" - : p.length.toString() + - ' x ' + - p.length.toString() + - ' x ' + - p.height.toString(), - style: textStyle, - )), - ], - ); - }).toList(); + _addCustom(CustomDuty customDuty) { + if (customDuty == null) return; + setState(() { + _invoice.customDuties.remove(customDuty); + _invoice.customDuties.add(customDuty); + }); } - List getCargoDataRow(BuildContext context) { - return _cargoTypes.asMap().entries.map((c) { - var cargo = c.value; - var amt = cargo.weight * cargo.rate; - return MyDataRow( - onSelectChanged: (bool selected) {}, - cells: [ - MyDataCell(new Text( - cargo.name, - style: textStyle, - )), - MyDataCell(new Text( - cargo.weight.toString() + ' x ' + cargo.rate.toString(), - style: textStyle, - )), - MyDataCell(new Text( - "\$$amt", - style: textStyle, - )), - ], - ); - }).toList() - // .insert(_cargoTypes.length,MyDataRow(cells: [ - // MyDataCell(new Text('')), - // MyDataCell(new Text('Total')), - // MyDataCell(new Text( - // "\$5000", - // style: textStyle, - // )), - // ]) - // ) - ; + _removeCustom(CustomDuty customDuty) { + setState(() { + _invoice.customDuties.remove(customDuty); + }); } + + _save() {} } diff --git a/lib/pages/invoice/invoice_shipment_list.dart b/lib/pages/invoice/invoice_shipment_list.dart index 2dc763c..9a5575a 100644 --- a/lib/pages/invoice/invoice_shipment_list.dart +++ b/lib/pages/invoice/invoice_shipment_list.dart @@ -1,3 +1,4 @@ +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/shipment/model/shipment_model.dart'; @@ -16,10 +17,20 @@ class InvoiceShipmentList extends StatefulWidget { class _InvoiceShipmentListState extends State { bool _isLoading = false; - + List _fcsShipments = []; @override void initState() { super.initState(); + _load(); + } + + _load() async { + FcsShipmentModel fcsShipmentModel = + Provider.of(context, listen: false); + var fcsShipments = await fcsShipmentModel.getInvoiceFcsShipments(); + setState(() { + _fcsShipments = fcsShipments; + }); } @override @@ -29,7 +40,6 @@ class _InvoiceShipmentListState extends State { @override Widget build(BuildContext context) { - FcsShipmentModel fcsShipmentModel = Provider.of(context); return LocalProgress( inAsyncCall: _isLoading, child: DefaultTabController( @@ -42,18 +52,8 @@ class _InvoiceShipmentListState extends State { onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, - title: LocalText(context, "shipment", + title: LocalText(context, "invoice.shipment.title", fontSize: 18, color: Colors.white), - actions: [ - IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, - // onPressed: () => showPlacesSearch(context), - ), - ], ), body: new ListView.separated( separatorBuilder: (context, index) => Divider( @@ -62,10 +62,10 @@ class _InvoiceShipmentListState extends State { scrollDirection: Axis.vertical, padding: EdgeInsets.only(top: 15), shrinkWrap: true, - itemCount: fcsShipmentModel.fcsShipments.length, + itemCount: _fcsShipments.length, itemBuilder: (BuildContext context, int index) { return InvoiceShipmentListRow( - fcsShipment: fcsShipmentModel.fcsShipments[index]); + fcsShipment: _fcsShipments[index]); }), ), ), diff --git a/lib/pages/invoice/invoice_shipment_list_row.dart b/lib/pages/invoice/invoice_shipment_list_row.dart index 739bf4b..c0f6df2 100644 --- a/lib/pages/invoice/invoice_shipment_list_row.dart +++ b/lib/pages/invoice/invoice_shipment_list_row.dart @@ -35,8 +35,10 @@ class _InvoiceShipmentListRowState extends State { padding: EdgeInsets.only(left: 15, right: 15), child: InkWell( onTap: () { - Navigator.of(context).push( - CupertinoPageRoute(builder: (context) => InvoiceCustomerList())); + Navigator.of(context).push(CupertinoPageRoute( + builder: (context) => InvoiceCustomerList( + fcsShipment: _fcsShipment, + ))); }, child: Row( children: [ diff --git a/lib/pages/invoice/model/invoice_model.dart b/lib/pages/invoice/model/invoice_model.dart index 12550d6..fa74b18 100644 --- a/lib/pages/invoice/model/invoice_model.dart +++ b/lib/pages/invoice/model/invoice_model.dart @@ -130,8 +130,8 @@ class InvoiceModel extends BaseModel { } Future loadMore({bool isCustomer}) async { - if (_selectedIndex == 1) return; // when paid menu is not selected return - if (_paid.ended) return; + if (_paid.ended || _selectedIndex == 1) + return; // when paid menu is not selected return isLoading = true; notifyListeners(); await _paid.load(onFinished: () { diff --git a/lib/pages/main/model/main_model.dart b/lib/pages/main/model/main_model.dart index 866b13c..5f2180e 100644 --- a/lib/pages/main/model/main_model.dart +++ b/lib/pages/main/model/main_model.dart @@ -148,7 +148,9 @@ class MainModel extends ChangeNotifier { } Future signout() async { - await removeMsgToken(); + try { + await removeMsgToken(); + } catch (e) {} await Services.instance.authService.signout(); models.forEach((m) => m.logout()); } diff --git a/lib/pages/package/package_info.dart b/lib/pages/package/package_info.dart index 83bc1d1..7380cd8 100644 --- a/lib/pages/package/package_info.dart +++ b/lib/pages/package/package_info.dart @@ -25,10 +25,12 @@ import 'package:provider/provider.dart'; final DateFormat dateFormat = DateFormat("d MMM yyyy"); class PackageInfo extends StatefulWidget { + final isCustomer; final isSearchResult; final Package package; - PackageInfo({this.package, this.isSearchResult = false}); + PackageInfo( + {this.package, this.isSearchResult = false, this.isCustomer = false}); @override _PackageInfoState createState() => _PackageInfoState(); @@ -156,7 +158,8 @@ class _PackageInfoState extends State { _package.photoUrls.length == 0 ? Container() : img, widget.isSearchResult ? Container() : descBox, remarkBox, - _package.status == package_processed_status + _package.status == package_received_status && + widget.isCustomer ? returnButton : Container(), widget.isSearchResult ? Container() : deliveryAddressBox, diff --git a/lib/pages/package/package_list.dart b/lib/pages/package/package_list.dart index 701058c..6d3c3f6 100644 --- a/lib/pages/package/package_list.dart +++ b/lib/pages/package/package_list.dart @@ -106,6 +106,7 @@ class _PackageListState extends State { return PackageListRow( key: ValueKey(packages[index].id), package: packages[index], + isCustomer: widget.forCustomer, ); }), onRefresh: () => diff --git a/lib/pages/package/package_list_row.dart b/lib/pages/package/package_list_row.dart index e793a6f..ea6052c 100644 --- a/lib/pages/package/package_list_row.dart +++ b/lib/pages/package/package_list_row.dart @@ -10,12 +10,14 @@ import 'package:intl/intl.dart'; typedef CallbackPackageSelect(Package package); class PackageListRow extends StatelessWidget { + final bool isCustomer; final Package package; final CallbackPackageSelect callbackPackageSelect; final double dotSize = 15.0; final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); - PackageListRow({Key key, this.package, this.callbackPackageSelect}) + PackageListRow( + {Key key, this.package, this.callbackPackageSelect, this.isCustomer}) : super(key: key); @override @@ -29,7 +31,10 @@ class PackageListRow extends StatelessWidget { Navigator.push( context, CupertinoPageRoute( - builder: (context) => PackageInfo(package: package)), + builder: (context) => PackageInfo( + package: package, + isCustomer: isCustomer, + )), ); }, child: Container( diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart index 398739b..67395f9 100644 --- a/lib/pages/profile/profile_page.dart +++ b/lib/pages/profile/profile_page.dart @@ -301,8 +301,6 @@ class _ProfileState extends State { }); try { await context.read().signout(); - Navigator.of(context).pushNamedAndRemoveUntil( - "/welcome", ModalRoute.withName('/welcome')); } catch (e) {} finally { Future.delayed(Duration(seconds: 1), () { if (mounted) { @@ -311,6 +309,8 @@ class _ProfileState extends State { }); } }); + Navigator.of(context).pushNamedAndRemoveUntil( + "/welcome", ModalRoute.withName('/welcome')); } }); } diff --git a/lib/pages/shipment/shipment_list.dart b/lib/pages/shipment/shipment_list.dart index bb7c9a8..9932bf7 100644 --- a/lib/pages/shipment/shipment_list.dart +++ b/lib/pages/shipment/shipment_list.dart @@ -88,19 +88,7 @@ class _ShipmentListState extends State { backgroundColor: primaryColor, title: LocalText(context, "shipment", fontSize: 18, color: Colors.white), - actions: [ - widget.forCustomer - ? Container() - : IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, - // onPressed: () => showPlacesSearch(context), - ), - popupMenu - ], + actions: [popupMenu], ), floatingActionButton: widget.forCustomer ? FloatingActionButton.extended(