Files
fcs/lib/pages/po/po_submission_form.dart
2020-09-04 15:30:10 +06:30

602 lines
19 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.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/po/po_item.dart';
import 'package:fcs/fcs/common/helpers/theme.dart';
import 'package:fcs/vo/attach.dart';
import 'package:fcs/vo/po.dart';
import 'package:fcs/widget/img_file.dart';
import 'package:fcs/widget/label_widgets.dart';
import 'package:fcs/widget/local_text.dart';
import 'package:fcs/widget/localization/app_translations.dart';
import 'package:fcs/widget/multi_img_controller.dart';
import 'package:fcs/widget/multi_img_file.dart';
import 'package:fcs/widget/my_data_table.dart';
import 'package:fcs/widget/number_cell.dart';
import 'package:fcs/widget/progress.dart';
import '../../util.dart';
import '../document_log_page.dart';
import '../../fcs/common/pages/util.dart';
import 'po_files.dart';
class POSubmissionForm extends StatefulWidget {
final POSubmission poSubmission;
POSubmissionForm({this.poSubmission});
@override
_POSubmissionFormState createState() => _POSubmissionFormState();
}
class _POSubmissionFormState extends State<POSubmissionForm> {
final numberFormatter = new NumberFormat("#,###");
var dateFormatter = new DateFormat('dd MMM yyyy - hh:mm a');
MultiImgController multiImgController = MultiImgController();
TextEditingController _numberController = new TextEditingController();
TextEditingController _storage = new TextEditingController();
TextEditingController _comment = new TextEditingController();
TextEditingController _name = new TextEditingController();
TextEditingController _bizName = new TextEditingController();
List<POLine> poLines = new List();
bool _isLoading = false;
bool _isNew = true;
int _amount = 0;
String _date = "", _status = "";
POSubmission poSubmission = POSubmission();
AttachFile attachFile;
POFiles files = POFiles();
@override
void initState() {
super.initState();
if (widget.poSubmission != null) {
_isNew = false;
poSubmission = widget.poSubmission;
_date = dateFormatter.format(poSubmission.poDate);
_numberController.text = poSubmission.poNumber.toString();
_comment.text = poSubmission.comment;
_name.text = poSubmission.userName;
_bizName.text = poSubmission.bizName;
poLines = poSubmission.poLines;
_status = poSubmission.status;
_storage.text = poSubmission.storageCharge.toString();
multiImgController.setImageUrls = poSubmission.poReceiptUrls;
Provider.of<POSubmissionModel>(context, listen: false)
.loadPOLines(poSubmission.id)
.then((poLines) {
setState(() {
this.poSubmission.poLines = poLines;
_amount = poSubmission.getAmount;
});
});
} else {
_amount = 0;
_date = dateFormatter.format(DateTime.now());
var productModel = Provider.of<ProductModel>(context, listen: false);
productModel.products.forEach((p) {
var _poLine = POLine(
productID: p.id,
productName: p.name,
price: p.price,
balanceQty: 0,
qty: 0,
amount: 0);
poSubmission.poLines.add(_poLine);
});
}
}
@override
Widget build(BuildContext context) {
MainModel mainModel = Provider.of<MainModel>(context);
bool isBuyer = mainModel.user.isBuyer();
var logModel = Provider.of<LogModel>(context);
final dateBox = Container(
padding: EdgeInsets.only(top: 15, left: 20, bottom: 5),
child: Row(
children: <Widget>[
LocalText(context, "po.date"),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(_date, style: textStyle),
),
],
),
);
final numberBox = Container(
padding: EdgeInsets.only(top: 5, left: 20, bottom: 5),
child: Row(
children: <Widget>[
LocalText(context, "po.number"),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(
_numberController.text,
style: textStyle,
),
)
],
),
);
final userNameBox = Container(
padding: EdgeInsets.only(top: 5, left: 20, bottom: 5),
child: Row(
children: <Widget>[
LocalText(context, "po.name"),
Container(
padding: EdgeInsets.only(left: 20),
child: Text(
_name.text,
style: textStyle,
),
)
],
),
);
final bizNameBox = Container(
padding: EdgeInsets.only(top: 5, left: 20, bottom: 5),
child: Row(
children: <Widget>[
LocalText(context, "po.biz"),
Container(
padding: EdgeInsets.only(left: 20),
child: Text(
_bizName.text,
style: textStyle,
),
)
],
),
);
final statusBox = Container(
padding: EdgeInsets.only(top: 5, left: 20),
child: Row(
children: <Widget>[
LocalText(context, "po.status"),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(
_status,
style: textStyle,
),
)
],
),
);
final commentBox = Container(
padding: EdgeInsets.only(top: 5, left: 20),
child: Row(
children: <Widget>[
LocalText(context, "po.comment"),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(
_comment.text,
style: textStyle,
),
)
],
),
);
final amountBox = Container(
padding: EdgeInsets.only(top: 5, left: 10),
child: labeledText(context, formatNumber(_amount), "po.amount",
number: true));
final storageBox = Container(
padding: EdgeInsets.only(top: 5, left: 20),
child: Row(
children: <Widget>[
LocalText(context, "po.storage_charge"),
Container(
padding: EdgeInsets.only(left: 10),
child: Text(
_storage.text,
style: textStyle,
),
)
],
),
);
final poPaymentBox = Container(
padding: EdgeInsets.only(left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
LocalText(context, "po.po_payment_receipt"),
MultiImageFile(
enabled: isBuyer
? _isNew || this.poSubmission.isPending() ? true : false
: false,
controller: multiImgController,
title: "Receipt File",
)
]));
final storagePaymentBox = Container(
padding: EdgeInsets.only(left: 20),
child: Row(children: <Widget>[
LocalText(context, "po.storage_receipt"),
ImageFile(
enabled: isBuyer
? _isNew || this.poSubmission.isPending() ? true : false
: false,
initialImgUrl: this.poSubmission.storageReceiptUrl,
title: "Receipt File",
onFile: (file) {
this.files.setStorageChargeFile = file;
}),
]));
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
backgroundColor: primaryColor,
title: Text(AppTranslations.of(context).text("po"),
style: Provider.of<LanguageModel>(context).isEng
? TextStyle(fontSize: 18)
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode')),
actions: <Widget>[
_isNew || !mainModel.showHistoryBtn()
? Container()
: IconButton(
icon: Icon(Icons.history),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DocumentLogPage(docID: poSubmission.id)),
);
},
),
isBuyer && (_isNew || poSubmission.isPending())
? IconButton(
icon: Icon(Icons.send),
onPressed: () {
showConfirmDialog(context, "po.confirm", () {
_submit();
});
},
)
: Container(),
isBuyer
? Container()
: PopupMenuButton(
onSelected: _select,
itemBuilder: (context) => [
PopupMenuItem(
enabled: poSubmission.isPending(),
value: 1,
child: Text("Approve PO"),
),
PopupMenuItem(
enabled: poSubmission.isPending(),
value: 2,
child: Text("Reject PO"),
),
PopupMenuItem(
enabled: mainModel.user.isOwner() &&
poSubmission.isApproved(),
value: 3,
child: Text("Cancel PO"),
),
],
),
],
),
// floatingActionButton: isBuyer && (_isNew || poSubmission.isPending())
// ? FloatingActionButton(
// backgroundColor: primaryColor,
// child: Icon(Icons.add),
// onPressed: () async {
// final POLine poLine = await Navigator.push<POLine>(
// context,
// MaterialPageRoute(builder: (context) => POItem()),
// );
// _save(poLine);
// },
// )
// : null,
body: Container(
child: ListView(
children: <Widget>[
dateBox,
Divider(),
_isNew ? Container() : numberBox,
_isNew ? Container() : Divider(),
_isNew ? Container() : userNameBox,
_isNew ? Container() : Divider(),
_isNew ? Container() : bizNameBox,
_isNew ? Container() : Divider(),
_isNew ? Container() : statusBox,
_isNew ||
widget.poSubmission.comment == null ||
widget.poSubmission.comment == ''
? Container()
: Divider(),
_isNew ||
widget.poSubmission.comment == null ||
widget.poSubmission.comment == ''
? Container()
: commentBox,
_isNew ? Container() : Divider(),
amountBox,
Divider(),
poPaymentBox,
Divider(),
_isNew || !poSubmission.hasStorageCharge()
? Container()
: storageBox,
_isNew || !poSubmission.hasStorageCharge()
? Container()
: Divider(),
_isNew || !poSubmission.hasStorageCharge()
? Container()
: storagePaymentBox,
_isNew || !poSubmission.hasStorageCharge()
? Container()
: Divider(),
Container(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: MyDataTable(
headingRowHeight: 40,
columnSpacing: 7,
columns: _isNew
? [
MyDataColumn(
label: LocalText(context, "po.product")),
MyDataColumn(
label: LocalText(context, "po.price"),
numeric: true),
MyDataColumn(
label: LocalText(context, "po.volume"),
numeric: true),
MyDataColumn(
label: LocalText(context, "po.amount"),
numeric: true),
]
: [
MyDataColumn(
label: LocalText(context, "po.product")),
MyDataColumn(
label: LocalText(context, "po.price"),
numeric: true),
MyDataColumn(
label: LocalText(context, "po.balance.volume"),
numeric: true),
MyDataColumn(
label: LocalText(context, "po.volume"),
numeric: true),
MyDataColumn(
label: LocalText(context, "po.amount"),
numeric: true),
],
rows: getProductRow(poSubmission.poLines),
),
),
),
],
),
),
),
);
}
_select(s) {
if (s == 1) {
showConfirmDialog(context, "po.approve.confirm", () {
_approve();
});
} else if (s == 2) {
showCommentDialog(context, (comment) {
this.poSubmission.comment = comment;
_reject();
});
} else if (s == 3) {
showConfirmDialog(context, "po.cancel.confirm", () {
_cancel();
});
}
}
List<MyDataRow> getProductRow(List<POLine> poLines) {
MainModel mainModel = Provider.of<MainModel>(context);
bool isBuyer = mainModel.user.isBuyer();
ProductModel productModel = Provider.of<ProductModel>(context);
if (poLines.isNotEmpty) {
poLines.forEach((d) {
productModel.products.forEach((p) {
if (p.id == d.productID) {
d.displayOrder = p.displayOrder;
} else {
return;
}
});
});
poLines.sort((p1, p2) => p1.displayOrder.compareTo(p2.displayOrder));
}
return poLines.map((p) {
return MyDataRow(
onSelectChanged: (bool selected) async {
if (!isBuyer) return;
if (_isNew || this.poSubmission.isPending()) {
var poLine = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => POItem(
poLine: p,
)),
);
_save(poLine);
}
},
cells: _isNew
? [
MyDataCell(
new Text(
p.productName,
style: textStyle,
),
),
MyDataCell(NumberCell(p.price)),
MyDataCell(
Container(
alignment: Alignment.centerRight,
width: 100,
child: NumberCell(
p.qty,
textStyle: textStyleOdd,
),
),
),
MyDataCell(NumberCell(p.amount)),
]
: [
MyDataCell(
new Text(
p.productName,
style: textStyle,
),
),
MyDataCell(NumberCell(p.price)),
MyDataCell(NumberCell(p.balanceQty)),
MyDataCell(NumberCell(p.qty)),
MyDataCell(NumberCell(p.amount)),
],
);
}).toList();
}
_save(POLine poLine) {
if (poLine == null) return;
if (poLine.action == "create") {
if (poSubmission.poLines.contains(poLine)) {
showMsgDialog(context, "Error", "Duplicate line");
return;
}
poSubmission.poLines.add(poLine);
} else if (poLine.action == "delete") {
poSubmission.poLines.remove(poLine);
}
setState(() {
_amount = poSubmission.getAmount;
});
}
_submit() async {
if (poSubmission.poLines.length == 0) {
showMsgDialog(context, "Error", "No product line");
return;
}
List<POLine> _poLines = [];
poSubmission.poLines.forEach((p) => p.qty <= 0 ? _poLines.add(p) : p);
poSubmission.poLines.removeWhere((p) => p.qty <= 0);
setState(() {
_isLoading = true;
});
try {
POSubmissionModel poModel = Provider.of<POSubmissionModel>(context);
if (_isNew) {
await poModel.createPO(poSubmission, multiImgController.getAddedFile);
} else {
if (poSubmission.hasStorageCharge()) {
if (files.storageChargeFile == null) {
showMsgDialog(
context, "Error", "Please insert storage charge file");
return;
}
}
await poModel.updatePO(poSubmission, multiImgController.getAddedFile,
multiImgController.getDeletedUrl);
}
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
_poLines.forEach((e) {
if (!poSubmission.poLines.contains(e)) poSubmission.poLines.add(e);
});
});
}
}
_approve() async {
setState(() {
_isLoading = true;
});
var oldStatus = poSubmission.status;
try {
POSubmissionModel poModel = Provider.of<POSubmissionModel>(context);
poSubmission.status = "approved";
await poModel.approvePO(poSubmission);
Navigator.pop(context);
} catch (e) {
poSubmission.status = oldStatus;
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
_reject() async {
setState(() {
_isLoading = true;
});
try {
POSubmissionModel poModel = Provider.of<POSubmissionModel>(context);
await poModel.rejectPO(poSubmission);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
_cancel() async {
setState(() {
_isLoading = true;
});
try {
POSubmissionModel poModel = Provider.of<POSubmissionModel>(context);
await poModel.cancelPO(poSubmission);
Navigator.pop(context);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
}