update invoice

This commit is contained in:
PhyoThandar
2020-10-16 21:38:39 +06:30
parent ad7d0039fc
commit 274c999959
18 changed files with 658 additions and 398 deletions

View File

@@ -16,13 +16,12 @@ import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'invoice_editor.dart';
import 'invoice_list_row.dart';
class InvoiceList extends StatefulWidget {
final bool onlyFcs;
final bool forCustomer;
const InvoiceList({Key key, this.onlyFcs}) : super(key: key);
const InvoiceList({Key key, this.forCustomer}) : super(key: key);
@override
_InvoiceListState createState() => _InvoiceListState();
}
@@ -35,14 +34,13 @@ class _InvoiceListState extends State<InvoiceList> {
@override
void initState() {
super.initState();
// Provider.of<InvoiceModel>(context, listen: false).initPaidInvoice(true);
// _controller.addListener(() {
// if (_showPaid &&
// _controller.position.pixels == _controller.position.maxScrollExtent) {
// Provider.of<InvoiceModel>(context, listen: false)
// .loadMorePaidInvoices();
// }
// });
_controller.addListener(() async {
if (_controller.position.pixels == _controller.position.maxScrollExtent) {
Provider.of<InvoiceModel>(context, listen: false).loadMore(isCustomer: widget.forCustomer);
}
});
Provider.of<InvoiceModel>(context, listen: false).initData(false);
}
@override
@@ -54,15 +52,17 @@ class _InvoiceListState extends State<InvoiceList> {
Widget build(BuildContext context) {
var owner = true;
var invoiceModel = Provider.of<InvoiceModel>(context);
bool onlyFcs = widget.onlyFcs;
var invoices =
_showPaid ? invoiceModel.paidInvoices : invoiceModel.invoices;
final popupMenu = LocalPopupMenuButton(
popmenus: [
LocalPopupMenu(
id: 1, textKey: "invoice.popupmenu.pending", selected: true),
LocalPopupMenu(id: 2, textKey: "invoice.popupmenu.paid")
id: 1,
textKey: "invoice.popupmenu.pending",
selected: invoiceModel.selectedIndex == 1),
LocalPopupMenu(
id: 2,
textKey: "invoice.popupmenu.paid",
selected: invoiceModel.selectedIndex == 2)
],
popupMenuCallback: (p) => this.setState(() {
_showPaid = p.id == 2;
@@ -104,18 +104,38 @@ class _InvoiceListState extends State<InvoiceList> {
body: Column(
children: <Widget>[
Expanded(
child: new ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(top: 15),
shrinkWrap: true,
itemCount: invoices.length,
itemBuilder: (BuildContext context, int index) {
return InvoiceListRow(invoice: invoices[index]);
}),
child: RefreshIndicator(
child: ListView.separated(
physics: AlwaysScrollableScrollPhysics(),
controller: _controller,
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(top: 15),
shrinkWrap: true,
itemCount: invoiceModel.invoices.length,
itemBuilder: (BuildContext context, int index) {
return InvoiceListRow(
key: ValueKey(invoiceModel.invoices[index].id),
invoice: invoiceModel.invoices[index]);
}),
onRefresh: () => invoiceModel.refresh(),
),
),
invoiceModel.isLoading
? Container(
padding: EdgeInsets.all(8),
color: primaryColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Loading...",
style: TextStyle(color: Colors.white)),
],
),
)
: Container(),
],
)),
),

View File

