import 'dart:io'; import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/payment.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/img_picker.dart'; import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_title.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; class PaymentPage extends StatefulWidget { final Invoice invoice; final bool forCustomer; PaymentPage({this.invoice, this.forCustomer}); @override _PaymentPageState createState() => _PaymentPageState(); } class _PaymentPageState extends State { TextEditingController _amountController = new TextEditingController(); var dateFormatter = new DateFormat('dd MMM yyyy'); Invoice _invoice = new Invoice(); bool _isLoading = false; bool isNew; File _file; bool _hasBalance; @override void initState() { super.initState(); _invoice = widget.invoice; _hasBalance = widget.invoice.balance > 0; _loadInvoice(); } _loadInvoice() async { InvoiceModel invoiceModel = Provider.of(context, listen: false); Invoice i = await invoiceModel.getInvoice(_invoice.id); setState(() { _invoice = i; }); } @override void dispose() { super.dispose(); } final DateFormat dateFormat = DateFormat("d MMM yyyy"); @override Widget build(BuildContext context) { final amountBox = InputText( labelTextKey: 'pm.amount', controller: _amountController, iconData: FontAwesomeIcons.moneyBill); final receiptFileBox = Row(children: [ Padding( padding: const EdgeInsets.only(right: 8.0), child: Text("Attach receipt"), ), LocalImagePicker( color: primaryColor, title: "Receipt", onFile: (f) => _file = f, ) ]); final payBtnBox = LocalButton( callBack: _pay, textKey: "pm.pay", ); return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( appBar: AppBar( centerTitle: true, leading: new IconButton( icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, title: Text(AppTranslations.of(context).text("pm_.title")), ), body: ListView( padding: const EdgeInsets.all(10.0), children: [ _hasBalance ? amountBox : Container(), SizedBox(height: 10), _hasBalance ? Align( child: Padding( padding: const EdgeInsets.all(8.0), child: receiptFileBox, ), alignment: Alignment.centerLeft, ) : Container(), _hasBalance ? payBtnBox : Container(), SizedBox(height: 15), LocalTitle(textKey: "pm.receipt"), Column( children: getCustomFeeRows(context), ), SizedBox(height: 25), ], ), ), ); } getCustomFeeRows(BuildContext context) { List dataRow = []; dataRow = _invoice?.payments?.map((p) { return Container( decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))), padding: const EdgeInsets.only( left: 5.0, right: 5.0, top: 5.0, bottom: 5.0), child: Row( children: [ Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( '${p.paymentDate != null ? dateFormatter.format(p.paymentDate) : ""}'), ), SizedBox( height: 5, ), LocalImagePicker( key: ValueKey(p.id), enabled: false, initialImgUrl: p.paymentReceiptURL, title: "Receipt", color: primaryColor, ) ], )), Expanded( flex: 1, child: Center( child: Column( children: [Text('\$ ${p.amount}'), Text('${p.status}')], ))), widget.forCustomer ? Container() : Expanded( flex: 1, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: p.status == payment_pending_status ? [ InkWell( onTap: () => _confirm(p), child: Padding( padding: const EdgeInsets.all(8.0), child: Icon( Icons.check, color: primaryColor, ), ), ), InkWell( onTap: () => _cancel(p), child: Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.close, color: primaryColor), ), ), ] : [], )), ], ), ); })?.toList() ?? []; dataRow.insert( 0, Container( decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))), padding: const EdgeInsets.only( left: 5.0, right: 5.0, top: 10.0, bottom: 15.0), child: Row( children: [ Expanded( flex: 1, child: Text('Receipt', style: TextStyle(color: Colors.grey))), Expanded( flex: 1, child: Text('Amount', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey))), widget.forCustomer ? Container() : Expanded( flex: 1, child: Text('Actions', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey))), ], ), )); dataRow.insert( dataRow.length, Container( padding: const EdgeInsets.only( left: 5.0, right: 5.0, top: 15.0, bottom: 15.0), child: Row( children: [ Expanded( flex: 1, child: Center( child: LocalText( context, 'pm.remaining_balance', color: Colors.black, fontWeight: FontWeight.bold, ), ), ), Expanded( flex: 1, child: Center( child: Text( '\$ ${widget.invoice.balance.toStringAsFixed(2)}', textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16.0)))), widget.forCustomer ? Container() : Expanded( flex: 1, child: Container(), ), ], ), )); return dataRow; } _confirm(Payment payment) { payment.status = payment_confirmed_status; showConfirmDialog(context, "invoice.payment.confirm.confirm", () => _updatePayment(payment)); } _cancel(Payment payment) { payment.status = payment_canceled_status; showConfirmDialog(context, "invoice.payment.cancel.confirm", () => _updatePayment(payment)); } _updatePayment(Payment payment) async { payment.invoiceID = widget.invoice.id; setState(() { _isLoading = true; }); try { InvoiceModel invoiceModel = Provider.of(context, listen: false); await invoiceModel.updatePaymentStatus(payment); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { setState(() { _isLoading = false; }); } } _pay() async { if (_file == null) { showMsgDialog(context, "Error", "Expect receipt attachment"); return; } double amount = double.tryParse(_amountController.text) ?? 0; if (amount <= 0) { showMsgDialog(context, "Error", "Expect valid amount"); return; } Payment payment = Payment(invoiceID: _invoice.id, amount: amount); setState(() { _isLoading = true; }); try { InvoiceModel invoiceModel = Provider.of(context, listen: false); await invoiceModel.pay(payment, _file); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { setState(() { _isLoading = false; }); } } }