add structure
This commit is contained in:
904
lib/pages/do/do_approve.dart
Normal file
904
lib/pages/do/do_approve.dart
Normal file
@@ -0,0 +1,904 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:quiver/async.dart';
|
||||
import 'package:fcs/model/do_model.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/model/log_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/model/po_model.dart';
|
||||
import 'package:fcs/model/product_model.dart';
|
||||
import 'package:fcs/pages/do/photo_page.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/img_file.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import '../document_log_page.dart';
|
||||
import '../util.dart';
|
||||
import 'do_files.dart';
|
||||
import 'do_storage_item.dart';
|
||||
|
||||
class DOApproval extends StatefulWidget {
|
||||
final DOSubmission doSubmission;
|
||||
const DOApproval({this.doSubmission});
|
||||
@override
|
||||
_DOApprovalState createState() => _DOApprovalState();
|
||||
}
|
||||
|
||||
class _DOApprovalState extends State<DOApproval> {
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var doDateFormatter = new DateFormat('dd MMM yyyy - hh:mm a');
|
||||
|
||||
bool _isLoading = false;
|
||||
TextEditingController _date = new TextEditingController();
|
||||
TextEditingController _doDate = new TextEditingController();
|
||||
TextEditingController _number = new TextEditingController();
|
||||
TextEditingController _licence = new TextEditingController();
|
||||
TextEditingController _driver = new TextEditingController();
|
||||
TextEditingController _carNo = new TextEditingController();
|
||||
TextEditingController _type = new TextEditingController();
|
||||
TextEditingController _name = new TextEditingController();
|
||||
TextEditingController _bizName = new TextEditingController();
|
||||
TextEditingController _storage = new TextEditingController();
|
||||
TextEditingController _comment = new TextEditingController();
|
||||
DOSubmission doObj = DOSubmission();
|
||||
int _count;
|
||||
DateTime _result;
|
||||
DOFiles files = DOFiles();
|
||||
List<DOLine> doLines = new List();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
var mainModel = Provider.of<MainModel>(context, listen: false);
|
||||
var doModel = Provider.of<DOModel>(context, listen: false);
|
||||
|
||||
doObj = widget.doSubmission;
|
||||
_date.text = doObj.deliveryDate != null
|
||||
? dateFormatter.format(doObj.deliveryDate)
|
||||
: "";
|
||||
_doDate.text =
|
||||
doObj.doDate != null ? doDateFormatter.format(doObj.doDate) : "";
|
||||
_number.text = doObj.doNumber.toString();
|
||||
_licence.text = doObj.driverLicenseNumber;
|
||||
_driver.text = doObj.driverName;
|
||||
_carNo.text = doObj.carNo;
|
||||
_type.text = doObj.type;
|
||||
_name.text = doObj.userName;
|
||||
_bizName.text = doObj.bizName;
|
||||
_storage.text = doObj.storageCharge == null
|
||||
? ""
|
||||
: numberFormatter.format(doObj.storageCharge);
|
||||
_comment.text = doObj.comment;
|
||||
|
||||
if (doObj.deliveryStatus == 'initiated') {
|
||||
_count = doModel.timber;
|
||||
|
||||
Duration diff = DateTime.now().difference(doObj.deliveryInitiatedTime);
|
||||
|
||||
if (diff.inMinutes < mainModel.setting.deliveryStartWaitMin) {
|
||||
var time = mainModel.setting.deliveryStartWaitMin - diff.inMinutes;
|
||||
new CountdownTimer(
|
||||
new Duration(minutes: time), new Duration(seconds: 1))
|
||||
.listen((data) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_count = data.remaining.inSeconds;
|
||||
doModel.addTimber(_count);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
_load();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
MainModel mainModel = Provider.of<MainModel>(context);
|
||||
bool isBuyer = mainModel.user.isBuyer();
|
||||
var logModel = Provider.of<LogModel>(context);
|
||||
String formattedTime;
|
||||
if (doObj.deliveryStatus == 'initiated') {
|
||||
_result = DateTime(
|
||||
doObj.deliveryInitiatedTime.year,
|
||||
doObj.deliveryInitiatedTime.month,
|
||||
doObj.deliveryInitiatedTime.day,
|
||||
doObj.deliveryInitiatedTime.hour,
|
||||
doObj.deliveryInitiatedTime.minute,
|
||||
_count);
|
||||
formattedTime = DateFormat.ms().format(_result);
|
||||
}
|
||||
|
||||
final doDateBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 15),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.do_date"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_doDate.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final dateBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 8),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.date"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_date.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final numberBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.do_num"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_number.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final driverBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.driver"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_driver.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final carNoBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.car"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_carNo.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final licenceBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.licence"),
|
||||
ImageFile(
|
||||
enabled: false,
|
||||
title: "Image",
|
||||
initialImgUrl: doObj.driverLicenceUrl,
|
||||
onFile: (file) {}),
|
||||
],
|
||||
),
|
||||
);
|
||||
final statusBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.status"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doObj.status,
|
||||
style: doObj.isPending
|
||||
? textHighlightBlueStyle
|
||||
: doObj.isApproved
|
||||
? textHighlightGreenStyle
|
||||
: textHighlightRedStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final deliveryStatusBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.delivery.status"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 15),
|
||||
child: Text(
|
||||
doObj.getDeliveryStatus,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
doObj.deliveryStatus == 'initiated'
|
||||
? Text(
|
||||
"(can start in $formattedTime)",
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final typeBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.type"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Text(
|
||||
_type.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final userNameBox = Container(
|
||||
padding: EdgeInsets.only(top: 5, left: 20),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.name"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Text(
|
||||
_name.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final bizNameBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.biz"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Text(
|
||||
_bizName.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final driverImgUrlBox = Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "do.driver.image"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: ImageFile(
|
||||
enabled: !isBuyer && doObj.deliveryStatus == null,
|
||||
initialImgUrl: doObj.driverImgUrl,
|
||||
title: "Image",
|
||||
imageSource: ImageSource.camera,
|
||||
onFile: (file) {
|
||||
doObj.driverImg = file;
|
||||
}),
|
||||
),
|
||||
]));
|
||||
|
||||
final receiptImagebox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 0),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "do.receipt"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: ImageFile(
|
||||
enabled: false,
|
||||
initialImgUrl: doObj.doReceiptUrl,
|
||||
title: "Receipt",
|
||||
),
|
||||
),
|
||||
]));
|
||||
|
||||
final deliveryInitTimeBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.delivery.init.time"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doObj.deliveryInitTime,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final storageBox = Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.storage_charge"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_storage.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final storagePaymentBox = Container(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "do.storage_receipt"),
|
||||
ImageFile(
|
||||
enabled: mainModel.user.isBuyer() ? true : false,
|
||||
title: "Receipt File",
|
||||
initialImgUrl: this.doObj.storageReceiptUrl,
|
||||
onFile: (file) {
|
||||
this.files.setStorageChargeFile = file;
|
||||
}),
|
||||
]));
|
||||
|
||||
final commentBox = Container(
|
||||
padding: EdgeInsets.only(top: 5, left: 20),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.comment"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_comment.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(AppTranslations.of(context).text("do"),
|
||||
style: Provider.of<LanguageModel>(context).isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode')),
|
||||
actions: <Widget>[
|
||||
mainModel.showHistoryBtn()
|
||||
? IconButton(
|
||||
icon: Icon(Icons.history),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
DocumentLogPage(docID: doObj.id)),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
isBuyer
|
||||
? doObj.isPending
|
||||
? PopupMenuButton(
|
||||
onSelected: _selectBuyer,
|
||||
itemBuilder: (context) => List<PopupMenuEntry>.from([
|
||||
PopupMenuItem(
|
||||
enabled: this.doObj.isPending &&
|
||||
this.doObj.storageCharge > 0,
|
||||
value: 1,
|
||||
child: Text("Update DO"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
enabled: this.doObj.isPending,
|
||||
value: 2,
|
||||
child: Text("Cancel DO"),
|
||||
),
|
||||
]))
|
||||
: Container()
|
||||
: PopupMenuButton(
|
||||
onSelected: _select,
|
||||
itemBuilder: (context) => List<PopupMenuEntry>.from([
|
||||
PopupMenuItem(
|
||||
enabled: this.doObj.isPending,
|
||||
value: 1,
|
||||
child: Text("Approve DO"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
enabled: this.doObj.isPending,
|
||||
value: 2,
|
||||
child: Text("Reject DO"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
enabled:
|
||||
this.doObj.isApproved && mainModel.user.isOwner(),
|
||||
value: 6,
|
||||
child: Text("Cancel DO"),
|
||||
)
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 10),
|
||||
child: Card(
|
||||
elevation: 23,
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
doDateBox,
|
||||
Divider(),
|
||||
dateBox,
|
||||
Divider(),
|
||||
numberBox,
|
||||
Divider(),
|
||||
userNameBox,
|
||||
Divider(),
|
||||
bizNameBox,
|
||||
Divider(),
|
||||
typeBox,
|
||||
Divider(),
|
||||
statusBox,
|
||||
Divider(),
|
||||
doObj.comment == null || doObj.comment == ''
|
||||
? Container()
|
||||
: commentBox,
|
||||
doObj.comment == null || doObj.comment == ''
|
||||
? Container()
|
||||
: Divider(),
|
||||
driverBox,
|
||||
Divider(),
|
||||
carNoBox,
|
||||
Divider(),
|
||||
licenceBox,
|
||||
Divider(),
|
||||
receiptImagebox,
|
||||
Divider(),
|
||||
doObj.hasStorageCharge() ? storageBox : Container(),
|
||||
doObj.hasStorageCharge() ? Divider() : Container(),
|
||||
doObj.hasStorageCharge()
|
||||
? storagePaymentBox
|
||||
: Container(),
|
||||
doObj.isApproved || doObj.isClosed
|
||||
? deliveryStatusBox
|
||||
: Container(),
|
||||
doObj.isApproved || doObj.isClosed
|
||||
? Divider()
|
||||
: Container(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: LocalText(
|
||||
context,
|
||||
'do.products',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
underline: true,
|
||||
color: secondaryColor,
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 40,
|
||||
columns: [
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.product"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.storage"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.quantity"),numeric: true
|
||||
),
|
||||
],
|
||||
rows: getProductRow(doObj.doLines),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
getPOProductTable()
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<DOLine> doLines) {
|
||||
MainModel mainModel = Provider.of<MainModel>(context);
|
||||
ProductModel productModel = Provider.of<ProductModel>(context);
|
||||
bool isBuyer = mainModel.user.isBuyer();
|
||||
|
||||
if (doLines.isNotEmpty) {
|
||||
doLines.forEach((d) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == d.productID) {
|
||||
d.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
doLines.sort((p1, p2) => p1.displayOrder.compareTo(p2.displayOrder));
|
||||
}
|
||||
return doLines.map((d) {
|
||||
return MyDataRow(
|
||||
onSelectChanged: (bool selected) async {
|
||||
if (isBuyer) return;
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DOStorageItem(
|
||||
doLine: d,
|
||||
onSave: (storageID, storageName) {
|
||||
setState(() {
|
||||
d.storageID = storageID;
|
||||
d.storageName = storageName;
|
||||
});
|
||||
},
|
||||
)),
|
||||
);
|
||||
},
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(d.storageName, style: textStyle),
|
||||
),
|
||||
MyDataCell(NumberCell(d.qty)),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Widget getPOProductTable() {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: LocalText(context, 'po.info',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
underline: true,
|
||||
color: secondaryColor),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "po.number")),
|
||||
MyDataColumn(label: LocalText(context, "po.product")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.po_qty"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.po_balance_qty"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.retrieved.amount"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.do_qty"),numeric: true,
|
||||
),
|
||||
],
|
||||
rows: getPOProductRow(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getPOProductRow() {
|
||||
ProductModel productModel = Provider.of<ProductModel>(context);
|
||||
if (doObj.dopoLies.isNotEmpty) {
|
||||
doObj.dopoLies.sort((p1, p2) => p1.poNumber.compareTo(p2.poNumber));
|
||||
|
||||
doObj.dopoLies.forEach((d) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == d.productID) {
|
||||
d.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
doObj.dopoLies.sort((p1, p2) {
|
||||
if (p1.displayOrder != p2.displayOrder)
|
||||
return p1.displayOrder.compareTo(p2.displayOrder);
|
||||
return p1.poNumber.compareTo(p2.poNumber);
|
||||
});
|
||||
}
|
||||
return doObj.dopoLies.map((d) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.poNumber,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(NumberCell(d.poQty)),
|
||||
MyDataCell(NumberCell(d.poBalAtCreate)),
|
||||
MyDataCell(NumberCell(d.getPoBalanceQtyAtCreate)),
|
||||
MyDataCell(NumberCell(d.doQty)),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_select(s) {
|
||||
if (s == 1) {
|
||||
showConfirmDialog(context, "do.approve.confirm", () {
|
||||
_approve();
|
||||
});
|
||||
} else if (s == 2) {
|
||||
showCommentDialog(context, (comment) {
|
||||
doObj.comment = comment;
|
||||
_reject();
|
||||
});
|
||||
} else if (s == 5) {
|
||||
showConfirmDialog(context, "do.end.confirm", () {
|
||||
_endDelivery();
|
||||
});
|
||||
} else if (s == 6) {
|
||||
showConfirmDialog(context, "do.cancel.confirm", () {
|
||||
_cancelDelivery();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_selectBuyer(s) {
|
||||
if (s == 1) {
|
||||
showConfirmDialog(context, "do.confirm", () {
|
||||
_submit();
|
||||
});
|
||||
} else if (s == 2) {
|
||||
showConfirmDialog(context, "do.cancel.confirm", () {
|
||||
_cancelDelivery();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
POSubmissionModel poModel =
|
||||
Provider.of<POSubmissionModel>(context, listen: false);
|
||||
DOModel doModel = Provider.of<DOModel>(context, listen: false);
|
||||
|
||||
var _doSub = await poModel.loadDOLines(doObj);
|
||||
_doSub = await doModel.loadDOPOLines(_doSub);
|
||||
// set po balance
|
||||
List<String> pos = _doSub.getPOs();
|
||||
for (var po in pos) {
|
||||
List<POLine> poLines = await poModel.loadPOLines(po);
|
||||
_doSub.setDOPOLineBalance(po, poLines);
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
doObj.doLines = _doSub.doLines;
|
||||
doObj.dopoLies = _doSub.dopoLies;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_approve() async {
|
||||
if (doObj.doLines.any((l) => l.storageID.isEmpty)) {
|
||||
showMsgDialog(context, "Error", "Storage required for every product");
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.approveDO(doObj);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_reject() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.rejectDO(doObj);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_initDelivery() async {
|
||||
if (doObj.driverImg == null) {
|
||||
showMsgDialog(context, "Error", "Please attach driver image");
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.initDelivery(doObj);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_startDelivery() async {
|
||||
MainModel mainModel = Provider.of<MainModel>(context);
|
||||
Duration diff = DateTime.now().difference(doObj.deliveryInitiatedTime);
|
||||
if (diff.inMinutes < mainModel.setting.deliveryStartWaitMin) {
|
||||
showMsgDialog(context, "Waiting...",
|
||||
"Can not start delivery, wait for ${mainModel.setting.deliveryStartWaitMin} minutes");
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.startDelivery(doObj);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_endDelivery() async {
|
||||
var photo = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => PhotoPage()),
|
||||
);
|
||||
if (photo == null) {
|
||||
return;
|
||||
}
|
||||
Uint8List bytesPhoto = photo.readAsBytesSync() as Uint8List;
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.endDelivery(doObj, bytesPhoto);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_cancelDelivery() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.cancelDO(doObj);
|
||||
Navigator.pop(context);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_submit() async {
|
||||
if (doObj.hasStorageCharge()) {
|
||||
if (files.storageChargeFile == null && doObj.storageReceiptUrl == '') {
|
||||
showMsgDialog(context, "Error", "Please insert storage receipt");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
await doModel.updateDO(doObj, files);
|
||||
Navigator.pop<bool>(context, true);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
650
lib/pages/do/do_creation_form.dart
Normal file
650
lib/pages/do/do_creation_form.dart
Normal file
@@ -0,0 +1,650 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/do_model.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/model/po_model.dart';
|
||||
import 'package:fcs/model/product_model.dart';
|
||||
import 'package:fcs/pages/do/do_product_item.dart';
|
||||
import 'package:fcs/pages/util.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/img_file.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import 'do_files.dart';
|
||||
import 'po_selection.dart';
|
||||
|
||||
class DOForm extends StatefulWidget {
|
||||
final DOSubmission doSubmission;
|
||||
const DOForm({this.doSubmission});
|
||||
@override
|
||||
_DOFormState createState() => _DOFormState();
|
||||
}
|
||||
|
||||
class _DOFormState extends State<DOForm> {
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
|
||||
TextEditingController _deliveryDate = new TextEditingController();
|
||||
TextEditingController _licence = new TextEditingController();
|
||||
TextEditingController _driver = new TextEditingController();
|
||||
TextEditingController _carNo = new TextEditingController();
|
||||
TextEditingController _doStatus = new TextEditingController();
|
||||
TextEditingController _storage = new TextEditingController();
|
||||
TextEditingController _doNumber = new TextEditingController();
|
||||
DOSubmission doSubmission = DOSubmission();
|
||||
|
||||
bool _isLoading = false;
|
||||
bool _isNew = true;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
int doTypeValue = 0;
|
||||
DOLine doLine = new DOLine();
|
||||
DOFiles files = DOFiles();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if (widget.doSubmission != null) {
|
||||
this.doSubmission = widget.doSubmission;
|
||||
this._isNew = false;
|
||||
_deliveryDate.text =
|
||||
dateFormatter.format(widget.doSubmission.deliveryDate);
|
||||
_licence.text = widget.doSubmission.driverLicenseNumber;
|
||||
_driver.text = widget.doSubmission.driverName;
|
||||
_carNo.text = widget.doSubmission.carNo;
|
||||
_doStatus.text = widget.doSubmission.status;
|
||||
_storage.text = widget.doSubmission.storageCharge == null
|
||||
? ""
|
||||
: numberFormatter.format(widget.doSubmission.storageCharge);
|
||||
_doNumber.text = widget.doSubmission.doNumber;
|
||||
|
||||
if (widget.doSubmission.type == 'multiple') {
|
||||
doTypeValue = 1;
|
||||
} else {
|
||||
doTypeValue = 0;
|
||||
}
|
||||
this.doLine.action = 'update';
|
||||
} else {
|
||||
this.doLine.action = 'create';
|
||||
doSubmission.type = 'single';
|
||||
_storage.text = "0";
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var languageModel = Provider.of<LanguageModel>(context);
|
||||
var mainModel = Provider.of<MainModel>(context);
|
||||
var poModel = Provider.of<POSubmissionModel>(context);
|
||||
|
||||
bool isBuyer = mainModel.user.isBuyer();
|
||||
|
||||
final doNumberBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.do_num"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_doNumber.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final _doTypeValueBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.type"),
|
||||
Container(
|
||||
width: 130,
|
||||
child: RadioListTile(
|
||||
dense: true,
|
||||
title: LocalText(context, "do.single"),
|
||||
value: 0,
|
||||
groupValue: doTypeValue,
|
||||
onChanged: handleRadioValueChanged,
|
||||
activeColor: primaryColor,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 136,
|
||||
child: RadioListTile(
|
||||
dense: true,
|
||||
title: LocalText(context, 'do.multiple'),
|
||||
value: 1,
|
||||
groupValue: doTypeValue,
|
||||
onChanged: handleRadioValueChanged,
|
||||
activeColor: primaryColor,
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final deliveryDateBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 15),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
DatePicker.showDatePicker(context,
|
||||
showTitleActions: true,
|
||||
currentTime: _deliveryDate.text == ""
|
||||
? null
|
||||
: dateFormatter.parse(_deliveryDate.text),
|
||||
minTime: DateTime.now(),
|
||||
maxTime: DateTime(2030, 12, 31), onConfirm: (date) {
|
||||
setState(() {
|
||||
_deliveryDate.text = dateFormatter.format(date);
|
||||
doSubmission.deliveryDate =
|
||||
dateFormatter.parse(_deliveryDate.text);
|
||||
doSubmission.updateStorageCharge(mainModel.setting);
|
||||
});
|
||||
}, locale: LocaleType.en);
|
||||
},
|
||||
child: TextFormField(
|
||||
controller: _deliveryDate,
|
||||
autofocus: false,
|
||||
cursorColor: primaryColor,
|
||||
style: textStyle,
|
||||
enabled: false,
|
||||
keyboardType: TextInputType.datetime,
|
||||
decoration: new InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
labelText: AppTranslations.of(context).text("do.date"),
|
||||
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
|
||||
icon: Icon(
|
||||
Icons.date_range,
|
||||
color: primaryColor,
|
||||
)),
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return AppTranslations.of(context).text("do.form.date");
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
));
|
||||
|
||||
final driverBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 15),
|
||||
child: TextFormField(
|
||||
controller: _driver,
|
||||
autofocus: false,
|
||||
style: textStyle,
|
||||
cursorColor: primaryColor,
|
||||
decoration: new InputDecoration(
|
||||
labelText: AppTranslations.of(context).text("do.driver"),
|
||||
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1.0)),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1.0)),
|
||||
icon: Icon(
|
||||
Icons.account_box,
|
||||
color: primaryColor,
|
||||
)),
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return AppTranslations.of(context).text("do.form.driver");
|
||||
}
|
||||
return null;
|
||||
},
|
||||
));
|
||||
|
||||
final carNoBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 15),
|
||||
child: TextFormField(
|
||||
controller: _carNo,
|
||||
autofocus: false,
|
||||
style: textStyle,
|
||||
cursorColor: primaryColor,
|
||||
decoration: new InputDecoration(
|
||||
labelText: AppTranslations.of(context).text("do.car"),
|
||||
labelStyle: languageModel.isEng ? labelStyle : labelStyleMM,
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1.0)),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1.0)),
|
||||
icon: Icon(
|
||||
Icons.directions_car,
|
||||
color: primaryColor,
|
||||
)),
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return AppTranslations.of(context).text("do.form.car");
|
||||
}
|
||||
return null;
|
||||
},
|
||||
));
|
||||
|
||||
final doStatusBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, right: 15),
|
||||
child: TextFormField(
|
||||
controller: _doStatus,
|
||||
autofocus: false,
|
||||
style: textStyle,
|
||||
readOnly: true,
|
||||
decoration: new InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
icon: Image.asset("assets/status.png",
|
||||
width: 25, color: primaryColor)),
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return "Please enter DO Status";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
));
|
||||
|
||||
final storageBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.storage_charge"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doSubmission.storageCharge == null
|
||||
? ""
|
||||
: numberFormatter.format(doSubmission.storageCharge),
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
final storagePaymentBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "do.storage_receipt"),
|
||||
ImageFile(
|
||||
enabled: isBuyer,
|
||||
title: "Receipt File",
|
||||
initialImgUrl: this.doSubmission.storageReceiptUrl,
|
||||
onFile: (file) {
|
||||
this.files.setStorageChargeFile = file;
|
||||
}),
|
||||
]));
|
||||
final licesebox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "do.licence"),
|
||||
ImageFile(
|
||||
enabled: isBuyer,
|
||||
title: "Image",
|
||||
initialImgUrl: this.doSubmission.driverLicenceUrl,
|
||||
onFile: (file) {
|
||||
this.files.setlicenseFile = file;
|
||||
}),
|
||||
]));
|
||||
|
||||
final poButtun = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(children: <Widget>[
|
||||
LocalText(context, "po.title"),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
POSelection.showPOSelection(
|
||||
context, poModel.approvedPOs, doSubmission.pos,
|
||||
ok: (List<POSubmission> pos) async {
|
||||
for (var po in pos) {
|
||||
po.poLines = await poModel.loadPOLines(po.id);
|
||||
}
|
||||
setState(() {
|
||||
doSubmission.pos = pos;
|
||||
doSubmission.loadPOs();
|
||||
doSubmission.updateStorageCharge(mainModel.setting);
|
||||
});
|
||||
});
|
||||
},
|
||||
icon: Icon(Icons.edit)),
|
||||
]));
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(AppTranslations.of(context).text("do"),
|
||||
style: Provider.of<LanguageModel>(context).isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode')),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: () {
|
||||
if (!_formKey.currentState.validate()) return;
|
||||
showConfirmDialog(context, "do.confirm", () {
|
||||
_submit(mainModel);
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
this.doSubmission.doNumber != null
|
||||
? doNumberBox
|
||||
: Container(),
|
||||
this.doSubmission.hasStorageCharge()
|
||||
? storageBox
|
||||
: Container(),
|
||||
this.doSubmission.hasStorageCharge()
|
||||
? storagePaymentBox
|
||||
: Container(),
|
||||
_doTypeValueBox,
|
||||
deliveryDateBox,
|
||||
driverBox,
|
||||
licesebox,
|
||||
carNoBox,
|
||||
poButtun,
|
||||
widget.doSubmission == null ? Container() : doStatusBox,
|
||||
getProductTable(),
|
||||
getPOProductTable(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
void handleRadioValueChanged(int value) {
|
||||
var mainModel = Provider.of<MainModel>(context, listen: false);
|
||||
setState(() {
|
||||
doSubmission.type = value == 0 ? 'single' : 'multiple';
|
||||
doTypeValue = value;
|
||||
doSubmission.loadPOs();
|
||||
doSubmission.updateStorageCharge(mainModel.setting);
|
||||
switch (doTypeValue) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget getProductTable() {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: LocalText(
|
||||
context,
|
||||
'do.products',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
underline: true,
|
||||
color: secondaryColor,
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "do.product")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.avail.qty"),
|
||||
numeric: true
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.do_qty"),
|
||||
numeric: true,
|
||||
),
|
||||
],
|
||||
rows: getProductRow(doSubmission.doLines),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<DOLine> doLines) {
|
||||
ProductModel productModel = Provider.of<ProductModel>(context);
|
||||
if (doLines.isNotEmpty) {
|
||||
doLines.forEach((d) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == d.productID) {
|
||||
d.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
doLines.sort((p1, p2) => p1.displayOrder.compareTo(p2.displayOrder));
|
||||
}
|
||||
return doLines.map((d) {
|
||||
return MyDataRow(
|
||||
onSelectChanged: (bool selected) async {
|
||||
if (doTypeValue == 0) return;
|
||||
var doLine = await showDialog(
|
||||
context: context,
|
||||
builder: (_) => DOProductItem(
|
||||
doLine: DOLine(productID: d.productID, qty: d.qty),
|
||||
));
|
||||
_updateQty(doLine);
|
||||
},
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(d.poBalQty)
|
||||
),
|
||||
MyDataCell(
|
||||
Container(
|
||||
color: Colors.cyan,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
new Text(d.qty == null ? "0" : d.qty.toString(),
|
||||
style: textStyle),
|
||||
],
|
||||
)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Widget getPOProductTable() {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: LocalText(context, 'po.info',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
underline: true,
|
||||
color: secondaryColor),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "po.number")),
|
||||
MyDataColumn(label: LocalText(context, "po.product")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.po_qty"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.avail.qty"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.retrieved.amount"),numeric: true,
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.do_qty"),numeric: true,
|
||||
),
|
||||
],
|
||||
rows: getPOProductRow(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getPOProductRow() {
|
||||
ProductModel productModel = Provider.of<ProductModel>(context);
|
||||
if (doSubmission.dopoLies.isNotEmpty) {
|
||||
doSubmission.dopoLies
|
||||
.sort((p1, p2) => p1.poNumber.compareTo(p2.poNumber));
|
||||
doSubmission.dopoLies.forEach((d) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == d.productID) {
|
||||
d.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
doSubmission.dopoLies.sort((p1, p2) {
|
||||
if (p1.displayOrder!=p2.displayOrder)
|
||||
return p1.displayOrder.compareTo(p2.displayOrder);
|
||||
return p1.poNumber.compareTo(p2.poNumber);
|
||||
});
|
||||
}
|
||||
return doSubmission.dopoLies.map((d) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.poNumber,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
d.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(d.poQty)
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(d.poBalQty)
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(d.getPoBalanceQty)
|
||||
),
|
||||
MyDataCell(
|
||||
Container(
|
||||
color: Colors.grey,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
new Text(d.doQty == null ? "0" : d.doQty.toString(),
|
||||
style: textStyle),
|
||||
],
|
||||
)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_updateQty(DOLine doLine) {
|
||||
if (doLine == null) return;
|
||||
|
||||
try {
|
||||
var mainModel = Provider.of<MainModel>(context);
|
||||
setState(() {
|
||||
doSubmission.updateDoline(doLine.productID, doLine.qty);
|
||||
doSubmission.updateStorageCharge(mainModel.setting);
|
||||
});
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
_submit(MainModel mainModel) async {
|
||||
if (doSubmission.doLines.length == 0) {
|
||||
showMsgDialog(context, "Error", "No product line");
|
||||
return;
|
||||
}
|
||||
if (files.licenseFile == null) {
|
||||
showMsgDialog(context, "Error", "Please insert driver licence");
|
||||
return;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
doSubmission.doLines.forEach((doLine) {
|
||||
total += doLine.qty;
|
||||
});
|
||||
|
||||
if (total <= 0) {
|
||||
showMsgDialog(context, "Error", "must be greater than zero");
|
||||
return;
|
||||
}
|
||||
|
||||
doSubmission.carNo = _carNo.text;
|
||||
doSubmission.driverName = _driver.text;
|
||||
doSubmission.driverLicenseNumber = _licence.text;
|
||||
doSubmission.deliveryDate = dateFormatter.parse(_deliveryDate.text);
|
||||
doSubmission.type = doTypeValue == 0 ? 'single' : 'multiple';
|
||||
doSubmission.doLines.removeWhere((d) => d.qty == 0);
|
||||
doSubmission.dopoLies.removeWhere((d) => d.doQty == 0);
|
||||
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
DOModel doModel = Provider.of<DOModel>(context);
|
||||
|
||||
if (_isNew) {
|
||||
await doModel.createDO(doSubmission, files);
|
||||
} else {
|
||||
await doModel.updateDO(doSubmission, files);
|
||||
}
|
||||
Navigator.pop<bool>(context, true);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
423
lib/pages/do/do_creation_todelete.dart
Normal file
423
lib/pages/do/do_creation_todelete.dart
Normal file
@@ -0,0 +1,423 @@
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/model/po_model.dart';
|
||||
import 'package:fcs/pages/util.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/img_file.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:progress/progress.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import 'do_creation_form.dart';
|
||||
|
||||
class DoCreation extends StatefulWidget {
|
||||
final POSubmission poSubmission;
|
||||
const DoCreation({this.poSubmission});
|
||||
@override
|
||||
_DoCreationState createState() => _DoCreationState();
|
||||
}
|
||||
|
||||
class _DoCreationState extends State<DoCreation> {
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
TextEditingController _podate = new TextEditingController();
|
||||
TextEditingController _ponumber = new TextEditingController();
|
||||
TextEditingController _postatus = new TextEditingController();
|
||||
POSubmission poSubmission = POSubmission();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
this.poSubmission = widget.poSubmission;
|
||||
_podate.text = dateFormatter.format(this.poSubmission.poDate);
|
||||
_ponumber.text = this.poSubmission.poNumber.toString();
|
||||
_postatus.text = this.poSubmission.status;
|
||||
_isLoading = true;
|
||||
_load();
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
List<POLine> poLines =
|
||||
await Provider.of<POSubmissionModel>(context, listen: false)
|
||||
.loadPOLines(poSubmission.id);
|
||||
var _poDos = await Provider.of<POSubmissionModel>(context, listen: false)
|
||||
.loadDOs(poSubmission);
|
||||
setState(() {
|
||||
this.poSubmission.poLines = poLines;
|
||||
this.poSubmission.dos = _poDos.dos;
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Widget doDateBox(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.date"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
dateFormatter.format(doSubmission.deliveryDate),
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget doNumberBox(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.do_num"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doSubmission.doNumber,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget driverBox(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.driver"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doSubmission.driverName,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget carNoBox(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.car"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doSubmission.carNo,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget doStatusBox(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.status"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
doSubmission.status,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget driverLicence(BuildContext context, DOSubmission doSubmission) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.licence"),
|
||||
ImageFile(
|
||||
enabled: false,
|
||||
title: "Receipt File",
|
||||
initialImgUrl: doSubmission.driverLicenceUrl,
|
||||
onFile: (file) {}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var languageModle = Provider.of<LanguageModel>(context);
|
||||
|
||||
final poDateBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 15),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "po.date"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_podate.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final poNumberBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.po_num"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_ponumber.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final poStatusBox = Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 5),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "po.status"),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
_postatus.text,
|
||||
style: textStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(AppTranslations.of(context).text("do.title"),
|
||||
style: languageModle.isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode')),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
backgroundColor: primaryColor,
|
||||
heroTag: "btn2",
|
||||
onPressed: () async {
|
||||
if (poSubmission.poLines
|
||||
.fold<int>(0, (p, e) => p + e.balanceQty) ==
|
||||
0) {
|
||||
showMsgDialog(context, "Error", "Zero PO balance qty");
|
||||
return;
|
||||
}
|
||||
|
||||
final bool successful = await Navigator.push<bool>(
|
||||
context, MaterialPageRoute(builder: (context) => DOForm()));
|
||||
if (successful != null && successful) _load();
|
||||
},
|
||||
child: Icon(Icons.add),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 10),
|
||||
child: Card(
|
||||
elevation: 23,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
poDateBox,
|
||||
poNumberBox,
|
||||
poStatusBox,
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 15,
|
||||
columns: [
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.product"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.po_qty"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label:
|
||||
LocalText(context, "do.po_balance_qty"),
|
||||
),
|
||||
],
|
||||
rows:
|
||||
getPoProductRow(widget.poSubmission.poLines),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: getDos(poSubmission.dos),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
List<MyDataRow> getPoProductRow(List<POLine> poLines) {
|
||||
return poLines.map((p) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
p.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(p.qty.toString(), style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(p.balanceQty.toString(), style: textStyle),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<Widget> getDos(List<DOSubmission> dos) {
|
||||
return dos.map((d) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 10, right: 10),
|
||||
child: Card(
|
||||
child: Theme(
|
||||
data: ThemeData(accentColor: Colors.grey),
|
||||
child: ExpansionTile(
|
||||
onExpansionChanged: (e) => _onExpend(context, e, d),
|
||||
title: ListTile(
|
||||
title: Text(dateFormatter.format(d.deliveryDate)),
|
||||
subtitle: Text(d.doNumber),
|
||||
),
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 20),
|
||||
child: InkWell(
|
||||
child: Icon(Icons.edit),
|
||||
onTap: () async {
|
||||
final bool successful =
|
||||
await Navigator.push<bool>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DOForm(
|
||||
doSubmission: d,
|
||||
)));
|
||||
if (successful != null && successful) _load();
|
||||
},
|
||||
)),
|
||||
),
|
||||
doDateBox(context, d),
|
||||
doNumberBox(context, d),
|
||||
doStatusBox(context, d),
|
||||
driverBox(context, d),
|
||||
carNoBox(context, d),
|
||||
driverLicence(context, d),
|
||||
Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 15,
|
||||
columns: [
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.product"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.do_qty"),
|
||||
),
|
||||
],
|
||||
rows: getdoProductRow(d.doLines),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<MyDataRow> getdoProductRow(List<DOLine> doLines) {
|
||||
return doLines.map((p) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(
|
||||
p.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(p.qty.toString(), style: textStyle),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_onExpend(BuildContext context, expended, DOSubmission doSub) async {
|
||||
if (!expended) return;
|
||||
POSubmissionModel poModel = Provider.of<POSubmissionModel>(context);
|
||||
var _doSub = await poModel.loadDOLines(doSub);
|
||||
setState(() {
|
||||
doSub = _doSub;
|
||||
});
|
||||
}
|
||||
}
|
||||
26
lib/pages/do/do_files.dart
Normal file
26
lib/pages/do/do_files.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'dart:io';
|
||||
|
||||
class DOFiles {
|
||||
File doPaymentFile, storageChargeFile, licenseFile;
|
||||
bool doFileChanged = false,
|
||||
storageFileChanged = false,
|
||||
licenseFileChanged = false;
|
||||
|
||||
set setDoPaymentFile(File file) {
|
||||
doPaymentFile = file;
|
||||
doFileChanged = true;
|
||||
}
|
||||
|
||||
set setStorageChargeFile(File file) {
|
||||
storageChargeFile = file;
|
||||
storageFileChanged = true;
|
||||
}
|
||||
|
||||
set setlicenseFile(File file) {
|
||||
licenseFile = file;
|
||||
licenseFileChanged = true;
|
||||
}
|
||||
|
||||
bool get anyChanged =>
|
||||
doFileChanged || storageFileChanged || licenseFileChanged;
|
||||
}
|
||||
286
lib/pages/do/do_list.dart
Normal file
286
lib/pages/do/do_list.dart
Normal file
@@ -0,0 +1,286 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/do_model.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/pages/do/do_creation_form.dart';
|
||||
import 'package:fcs/pages/util.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/popup_menu.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
import 'package:fcs/widget/popupmenu.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import 'do_approve.dart';
|
||||
|
||||
class DOList extends StatefulWidget {
|
||||
@override
|
||||
_DOListState createState() => _DOListState();
|
||||
}
|
||||
|
||||
class _DOListState extends State<DOList> {
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
final double dotSize = 10.0;
|
||||
DateTime _selectedDate = DateTime.now();
|
||||
String status;
|
||||
int _selectedIndex = 0;
|
||||
int _dateIndex = 0;
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
var doModel = Provider.of<DOModel>(context, listen: false);
|
||||
_selectedIndex = doModel.popupMenu.index;
|
||||
_dateIndex = doModel.dateIndex;
|
||||
_selectedDate = doModel.selectedDate;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<Null> _selectDate(BuildContext context) async {
|
||||
var doModel = Provider.of<DOModel>(context);
|
||||
|
||||
final DateTime picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: _selectedDate,
|
||||
firstDate: DateTime(2015, 8),
|
||||
lastDate: DateTime(2101),
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
primaryColor: primaryColor, //Head background
|
||||
accentColor: secondaryColor, //selection color
|
||||
dialogBackgroundColor: Colors.white, //Background color
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (picked != null) {
|
||||
var pickedDate = new DateTime(picked.year, picked.month, picked.day);
|
||||
var currentDate = new DateTime(
|
||||
DateTime.now().year, DateTime.now().month, DateTime.now().day);
|
||||
this._dateIndex = pickedDate == currentDate ? 0 : 1;
|
||||
setState(() {
|
||||
_selectedDate = picked;
|
||||
doModel.filterData(status, _selectedDate, _selectedIndex, _dateIndex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var doModel = Provider.of<DOModel>(context);
|
||||
MainModel mainModel = Provider.of<MainModel>(context);
|
||||
bool isBuyer = mainModel.user.isBuyer();
|
||||
var languageModle = Provider.of<LanguageModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(
|
||||
AppTranslations.of(context).text("do.title"),
|
||||
style: languageModle.isEng
|
||||
? TextStyle()
|
||||
: TextStyle(fontFamily: 'MyanmarUnicode'),
|
||||
),
|
||||
actions: <Widget>[
|
||||
InkWell(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Image.asset(
|
||||
"assets/date_filter.png",
|
||||
color: Colors.white,
|
||||
width: 25,
|
||||
),
|
||||
_dateIndex == 0
|
||||
? Container()
|
||||
: Positioned(
|
||||
bottom: 15,
|
||||
right: 10,
|
||||
child: Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
decoration: new BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: secondaryColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => _selectDate(context),
|
||||
),
|
||||
PopupMenuButton<PopupMenu>(
|
||||
elevation: 3.2,
|
||||
onSelected: (selected) {
|
||||
setState(() {
|
||||
_selectedIndex = selected.index;
|
||||
});
|
||||
if (selected.status == 'All') {
|
||||
status = null;
|
||||
} else {
|
||||
status = selected.status;
|
||||
}
|
||||
doModel.filterData(
|
||||
status, _selectedDate, _selectedIndex, _dateIndex);
|
||||
},
|
||||
icon: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: new BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.filter_list,
|
||||
color: primaryColor,
|
||||
),
|
||||
_selectedIndex != 0
|
||||
? Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
decoration: new BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: secondaryColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
)),
|
||||
itemBuilder: (BuildContext context) {
|
||||
return statusMenu.map((PopupMenu choice) {
|
||||
return PopupMenuItem<PopupMenu>(
|
||||
value: choice,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(choice.status),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
_selectedIndex != null &&
|
||||
_selectedIndex == choice.index
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: Colors.grey,
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}),
|
||||
],
|
||||
),
|
||||
floatingActionButton: mainModel.isBuyer()
|
||||
? FloatingActionButton(
|
||||
backgroundColor: primaryColor,
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => DOForm()),
|
||||
),
|
||||
child: Icon(Icons.add),
|
||||
)
|
||||
: null,
|
||||
body: new ListView.builder(
|
||||
scrollDirection: Axis.vertical,
|
||||
padding: EdgeInsets.only(left: 15, right: 15, top: 15),
|
||||
shrinkWrap: true,
|
||||
itemCount: doModel.dos.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Card(
|
||||
elevation: 10,
|
||||
color: Colors.white,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DOApproval(
|
||||
doSubmission: doModel.dos[index])),
|
||||
);
|
||||
},
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Padding(
|
||||
padding: new EdgeInsets.symmetric(
|
||||
horizontal: 32.0 - dotSize / 2),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Image.asset(
|
||||
"assets/do.png",
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
new Expanded(
|
||||
child: new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new Text(
|
||||
doModel.dos[index].doNumber,
|
||||
style: new TextStyle(
|
||||
fontSize: 12.0, color: Colors.black),
|
||||
),
|
||||
new Text(
|
||||
doModel.dos[index].deliveryDate == null
|
||||
? ""
|
||||
: dateFormatter.format(
|
||||
doModel.dos[index].deliveryDate),
|
||||
style: new TextStyle(
|
||||
fontSize: 14.0, color: Colors.grey),
|
||||
),
|
||||
!isBuyer
|
||||
? new Text(
|
||||
doModel.dos[index].userName,
|
||||
style: new TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: Colors.grey),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 15),
|
||||
child: getStatus(doModel.dos[index].status),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
134
lib/pages/do/do_product_item.dart
Normal file
134
lib/pages/do/do_product_item.dart
Normal file
@@ -0,0 +1,134 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/pages/util.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DOProductItem extends StatefulWidget {
|
||||
final DOLine doLine;
|
||||
const DOProductItem({Key key, this.doLine}) : super(key: key);
|
||||
@override
|
||||
_DOProductItemState createState() => _DOProductItemState();
|
||||
}
|
||||
|
||||
class _DOProductItemState extends State<DOProductItem> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
TextEditingController _doQty = new TextEditingController();
|
||||
DOLine doLine;
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.doLine != null) {
|
||||
doLine = widget.doLine;
|
||||
_doQty.text = widget.doLine.qty.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var languageModel = Provider.of<LanguageModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: AlertDialog(
|
||||
title: Center(
|
||||
child: Text(
|
||||
AppTranslations.of(context).text("do_qty"),
|
||||
style: TextStyle(
|
||||
color: primaryColor, fontWeight: FontWeight.bold, fontSize: 20),
|
||||
)),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new Expanded(
|
||||
child: new TextFormField(
|
||||
keyboardType: TextInputType.number,
|
||||
autofocus: true,
|
||||
controller: _doQty,
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
||||
cursorColor: primaryColor,
|
||||
decoration: new InputDecoration(
|
||||
fillColor: primaryColor,
|
||||
icon: Icon(
|
||||
FontAwesomeIcons.sortNumericUpAlt,
|
||||
color: primaryColor,
|
||||
),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey, width: 1.0)),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return AppTranslations.of(context).text("do.form.volume");
|
||||
}
|
||||
return null;
|
||||
},
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
child: LocalText(
|
||||
context,
|
||||
'do.cancel',
|
||||
color: secondaryColor,
|
||||
),
|
||||
onPressed: () {
|
||||
_doQty.clear();
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
FlatButton(
|
||||
color: primaryColor,
|
||||
child: LocalText(
|
||||
context,
|
||||
'do.enter',
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState.validate()) return;
|
||||
_save();
|
||||
})
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_save() {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
try {
|
||||
var qty = int.parse(_doQty.text);
|
||||
if (qty < 0)
|
||||
throw Exception("invalid number, must be zero or greater than zero");
|
||||
// if (qty > doLine.poLine.balanceQty)
|
||||
// throw Exception(
|
||||
// "invalid number, must be less than or equal to PO balance qty");
|
||||
this.doLine.qty = qty;
|
||||
Navigator.pop<DOLine>(context, this.doLine);
|
||||
} catch (e) {
|
||||
showMsgDialog(context, "Error", e.toString());
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_delete() {
|
||||
this.doLine.action = "delete";
|
||||
this.doLine.qty = 0;
|
||||
Navigator.pop<DOLine>(context, this.doLine);
|
||||
}
|
||||
}
|
||||
209
lib/pages/do/do_storage_item.dart
Normal file
209
lib/pages/do/do_storage_item.dart
Normal file
@@ -0,0 +1,209 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/storage_model.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/util.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/vo/storage.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
typedef OnSave = void Function(String storageID, String storageName);
|
||||
|
||||
class DOStorageItem extends StatefulWidget {
|
||||
final DOLine doLine;
|
||||
final OnSave onSave;
|
||||
const DOStorageItem({Key key, this.doLine, this.onSave}) : super(key: key);
|
||||
@override
|
||||
_DOStorageItemState createState() => _DOStorageItemState();
|
||||
}
|
||||
|
||||
class _DOStorageItemState extends State<DOStorageItem> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool _isLoading = false;
|
||||
String currentStorageID;
|
||||
TextEditingController _product = new TextEditingController();
|
||||
TextEditingController _quantity = new TextEditingController();
|
||||
DOLine doLine = DOLine();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
this.doLine = widget.doLine;
|
||||
|
||||
if (doLine.storageID != null && doLine.storageID.isNotEmpty) {
|
||||
this.currentStorageID = doLine.storageID;
|
||||
}
|
||||
_product.text = this.doLine.productName;
|
||||
_quantity.text = this.doLine.qty.toString();
|
||||
}
|
||||
|
||||
Widget showStorages(BuildContext context, StorageModel storageModel) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Image.asset(
|
||||
"assets/inventory.png",
|
||||
width: 30,
|
||||
height: 30,
|
||||
color: primaryColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
new Flexible(
|
||||
child: Container(
|
||||
width: 170.0,
|
||||
child: DropdownButton<String>(
|
||||
value: currentStorageID,
|
||||
isExpanded: true,
|
||||
hint: Text(
|
||||
'Select Storage',
|
||||
style: labelStyle,
|
||||
),
|
||||
onChanged: changedStorage,
|
||||
items: storageModel
|
||||
.getStorage(doLine.productID)
|
||||
.map<DropdownMenuItem<String>>((Storage storage) {
|
||||
return new DropdownMenuItem<String>(
|
||||
value: storage.id,
|
||||
child: new Text(storage.name, style: textStyle),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void changedStorage(selected) {
|
||||
setState(() {
|
||||
currentStorageID = selected;
|
||||
});
|
||||
}
|
||||
|
||||
Widget showStorgeTable(BuildContext context, StorageModel storageModel) {
|
||||
return Container(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "storge"),
|
||||
),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "storage.product.qty"),
|
||||
),
|
||||
],
|
||||
rows: getProductRow(storageModel.getStorage(doLine.productID)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Storage> storages) {
|
||||
return storages.map((s) {
|
||||
return MyDataRow(
|
||||
onSelectChanged: (bool selected) {
|
||||
setState(() {
|
||||
currentStorageID = s.id;
|
||||
});
|
||||
},
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(s.name, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(s.products
|
||||
.firstWhere((p) => p.id == doLine.productID)
|
||||
.quantity),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var storgeModel = Provider.of<StorageModel>(context);
|
||||
|
||||
final productbox = Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.product"),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Text(_product.text, style: textStyle)
|
||||
],
|
||||
));
|
||||
|
||||
final quantitybox = Container(
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do.quantity"),
|
||||
SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Text(formatNumber(this.doLine.qty), style: textStyle)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text("DO"),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.save),
|
||||
onPressed: () {
|
||||
_save();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.only(left: 24.0, right: 24.0, top: 10),
|
||||
children: <Widget>[
|
||||
productbox,
|
||||
quantitybox,
|
||||
showStorages(context, storgeModel),
|
||||
showStorgeTable(context, storgeModel)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
_save() {
|
||||
this.doLine.storageID = currentStorageID;
|
||||
var storageName =
|
||||
Provider.of<StorageModel>(context).getStorageName(currentStorageID);
|
||||
this.doLine.storageName = storageName;
|
||||
if (widget.onSave != null)
|
||||
widget.onSave(this.doLine.storageID, storageName);
|
||||
Navigator.pop<DOLine>(context, this.doLine);
|
||||
}
|
||||
}
|
||||
165
lib/pages/do/photo_page.dart
Normal file
165
lib/pages/do/photo_page.dart
Normal file
@@ -0,0 +1,165 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
|
||||
import '../util.dart';
|
||||
|
||||
class PhotoPage extends StatefulWidget {
|
||||
PhotoPage({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PhotoPageState createState() => _PhotoPageState();
|
||||
}
|
||||
|
||||
class _PhotoPageState extends State<PhotoPage> {
|
||||
File receiptImageFile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var languageModel = Provider.of<LanguageModel>(context);
|
||||
|
||||
final receiptImageBox = Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 5.0),
|
||||
child: Container(
|
||||
color: Colors.grey[400],
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: Text(
|
||||
AppTranslations.of(context).text('do.receipt'),
|
||||
style:
|
||||
languageModel.isEng ? photoLabelStyle : photoLabelStyleMM,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
ButtonTheme.bar(
|
||||
child: new ButtonBar(
|
||||
alignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new FlatButton(
|
||||
child: Icon(
|
||||
Icons.add_photo_alternate,
|
||||
size: 60.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
onPressed: () {
|
||||
pickImageFromGallery(ImageSource.gallery);
|
||||
},
|
||||
),
|
||||
],
|
||||
)),
|
||||
ButtonTheme.bar(
|
||||
child: new ButtonBar(
|
||||
alignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new FlatButton(
|
||||
child: Icon(
|
||||
Icons.add_a_photo,
|
||||
size: 50.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
onPressed: () {
|
||||
pickImageFromCamera(ImageSource.camera);
|
||||
},
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
receiptShowImage(),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(AppTranslations.of(context).text("do.receipt.title"),
|
||||
style: Provider.of<LanguageModel>(context).isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode')),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: () {
|
||||
if (receiptImageFile == null) {
|
||||
showMsgDialog(
|
||||
context, "Error", "Please insert delivery receipt file");
|
||||
return;
|
||||
}
|
||||
Navigator.pop(context, receiptImageFile);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.only(left: 24.0, right: 24.0, top: 20),
|
||||
children: <Widget>[
|
||||
receiptImageBox,
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget receiptShowImage() {
|
||||
return Container(
|
||||
child: receiptImageFile == null ? initialImage() : receiptEnableImage(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget initialImage() {
|
||||
var languageModel = Provider.of<LanguageModel>(context);
|
||||
|
||||
return Center(
|
||||
child: Text(
|
||||
AppTranslations.of(context).text('do.no.photo'),
|
||||
style: languageModel.isEng ? photoLabelStyle : photoLabelStyleMM,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget receiptEnableImage() {
|
||||
return Center(
|
||||
child: Image.file(
|
||||
receiptImageFile,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pickImageFromGallery(ImageSource source) async {
|
||||
var tempImage = await ImagePicker.pickImage(
|
||||
source: source, imageQuality: 80, maxWidth: 300);
|
||||
setState(() {
|
||||
receiptImageFile = tempImage;
|
||||
});
|
||||
}
|
||||
|
||||
pickImageFromCamera(ImageSource source) async {
|
||||
var tempImage = await ImagePicker.pickImage(
|
||||
source: source, imageQuality: 80, maxWidth: 300);
|
||||
setState(() {
|
||||
receiptImageFile = tempImage;
|
||||
});
|
||||
}
|
||||
}
|
||||
158
lib/pages/do/po_selection.dart
Normal file
158
lib/pages/do/po_selection.dart
Normal file
@@ -0,0 +1,158 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fcs/theme/theme.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
class POSelection extends StatefulWidget {
|
||||
final List<POSubmission> pos;
|
||||
final List<POSubmission> selectedPOs;
|
||||
|
||||
POSelection({Key key, this.pos, this.selectedPOs}) : super(key: key);
|
||||
|
||||
@override
|
||||
_POSelectionState createState() => new _POSelectionState();
|
||||
|
||||
static Future<void> showPOSelection(BuildContext context,
|
||||
List<POSubmission> pos, List<POSubmission> selectedPOs,
|
||||
{ok(List<POSubmission> pos)}) async {
|
||||
List<POSubmission> _selectedPOs = [];
|
||||
selectedPOs.forEach((i) => _selectedPOs.add(i));
|
||||
|
||||
final poselection = POSelection(
|
||||
pos: pos,
|
||||
selectedPOs: _selectedPOs,
|
||||
);
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertDialog(
|
||||
title: Center(
|
||||
child: LocalText(context, "po.title"),
|
||||
),
|
||||
content: Container(
|
||||
width: double.maxFinite,
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: <Widget>[
|
||||
poselection,
|
||||
Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: LocalText(context, "Cancel"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
FlatButton(
|
||||
color: primaryColor,
|
||||
child: LocalText(context, "Ok"),
|
||||
onPressed: () async {
|
||||
if (ok != null) ok(_selectedPOs);
|
||||
Navigator.of(context).pop();
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _POSelectionState extends State<POSelection> {
|
||||
List<POSubmission> pos;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
pos = widget.pos;
|
||||
pos.sort((p1, p2) => p1.poNumber.compareTo(p2.poNumber));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var width = MediaQuery.of(context).size.width * 0.8;
|
||||
var height = MediaQuery.of(context).size.height * 0.5;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: Text("Select All"),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
widget.selectedPOs.clear();
|
||||
widget.selectedPOs.addAll(pos);
|
||||
});
|
||||
}),
|
||||
Container(
|
||||
width: width,
|
||||
height: height,
|
||||
child: Column(
|
||||
children: pos.asMap().entries.map((p) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (widget.selectedPOs.contains(p.value)) {
|
||||
widget.selectedPOs.remove(p.value);
|
||||
} else {
|
||||
widget.selectedPOs.add(p.value);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Checkbox(
|
||||
onChanged: (v) => {_update(p.key)},
|
||||
value: widget.selectedPOs.contains(p.value),
|
||||
),
|
||||
Text(p.value.poNumber),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
// child: ListView.builder(
|
||||
// itemCount: pos.length,
|
||||
// scrollDirection: Axis.vertical,
|
||||
// itemBuilder: (BuildContext ctxt, int index) {
|
||||
// return InkWell(
|
||||
// onTap: () {
|
||||
// setState(() {
|
||||
// if (widget.selectedPOs.contains(pos[index])) {
|
||||
// widget.selectedPOs.remove(pos[index]);
|
||||
// } else {
|
||||
// widget.selectedPOs.add(pos[index]);
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Checkbox(
|
||||
// onChanged: (v) => {_update(index)},
|
||||
// value: widget.selectedPOs.contains(pos[index]),
|
||||
// ),
|
||||
// Text(pos[index].poNumber),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_update(int index) {
|
||||
setState(() {
|
||||
if (widget.selectedPOs.contains(pos[index])) {
|
||||
widget.selectedPOs.remove(pos[index]);
|
||||
} else {
|
||||
widget.selectedPOs.add(pos[index]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user