@@ -35,8 +35,6 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'box_addition.dart';
class InvoiceEditor extends StatefulWidget {
final Invoice invoice;
final User customer;
@@ -68,8 +66,8 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
List<Box> _boxes = [];
bool isSwitched = false;
int deliveryfee = 0;
double customFee = 10;
int handlingFee = 0;
double customFee = 10.0;
double handlingFee = 10.0; // it will get from shipment
double total = 0;
Discount _discount;
bool isNew = false;
@@ -124,7 +122,7 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
_balanceController.text = '0';
}
if (widget.customer != null) {
if (widget.customer != null && widget.invoice == null) {
user = widget.customer;
setState(() {
isNew = true;
@@ -193,29 +191,17 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
final nameBox = DisplayText(
iconData: Feather.user,
labelTextKey: 'invoice.customer_name',
text: user != null ? user.name : '');
text: user != null ? user.name : 'Ko Nyi');
final statusBox = DisplayText(
text: _statusController.text,
iconData: Icons.av_timer,
labelTextKey: 'invoice.status');
final fcsIDBox = Row(
children: <Widget>[
Expanded(
child: DisplayText(
text: user != null ? user.fcsID : "",
labelTextKey: "box.fcs.id",
icon: FcsIDIcon(),
)),
IconButton(
icon: Icon(Icons.search, color: primaryColor),
onPressed: () => searchUser(context, callbackUserSelect: (u) {
setState(() {
this.user = u;
});
})),
],
final fcsIDBox = DisplayText(
text: user != null ? user.fcsID : "FCS-KRUTUG",
labelTextKey: "box.fcs.id",
icon: FcsIDIcon(),
);
return LocalProgress(
@@ -249,7 +235,7 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
text: _invoiceNumberController.text),
fcsIDBox,
nameBox,
isNew ? statusBox : Container(),
isNew ? Container() : statusBox,
SizedBox(height: 20),
LocalTitle(textKey: "invoice.box_info"),
Center(child: Column(children: getCartonRows(context))),
@@ -261,7 +247,8 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
onPressed: () async {
CustomDuty custom = await Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => CustomList()));
builder: (context) =>
CustomList(selected: true)));
setState(() {
if (custom != null) customs.add(custom);
});
@@ -300,11 +287,13 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
),
),
SizedBox(height: 20),
LocalTitle(
textKey: "invoice.payment_attachment",
trailing: IconButton(
icon: Icon(Icons.add_circle, color: primaryColor),
onPressed: () async {})),
isNew
? Container()
: LocalTitle(
textKey: "invoice.payment_attachment",
trailing: IconButton(
icon: Icon(Icons.add_circle, color: primaryColor),
onPressed: () async {})),
widget.invoice == null
? fcsButton(
context, getLocalString(context, 'invoice.btn_create'))
@@ -341,13 +330,21 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
child: Row(
children: [
Container(
width: 33,
width: 35,
child: Checkbox(
value: true, onChanged: (v) {}, activeColor: primaryColor),
),
Expanded(flex: 1, child: Text(box.packageNumber)),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(box.packageNumber),
Text(box.shipmentNumber),
],
)),
Expanded(
flex: 2,
child: Text(
box.length == null
? ""
@@ -387,7 +384,7 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
),
)),
Expanded(
flex: 1,
flex: 2,
child: Center(
child: Text('L x W x H',
style: TextStyle(color: Colors.grey)))),
@@ -674,11 +671,9 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
),
),
),
new IconButton(
icon: Icon(Icons.edit, color: primaryColor),
onPressed: () async {}),
SizedBox(width: 50),
Expanded(
child: Text('\$ $handlingFee',
child: Text('\$ ${handlingFee.toString()}',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,

View File

@@ -36,11 +36,10 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'box_addition.dart';
class InvoiceInfoPage extends StatefulWidget {
final Invoice invoice;
InvoiceInfoPage({this.invoice});
final User customer;
InvoiceInfoPage({this.invoice, this.customer});
@override
_InvoiceInfoPageState createState() => _InvoiceInfoPageState();
@@ -57,7 +56,6 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
TextEditingController _discountController = new TextEditingController();
TextEditingController _amountController = new TextEditingController();
TextEditingController _statusController = new TextEditingController();
TextEditingController _handlingFeeController = new TextEditingController();
TextEditingController _customFeeController = new TextEditingController();
MultiImgController multiImgController = MultiImgController();
TextEditingController _descriptionController = new TextEditingController();
@@ -106,7 +104,6 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
// _amountController.text = _invoice.getAmount.toString();
_amountController.text = _invoice.amount.toString();
_statusController.text = _invoice.status.toString();
_handlingFeeController.text = '0';
_customFeeController.text = '0';
// multiImgController.setImageUrls = _receipts;
_descriptionController.text = 'For Electronics goods';
@@ -116,7 +113,6 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
} else {
_dateController.text = dateFormatter.format(DateTime.now());
_amountController.text = '0';
_handlingFeeController.text = '0';
_customFeeController.text = '0';
_descriptionController.text = '';
_balanceController.text = '0';
@@ -180,31 +176,15 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
@override
Widget build(BuildContext context) {
var mainModel = Provider.of<MainModel>(context);
var discountModel = Provider.of<DiscountModel>(context);
var paymentMethodModel = Provider.of<PaymentMethodModel>(context);
final nameBox = DisplayText(
iconData: Feather.user,
labelTextKey: 'invoice.customer_name',
text: user != null ? user.name : '');
text: user != null ? user.name : 'Ko Nyi');
final fcsIDBox = Row(
children: <Widget>[
Expanded(
child: DisplayText(
text: user != null ? user.fcsID : "",
labelTextKey: "box.fcs.id",
icon: FcsIDIcon(),
)),
IconButton(
icon: Icon(Icons.search, color: primaryColor),
onPressed: () => searchUser(context, callbackUserSelect: (u) {
setState(() {
this.user = u;
});
})),
],
final fcsIDBox = DisplayText(
text: user != null ? user.fcsID : "FCS-KRUTUG",
labelTextKey: "box.fcs.id",
icon: FcsIDIcon(),
);
final statusBox = DisplayText(
@@ -309,9 +289,17 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
const EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0, bottom: 5.0),
child: Row(
children: [
Expanded(flex: 2, child: Text(box.packageNumber)),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(box.packageNumber),
Text(box.shipmentNumber),
],
)),
Expanded(
flex: 2,
child: Text(
box.length == null
? ""
@@ -341,22 +329,27 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
child: Row(
children: [
Expanded(
flex: 2,
child: LocalText(
context,
"invoice.box.number",
color: Colors.grey,
flex: 1,
child: Center(
child: LocalText(
context,
"invoice.box.number",
color: Colors.grey,
),
)),
Expanded(
flex: 1,
child:
Text('L x W x H', style: TextStyle(color: Colors.grey))),
flex: 2,
child: Center(
child: Text('L x W x H',
style: TextStyle(color: Colors.grey)))),
Expanded(
flex: 2,
child: LocalText(
context,
"invoice.shipment_weight",
color: Colors.grey,
child: Center(
child: LocalText(
context,
"invoice.shipment_weight",
color: Colors.grey,
),
)),
],
),
@@ -596,7 +589,7 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 20.0, bottom: 0.0),
left: 5.0, right: 5.0, top: 20.0, bottom: 5.0),
child: Row(
children: [
Expanded(
@@ -609,7 +602,7 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
),
)),
Expanded(
child: Text('\$ $customFee',
child: Text('\$ 10.0',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,

View File

@@ -18,7 +18,7 @@ import 'payment_pdf_screen.dart';
class InvoiceListRow extends StatefulWidget {
final Invoice invoice;
const InvoiceListRow({this.invoice});
InvoiceListRow({Key key, this.invoice}) : super(key: key);
@override
_InvoiceListRowState createState() => _InvoiceListRowState();

View File

@@ -1,4 +1,5 @@
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';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
@@ -28,7 +29,7 @@ class _InvoiceShipmentListState extends State<InvoiceShipmentList> {
@override
Widget build(BuildContext context) {
ShipmentModel shipmentModel = Provider.of<ShipmentModel>(context);
FcsShipmentModel fcsShipmentModel = Provider.of<FcsShipmentModel>(context);
return LocalProgress(
inAsyncCall: _isLoading,
child: DefaultTabController(
@@ -61,10 +62,10 @@ class _InvoiceShipmentListState extends State<InvoiceShipmentList> {
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(top: 15),
shrinkWrap: true,
itemCount: shipmentModel.shipments.length,
itemCount: fcsShipmentModel.fcsShipments.length,
itemBuilder: (BuildContext context, int index) {
return InvoiceShipmentListRow(
pickUp: shipmentModel.shipments[index]);
fcsShipment: fcsShipmentModel.fcsShipments[index]);
}),
),
),

View File

@@ -1,15 +1,16 @@
import 'package:fcs/domain/entities/shipment.dart';
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:intl/intl.dart';
import '../main/util.dart';
import 'invoice_customer_list.dart';
class InvoiceShipmentListRow extends StatefulWidget {
final Shipment pickUp;
const InvoiceShipmentListRow({this.pickUp});
final FcsShipment fcsShipment;
const InvoiceShipmentListRow({this.fcsShipment});
@override
_InvoiceShipmentListRowState createState() => _InvoiceShipmentListRowState();
@@ -17,13 +18,14 @@ class InvoiceShipmentListRow extends StatefulWidget {
class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
final double dotSize = 15.0;
Shipment _pickUp = new Shipment();
final dateFormatter = new DateFormat('dd MMM yyyy');
FcsShipment _fcsShipment = new FcsShipment();
@override
void initState() {
super.initState();
if (widget.pickUp != null) {
_pickUp = widget.pickUp;
if (widget.fcsShipment != null) {
_fcsShipment = widget.fcsShipment;
}
}
@@ -40,15 +42,17 @@ class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
children: <Widget>[
Expanded(
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
children: <Widget>[
Padding(
padding: EdgeInsets.all(5.0),
child: Icon(
SimpleLineIcons.direction,
color: primaryColor,
)),
Container(
padding: EdgeInsets.only(left: 5, right: 10),
child: Icon(
Ionicons.ios_airplane,
color: primaryColor,
size: 30,
),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -56,7 +60,9 @@ class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: new Text(
_pickUp.id == null ? '' : _pickUp.id,
_fcsShipment.shipmentNumber == null
? ''
: _fcsShipment.shipmentNumber,
style: new TextStyle(
fontSize: 15.0, color: Colors.black),
),
@@ -64,9 +70,7 @@ class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10),
child: new Text(
_pickUp.id == null
? ''
: "Last ${_pickUp.last} days",
dateFormatter.format(_fcsShipment.cutoffDate),
style: new TextStyle(
fontSize: 15.0, color: Colors.grey),
),
@@ -78,35 +82,10 @@ class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
),
),
),
Column(
children: <Widget>[
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: <Widget>[
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),
),
],
),
),
],
)
Padding(
padding: const EdgeInsets.all(0),
child: getStatus(_fcsShipment.status),
),
],
),
),

View File

@@ -1,118 +1,22 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/package.dart';
import 'package:fcs/domain/entities/receipt.dart';
import 'package:fcs/helpers/pagination.dart';
import 'package:fcs/domain/vo/message.dart';
import 'package:fcs/helpers/paginator.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:logging/logging.dart';
import 'package:fcs/domain/constants.dart';
class InvoiceModel extends BaseModel {
final log = Logger('InvoiceModel');
Pagination pagination;
StreamSubscription<QuerySnapshot> listener;
List<Invoice> invoices = [
Invoice(
invoiceNumber: 'A092(A)-30',
invoiceDate: DateTime(2020, 4, 5, 12, 30),
customerName: 'Ko Nyi',
customerPhoneNumber: '+959 888888888',
amount: 500,
status: 'Pending',
packages: [
Package(
shipmentNumber: "A202",
receiverNumber: "3",
boxNumber: "1",
rate: 7,
packageType: "General",
weight: 25,
status: "Received",
receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon',
arrivedDate: DateTime(2020, 6, 1),
),
Package(
shipmentNumber: "A202",
receiverNumber: "3",
boxNumber: "2",
rate: 7,
packageType: "General",
weight: 20,
status: "Received",
arrivedDate: DateTime(2020, 6, 1),
receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'),
],
receipts: [
Receipt(amount: 200, date: DateTime(2020, 6, 1)),
Receipt(amount: 100, date: DateTime(2020, 6, 16)),
]),
Invoice(
invoiceNumber: 'A092(A)-31',
invoiceDate: DateTime(2020, 4, 5, 9, 30),
customerName: 'Ko Aung Myo',
customerPhoneNumber: '+959 444444444',
amount: 300,
status: 'Paid',
packages: [
Package(
shipmentNumber: "A202",
receiverNumber: "3",
boxNumber: "3",
rate: 7,
packageType: "General",
weight: 15,
status: "Received",
arrivedDate: DateTime(2020, 6, 1),
receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'),
Package(
shipmentNumber: "A202",
receiverNumber: "2",
boxNumber: "1",
rate: 8,
packageType: "Medicine",
weight: 15,
status: "Processing",
arrivedDate: DateTime(2020, 6, 1),
receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'),
],
receipts: [
Receipt(amount: 200, date: DateTime(2020, 6, 1)),
]),
Invoice(
invoiceNumber: 'A092(A)-32',
invoiceDate: DateTime(2020, 4, 6, 10, 10),
customerName: 'Ko Zaw Thu',
customerPhoneNumber: '+959 777777777',
amount: 200,
status: 'Paid',
packages: [
Package(
shipmentNumber: "A202",
receiverNumber: "2",
boxNumber: "2",
rate: 7,
packageType: "General",
weight: 55,
status: "Ready to ship",
arrivedDate: DateTime(2020, 6, 1),
receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'),
Package(
shipmentNumber: "A201",
receiverNumber: "1",
boxNumber: "1",
rate: 9,
packageType: "Dangerous",
weight: 25,
status: "Delivered",
arrivedDate: DateTime(2020, 5, 21),
receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon'),
],
receipts: [
Receipt(amount: 200, date: DateTime(2020, 6, 1)),
]),
List<Invoice> _invoices = [
Invoice(
invoiceNumber: 'A092(A)-33',
invoiceDate: DateTime(2020, 4, 6, 12, 15),
@@ -121,7 +25,7 @@ class InvoiceModel extends BaseModel {
amount: 300,
status: 'Pending',
receipts: [
Receipt(amount: 200, date: DateTime(2020, 6, 1)),
Receipt(amount: 200, date: '1 Jun 2020'),
],
packages: [
Package(
@@ -147,29 +51,55 @@ class InvoiceModel extends BaseModel {
])
];
List<Invoice> paidInvoices = [];
List<Invoice> get invoices =>
_selectedIndex == 1 ? _invoices : List<Invoice>.from(_paid.values);
Paginator _paid;
bool endOfPaidInvoices = false;
bool isLoading = false;
int _selectedIndex = 1;
set selectedIndex(int index) {
_selectedIndex = index;
notifyListeners();
}
get selectedIndex => _selectedIndex;
@override
void privilegeChanged() {
super.privilegeChanged();
// _loadInvoices();
}
Future<void> _loadInvoices() async {
if (user == null || !user.hasInvoices()) return;
String path = "/$invoices/";
initData(bool forCustomer) {
_selectedIndex = 1;
// _loadFcsInvoices(forCustomer);
if (_paid != null) _paid.close();
_paid = _getPaid(forCustomer);
}
Future<void> _loadFcsInvoices(bool forCustomer) async {
if (user == null) return;
if (!forCustomer && !user.hasInvoices()) return;
String path = "/$invoices_collection";
if (listener != null) listener.cancel();
invoices = [];
_invoices = [];
try {
listener = Firestore.instance
var q = Firestore.instance
.collection("$path")
.snapshots()
.listen((QuerySnapshot snapshot) {
invoices.clear();
invoices = snapshot.documents.map((documentSnapshot) {
.where("is_paid", isEqualTo: false)
.where("is_deleted", isEqualTo: false);
if (forCustomer) {
q = q.where("user_id", isEqualTo: user.id);
}
listener = q.snapshots().listen((QuerySnapshot snapshot) {
_invoices.clear();
_invoices = snapshot.documents.map((documentSnapshot) {
var s = Invoice.fromMap(
documentSnapshot.data, documentSnapshot.documentID);
return s;
@@ -181,75 +111,57 @@ class InvoiceModel extends BaseModel {
}
}
Future<void> initPaidInvoice(bool onlyFcs) {
if (onlyFcs) {
if (user == null ||
!((user.hasPackages() ||
user.hasReceiving() ||
user.hasProcessing()))) return null;
Paginator _getPaid(bool isCustomer) {
if (!isCustomer) {
if (user == null || !(user.hasInvoices())) throw "No privilege";
}
if (pagination != null) pagination.close();
paidInvoices = [];
endOfPaidInvoices = false;
isLoading = false;
var pageQuery = Firestore.instance
.collection("/$invoices");
// .collection(
// "/users/8OTfsbVvsUOn1SLxy1OrKk7Y_yNKkVoGalPcIlcHnAY/messages")
// .orderBy("date", descending: true);
// .where("is_delivered", isEqualTo: true)
// .where("is_deleted", isEqualTo: false);
if (!onlyFcs) {
.collection("/$packages_collection")
.where("is_delivered", isEqualTo: true)
.where("is_deleted", isEqualTo: false);
if (isCustomer) {
pageQuery = pageQuery.where("user_id", isEqualTo: user.id);
}
// pageQuery = pageQuery.orderBy("current_status_date", descending: true);
pagination = new Pagination(pageQuery, rowPerLoad: 20);
pagination.stream.listen((doc) {
if (doc == null) {
endOfPaidInvoices = true;
} else {
paidInvoices.add(Invoice.fromMap(doc.data, doc.documentID));
// var m = Message.fromMap(doc.data, doc.documentID);
// deliveredPackages.add(Package(
// id: m.id,
// status: package_delivered_status,
// currentStatus: package_delivered_status,
// currentStatusDate: m.date,
// trackingID: (count++).toString(),
// market: m.message));
}
pageQuery = pageQuery.orderBy("current_status_date", descending: true);
var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) {
return Invoice.fromMap(data, id);
});
return null;
return paginator;
}
Future<bool> loadMorePaidInvoices() {
if (pagination != null && !isLoading && !endOfPaidInvoices) {
isLoading = true;
Future<void> loadMore({bool isCustomer}) async {
if (_selectedIndex == 1) return; // when paid menu is not selected return
if (_paid.ended) return;
isLoading = true;
notifyListeners();
await _paid.load(onFinished: () {
isLoading = false;
notifyListeners();
pagination.load().then((value) {
isLoading = false;
notifyListeners();
});
}
return null;
});
}
Future<void> refresh({bool isCustomer}) async {
if (_selectedIndex == 1) return; // when paid menu is not selected return
await _paid.refresh(onFinished: () {
notifyListeners();
});
}
void initUser(user) {
super.initUser(user);
}
@override
logout() async {
if (_paid != null) _paid.close();
if (listener != null) await listener.cancel();
invoices = [];
_invoices = [];
}
Future<void> create(Invoice invoice) {
// return Services.instance.fcsShipmentService.createFcsShipment(fcsShipment);
Future<void> createInvoice(Invoice invoice) {
// return Services.instance.invoiceService.createInvoice(invoice);
}
Future<void> update(Invoice invoice) {
// return Services.instance.fcsShipmentService.updateFcsShipment(fcsShipment);
Future<void> updateInvoice(Invoice invoice) {
// return Services.instance.invoiceService.updateInvoice(invoice);
}
}

View File

@@ -1,21 +1,19 @@
import 'dart:io';
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/invoice/payment_page_edit.dart';
import 'package:fcs/pages/widgets/image_file_picker.dart';
import 'package:fcs/pages/widgets/input_text.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/number_cell.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:fcs/pages/widgets/show_img.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';
class PaymentPage extends StatefulWidget {
final Invoice invoice;
@@ -33,6 +31,7 @@ class _PaymentPageState extends State<PaymentPage> {
bool _isLoading = false;
bool isNew;
File _file;
@override
void initState() {
@@ -59,7 +58,25 @@ class _PaymentPageState extends State<PaymentPage> {
final receiptFileBox = Row(children: [
LocalText(context, 'pm.attachment', fontSize: 16, color: Colors.grey),
IconButton(
icon: Icon(Icons.attachment, color: primaryColor), onPressed: () {})
icon: Icon(Icons.attachment, color: primaryColor),
onPressed: () {
modelBottomSheet(context, onFile: (file) {
setState(() {
_file = file;
});
});
})
]);
final payBox = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Container(
height: 50,
width: 100,
alignment: Alignment.center,
child: Text(AppTranslations.of(context).text("pm.pay"),
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 14)),
color: primaryColor)
]);
return LocalProgress(
@@ -73,9 +90,6 @@ class _PaymentPageState extends State<PaymentPage> {
),
backgroundColor: primaryColor,
title: Text(AppTranslations.of(context).text("pm_.title")),
actions: [
IconButton(icon: Icon(Icons.cloud_upload), onPressed: () {})
],
),
body: ListView(
padding: const EdgeInsets.all(10.0),
@@ -84,6 +98,7 @@ class _PaymentPageState extends State<PaymentPage> {
SizedBox(height: 10),
receiptFileBox,
SizedBox(height: 10),
payBox,
Divider(),
SizedBox(height: 10),
LocalTitle(textKey: "pm.receipt"),
@@ -109,15 +124,31 @@ class _PaymentPageState extends State<PaymentPage> {
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(dateFormatter.format(r.date))),
Expanded(
flex: 2,
child: Center(child: Text('receipt' + k.toString() + '.png'))),
Expanded(flex: 1, child: Center(child: Text('pending'))),
Expanded(flex: 1, child: Center(child: Text('\$ ${r.amount}'))),
],
child: InkWell(
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => PaymentPageEdit(receipt: r)));
},
child: Row(
children: [
Expanded(flex: 2, child: Text('${r.date}')),
Expanded(
flex: 2,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowImage(
localImage: 'assets/logo.jpg',
url: null,
fileName: 'image')));
},
child: Icon(Icons.attachment, color: primaryColor))),
Expanded(flex: 1, child: Center(child: Text('pending'))),
Expanded(flex: 1, child: Center(child: Text('\$ ${r.amount}'))),
],
),
),
);
}).toList();
@@ -133,7 +164,7 @@ class _PaymentPageState extends State<PaymentPage> {
children: [
Expanded(
flex: 2,
child: Text('Product', style: TextStyle(color: Colors.grey))),
child: Text('Date', style: TextStyle(color: Colors.grey))),
Expanded(
flex: 2,
child: Text('File',

View File

@@ -0,0 +1,222 @@
import 'dart:io';
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/receipt.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/image_file_picker.dart';
import 'package:fcs/pages/widgets/input_text.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:fcs/pages/widgets/show_img.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class PaymentPageEdit extends StatefulWidget {
final Receipt receipt;
PaymentPageEdit({this.receipt});
@override
_PaymentPageEditState createState() => _PaymentPageEditState();
}
class _PaymentPageEditState extends State<PaymentPageEdit> {
TextEditingController _amountController = new TextEditingController();
var dateFormatter = new DateFormat('dd MMM yyyy');
Receipt _receipt = new Receipt();
bool _isLoading = false;
File _file;
bool isNew;
@override
void initState() {
if (widget.receipt != null) {
_receipt = widget.receipt;
}
super.initState();
}
@override
void dispose() {
super.dispose();
}
final DateFormat dateFormat = DateFormat("d MMM yyyy");
@override
Widget build(BuildContext context) {
var mainModel = Provider.of<MainModel>(context, listen: false);
bool customer = mainModel.isCustomer();
final amountBox = DisplayText(
labelTextKey: 'pm.amount',
iconData: FontAwesomeIcons.moneyBill,
text: _receipt.amount.toString());
final dateBox = DisplayText(
labelTextKey: 'pm.date',
iconData: Icons.date_range,
text: _receipt.date);
final statusBox = DisplayText(
labelTextKey: 'pm.status',
iconData: Icons.av_timer,
text: _receipt.status);
final receiptFileBox = Row(children: [
LocalText(context, 'pm.attachment', fontSize: 16, color: Colors.grey),
IconButton(
icon: Icon(Icons.attachment, color: primaryColor), onPressed: () {})
]);
final comfirmBox =
fcsButton(context, getLocalString(context, 'pm.btn_confirm'));
final cancelBox =
fcsButton(context, getLocalString(context, 'pm.btn_cancel'));
final fileBox = Container(
// padding: EdgeInsets.only(top: 20, left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocalText(
context,
"pm.attachment",
fontSize: 16,
color: labelColor,
),
Container(
padding: EdgeInsets.only(top: 15),
child: Stack(
children: <Widget>[
Container(
width: 200,
height: 200,
padding: const EdgeInsets.all(2.0),
decoration: BoxDecoration(
color: Colors.grey[300],
border: Border.all(
color: primaryColor,
width: 1.0,
),
),
child: _file == null
? checkImage(context)
: enableUpload(context),
),
customer
? Positioned(
bottom: -8,
right: -10,
child: IconButton(
color: primaryColor,
icon: CircleAvatar(
backgroundColor: primaryColor,
radius: 20,
child: Icon(
FontAwesomeIcons.camera,
size: 20,
color: Colors.white,
),
),
onPressed: () =>
modelBottomSheet(context, onFile: (file) {
setState(() {
_file = file;
});
}),
))
: Container()
],
),
),
],
),
);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(CupertinoIcons.back),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: primaryColor,
title: Text(AppTranslations.of(context).text("pm_.title")),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
dateBox,
SizedBox(height: 10),
amountBox,
SizedBox(height: 10),
statusBox,
SizedBox(height: 10),
fileBox,
SizedBox(height: 5),
Spacer(),
customer ? Container() : comfirmBox,
SizedBox(height: 5),
customer ? cancelBox : Container(),
SizedBox(height: 5),
],
),
),
),
);
}
Widget checkImage(BuildContext context) {
if (widget.receipt == null) {
return initialImage();
} else {
Widget _widget;
if (widget.receipt.fileUrl == null) {
_widget = initialImage();
} else {
_widget = InkWell(
child: Image.asset(widget.receipt.fileUrl, fit: BoxFit.cover),
onTap: () {},
);
}
return _widget;
}
}
Widget initialImage() {
return Center(
child: Icon(
Icons.insert_photo,
size: 45,
color: labelColor,
),
);
}
Widget enableUpload(BuildContext context) {
return InkWell(
child: Image.file(_file, fit: BoxFit.cover),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ShowImage(imageFile: _file, url: null, fileName: 'image')));
},
);
}
}

View File

@@ -1,11 +1,18 @@
import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:image_downloader/image_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:share/share.dart';
import 'package:http/http.dart' as http;
class PaymentPDFScreen extends StatefulWidget {
final String path;
@@ -41,14 +48,13 @@ class _PaymentPDFScreenState extends State<PaymentPDFScreen>
IconButton(
icon: Icon(Icons.file_download),
onPressed: () async {
print('image path => ${widget.path}');
await ImageDownloader.downloadImage(widget.path,
destination: AndroidDestinationType.directoryDownloads);
// var _dir = (await getApplicationDocumentsDirectory()).path;
// _downloadFile(widget.path, 'invoice.pdf', _dir);
},
),
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
onPressed: () => _share(widget.path),
),
],
),
@@ -72,18 +78,6 @@ class _PaymentPDFScreenState extends State<PaymentPDFScreen>
isReady = true;
});
},
// onError: (error) {
// setState(() {
// errorMessage = error.toString();
// });
// print(error.toString());
// },
// onPageError: (page, error) {
// setState(() {
// errorMessage = '$page: ${error.toString()}';
// });
// print('$page: ${error.toString()}');
// },
onViewCreated: (PDFViewController pdfViewController) {
_controller.complete(pdfViewController);
},
@@ -97,32 +91,24 @@ class _PaymentPDFScreenState extends State<PaymentPDFScreen>
});
},
),
// errorMessage.isEmpty
// ? !isReady
// ? Center(
// child: CircularProgressIndicator(),
// )
// : Container()
// : Center(
// child: Text(errorMessage),
// )
],
),
// floatingActionButton: FutureBuilder<PDFViewController>(
// future: _controller.future,
// builder: (context, AsyncSnapshot<PDFViewController> snapshot) {
// if (snapshot.hasData) {
// return FloatingActionButton.extended(
// label: Text("Go to ${pages ~/ 2}"),
// onPressed: () async {
// await snapshot.data.setPage(pages ~/ 2);
// },
// );
// }
// return Container();
// },
// ),
);
}
Future<File> _downloadFile(String url, String filename, String dir) async {
var req = await http.Client().get(Uri.parse(url));
var file = File('$dir/$filename');
return file.writeAsBytes(req.bodyBytes);
}
_share(String url) async {
MainModel mainModel = Provider.of<MainModel>(context, listen: false);
String appUrl = mainModel.setting.appUrl;
final RenderBox box = context.findRenderObject();
await Share.share(
"Join us on FCS Logistics App. Here is the link:\n $appUrl\n" + url,
subject: "Invitation to FCS Logistics App",
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
}
}