add invoice pdf

This commit is contained in:
Sai Naw Wun
2020-10-26 04:41:24 +06:30
parent feec3c8687
commit 2786acfd08
33 changed files with 787 additions and 1114 deletions

View File

@@ -441,7 +441,7 @@
"invoice.payment_attachment":"Payment attachment", "invoice.payment_attachment":"Payment attachment",
"invoice.box_info":"Cartons", "invoice.box_info":"Cartons",
"invoice.cargo_table":"Cargo table", "invoice.cargo_table":"Cargo table",
"invoice.btn_create":"Create invoice", "invoice.issue.btn":"Issue invoice",
"invoice.btn_save":"Save invoice", "invoice.btn_save":"Save invoice",
"invoice.btn_payment_receipt":"Attachment payment receipt", "invoice.btn_payment_receipt":"Attachment payment receipt",
"invoice.description": "Description", "invoice.description": "Description",
@@ -458,8 +458,9 @@
"invoice.pdf": "Invoice PDF", "invoice.pdf": "Invoice PDF",
"invoice.total_custom_fee":"Total custom fee", "invoice.total_custom_fee":"Total custom fee",
"invoice.shipment_weight":"Shipment weight", "invoice.shipment_weight":"Shipment weight",
"invoice.popupmenu.pending":"Pending", "invoice.popupmenu.issused":"Issused",
"invoice.popupmenu.paid":"Paid", "invoice.popupmenu.paid":"Paid",
"invoice.popupmenu.cancel":"Canceled",
"invoice.shipment.title":"Select FCS shipment", "invoice.shipment.title":"Select FCS shipment",
"invoice.customer.title":"Select Customer", "invoice.customer.title":"Select Customer",
"invoice.add.custom.fee.menu":"Custom fee", "invoice.add.custom.fee.menu":"Custom fee",
@@ -468,6 +469,8 @@
"invoice.shipment.handling.fee.title":"Select shipment", "invoice.shipment.handling.fee.title":"Select shipment",
"invoice.shipment.number":"Shipment number", "invoice.shipment.number":"Shipment number",
"invoice.shipment.discount.title":"Select discount", "invoice.shipment.discount.title":"Select discount",
"invoice.cancel.btn":"Cancel",
"invoice.cancel.confirm":"Cancel invoice?",
"Invoices End ================================================================":"", "Invoices End ================================================================":"",
"Discount Start ================================================================":"", "Discount Start ================================================================":"",

View File

@@ -441,7 +441,8 @@
"invoice.payment_attachment":"ပေးချေပြီးဖိုင်များ", "invoice.payment_attachment":"ပေးချေပြီးဖိုင်များ",
"invoice.box_info":"Cartons", "invoice.box_info":"Cartons",
"invoice.cargo_table":"ကုန်ပစ္စည်းဇယား", "invoice.cargo_table":"ကုန်ပစ္စည်းဇယား",
"invoice.btn_create":"ငွေတောင်းခံလွှာ ပြုလုပ်ရန်", "invoice.issue.btn":"ငွေတောင်းခံလွှာ ထုတ်မည်",
"invoice.btn_save":"ငွေတောင်းခံလွှာ သိမ်းရန်", "invoice.btn_save":"ငွေတောင်းခံလွှာ သိမ်းရန်",
"invoice.btn_payment_receipt":"ငွေလက်ခံဖြတ်ပိုင်း ထည့်ရန်", "invoice.btn_payment_receipt":"ငွေလက်ခံဖြတ်ပိုင်း ထည့်ရန်",
"invoice.box.cargo_type": "ကုန်ပစ္စည်းအမျိုးအစားများ", "invoice.box.cargo_type": "ကုန်ပစ္စည်းအမျိုးအစားများ",
@@ -458,8 +459,9 @@
"invoice.pdf": "Invoice PDF", "invoice.pdf": "Invoice PDF",
"invoice.total_custom_fee":"အခွန်စုစုပေါင်း", "invoice.total_custom_fee":"အခွန်စုစုပေါင်း",
"invoice.shipment_weight":"Shipment weight", "invoice.shipment_weight":"Shipment weight",
"invoice.popupmenu.pending":"Pending", "invoice.popupmenu.issused":"Issused",
"invoice.popupmenu.paid":"Paid", "invoice.popupmenu.paid":"Paid",
"invoice.popupmenu.cancel":"Canceled",
"invoice.shipment.title":"Select FCS shipment", "invoice.shipment.title":"Select FCS shipment",
"invoice.customer.title":"Select Customer", "invoice.customer.title":"Select Customer",
"invoice.add.custom.fee.menu":"Custom fee", "invoice.add.custom.fee.menu":"Custom fee",
@@ -468,6 +470,8 @@
"invoice.shipment.number":"Shipment number", "invoice.shipment.number":"Shipment number",
"invoice.shipment.handling.fee.title":"Select shipment", "invoice.shipment.handling.fee.title":"Select shipment",
"invoice.shipment.discount.title":"Select discount", "invoice.shipment.discount.title":"Select discount",
"invoice.cancel.btn":"Cancel",
"invoice.cancel.confirm":"Cancel invoice?",
"Invoices End ================================================================":"", "Invoices End ================================================================":"",
"Discount Start ================================================================":"", "Discount Start ================================================================":"",

View File

@@ -0,0 +1,25 @@
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/helpers/api_helper.dart';
import 'package:fcs/helpers/firebase_helper.dart';
import 'package:logging/logging.dart';
class InvoiceDataProvider {
final log = Logger('InvoiceDataProvider');
static final InvoiceDataProvider instance = InvoiceDataProvider._();
InvoiceDataProvider._();
Future<void> createInvoice(Invoice invoice) async {
return await requestAPI("/invoices", "POST",
payload: invoice.toMap(), token: await getToken());
}
Future<void> updateInvoice(Invoice invoice) async {
return await requestAPI("/invoices", "PUT",
payload: invoice.toMap(), token: await getToken());
}
Future<void> cancelInvoice(Invoice invoice) async {
return await requestAPI("/invoices/cancel", "PUT",
payload: {"id": invoice.id}, token: await getToken());
}
}

View File

@@ -0,0 +1,34 @@
import 'package:fcs/data/provider/invoice_data_provider.dart';
import 'package:fcs/data/provider/shipment_data_provider.dart';
import 'package:fcs/data/services/shipment_service.dart';
import 'package:fcs/domain/entities/connectivity.dart';
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/shipment.dart';
import 'package:flutter/material.dart';
import 'invoice_service.dart';
class InvoiceServiceImp implements InvoiceService {
InvoiceServiceImp({
@required this.invoiceDataProvider,
@required this.connectivity,
});
final Connectivity connectivity;
final InvoiceDataProvider invoiceDataProvider;
@override
Future<void> cancelInvoice(Invoice invoice) {
return invoiceDataProvider.cancelInvoice(invoice);
}
@override
Future<void> createInvoice(Invoice invoice) {
return invoiceDataProvider.createInvoice(invoice);
}
@override
Future<void> updateInvoice(Invoice invoice) {
return invoiceDataProvider.updateInvoice(invoice);
}
}

View File

@@ -0,0 +1,8 @@
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/shipment.dart';
abstract class InvoiceService {
Future<void> createInvoice(Invoice invoice);
Future<void> updateInvoice(Invoice invoice);
Future<void> cancelInvoice(Invoice invoice);
}

View File

@@ -3,6 +3,7 @@ import 'package:fcs/data/provider/carton_data_provider.dart';
import 'package:fcs/data/provider/common_data_provider.dart'; import 'package:fcs/data/provider/common_data_provider.dart';
import 'package:fcs/data/provider/delivery_address_data_provider.dart'; import 'package:fcs/data/provider/delivery_address_data_provider.dart';
import 'package:fcs/data/provider/fcs_shipment_data_provider.dart'; import 'package:fcs/data/provider/fcs_shipment_data_provider.dart';
import 'package:fcs/data/provider/invoice_data_provider.dart';
import 'package:fcs/data/provider/package_data_provider.dart'; import 'package:fcs/data/provider/package_data_provider.dart';
import 'package:fcs/data/provider/rate_data_provider.dart'; import 'package:fcs/data/provider/rate_data_provider.dart';
import 'package:fcs/data/provider/shipment_data_provider.dart'; import 'package:fcs/data/provider/shipment_data_provider.dart';
@@ -13,6 +14,8 @@ import 'package:fcs/data/services/delivery_address_imp.dart';
import 'package:fcs/data/services/delivery_address_service.dart'; import 'package:fcs/data/services/delivery_address_service.dart';
import 'package:fcs/data/services/fcs_shipment_imp.dart'; import 'package:fcs/data/services/fcs_shipment_imp.dart';
import 'package:fcs/data/services/fcs_shipment_service.dart'; import 'package:fcs/data/services/fcs_shipment_service.dart';
import 'package:fcs/data/services/invoice_imp.dart';
import 'package:fcs/data/services/invoice_service.dart';
import 'package:fcs/data/services/rate_imp.dart'; import 'package:fcs/data/services/rate_imp.dart';
import 'package:fcs/data/services/rate_service.dart'; import 'package:fcs/data/services/rate_service.dart';
import 'package:fcs/data/services/shipment_imp.dart'; import 'package:fcs/data/services/shipment_imp.dart';
@@ -42,6 +45,7 @@ class Services {
RateService _rateService; RateService _rateService;
ShipmentService _shipmentService; ShipmentService _shipmentService;
CartonService _cartonService; CartonService _cartonService;
InvoiceService _invoiceService;
Services._() { Services._() {
_authService = AuthServiceImp( _authService = AuthServiceImp(
authFb: AuthFb.instance, authFb: AuthFb.instance,
@@ -65,6 +69,8 @@ class Services {
connectivity: null); connectivity: null);
_cartonService = CartonServiceImp( _cartonService = CartonServiceImp(
cartonDataProvider: CartonDataProvider.instance, connectivity: null); cartonDataProvider: CartonDataProvider.instance, connectivity: null);
_invoiceService = InvoiceServiceImp(
invoiceDataProvider: InvoiceDataProvider.instance, connectivity: null);
} }
AuthService get authService => _authService; AuthService get authService => _authService;
@@ -77,4 +83,5 @@ class Services {
RateService get rateService => _rateService; RateService get rateService => _rateService;
ShipmentService get shipmentService => _shipmentService; ShipmentService get shipmentService => _shipmentService;
CartonService get cartonService => _cartonService; CartonService get cartonService => _cartonService;
InvoiceService get invoiceService => _invoiceService;
} }

View File

@@ -91,3 +91,9 @@ const shipment_pickuped_status = "pickuped";
const shipment_packed_status = "packed"; const shipment_packed_status = "packed";
const shipment_shipped_status = "shipped"; const shipment_shipped_status = "shipped";
const shipment_delivered_status = "delivered"; const shipment_delivered_status = "delivered";
// invoice status
const invoice_issued_status = "issued";
const invoice_saved_status = "saved";
const invoice_cancel_status = "canceled";
const invoice_paid_status = "paid";

View File

@@ -4,7 +4,7 @@ class CargoType {
double rate; double rate;
double weight; double weight;
double amount; double get calAmount => (calRate ?? 0) * (calWeight ?? 0);
double calRate; double calRate;
double calWeight; double calWeight;
@@ -16,9 +16,16 @@ class CargoType {
rate: map['rate']?.toDouble() ?? 0, rate: map['rate']?.toDouble() ?? 0,
weight: map['weight']?.toDouble() ?? 0, weight: map['weight']?.toDouble() ?? 0,
calWeight: map['cal_weight']?.toDouble() ?? 0, calWeight: map['cal_weight']?.toDouble() ?? 0,
calRate: map['cal_rate']?.toDouble() ?? 0,
); );
} }
CargoType({this.id, this.name, this.rate, this.weight, this.calWeight}); CargoType(
{this.id,
this.name,
this.rate,
this.weight,
this.calWeight,
this.calRate});
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
@@ -27,6 +34,7 @@ class CargoType {
'rate': rate, 'rate': rate,
'weight': weight, 'weight': weight,
'cal_weight': calWeight, 'cal_weight': calWeight,
'cal_rate': calRate,
}; };
} }

View File

@@ -171,7 +171,7 @@ class Carton {
'length': length, 'length': length,
'width': width, 'width': width,
'height': height, 'height': height,
'delivery_address': deliveryAddress.toMap(), 'delivery_address': deliveryAddress?.toMap(),
'carton_type': cartonType, 'carton_type': cartonType,
'mix_carton_id': mixCartonID, 'mix_carton_id': mixCartonID,
}; };

View File

@@ -1,3 +1,4 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/custom_duty.dart'; import 'package:fcs/domain/entities/custom_duty.dart';
@@ -13,6 +14,7 @@ class Invoice {
DateTime invoiceDate; DateTime invoiceDate;
String fcsShipmentID; String fcsShipmentID;
String userID; String userID;
String fcsID;
String userName; String userName;
String phoneNumber; String phoneNumber;
String status; String status;
@@ -28,20 +30,23 @@ class Invoice {
List<Shipment> shipments; List<Shipment> shipments;
Discount discount; Discount discount;
PaymentMethod paymentMethod; PaymentMethod paymentMethod;
String invoiceURL;
List<CargoType> getCargoTypes(Rate rate) { List<CargoType> getCargoTypes(Rate rate) {
List<CargoType> cargoTypes = []; if (cargoTypes != null) return cargoTypes;
List<CargoType> _cargoTypes = [];
double totalCalWeight = 0; double totalCalWeight = 0;
cartons.forEach((carton) { cartons.forEach((carton) {
if (carton.isChecked) { if (carton.isChecked) {
var _cartonsTypes = var _cartonsTypes =
carton.getCargoTypeForCalWeight(rate.volumetricRatio); carton.getCargoTypeForCalWeight(rate.volumetricRatio);
_cartonsTypes.forEach((ct) { _cartonsTypes.forEach((ct) {
if (cargoTypes.contains(ct)) { if (_cargoTypes.contains(ct)) {
CargoType existing = cargoTypes.firstWhere((wc) => wc.id == ct.id); CargoType existing = _cargoTypes.firstWhere((wc) => wc.id == ct.id);
existing.calWeight += ct.calWeight; existing.calWeight += ct.calWeight;
} else { } else {
cargoTypes.add(ct.clone()); _cargoTypes.add(ct.clone());
} }
totalCalWeight += ct.calWeight; totalCalWeight += ct.calWeight;
}); });
@@ -51,25 +56,23 @@ class Invoice {
DiscountByWeight discountByWeight = DiscountByWeight discountByWeight =
rate.getDiscountByWeight(totalCalWeight); rate.getDiscountByWeight(totalCalWeight);
cargoTypes.forEach((e) { _cargoTypes.forEach((e) {
double r = double r =
e.rate - (discountByWeight != null ? discountByWeight.discount : 0); e.rate - (discountByWeight != null ? discountByWeight.discount : 0);
double amount = e.calWeight * r;
e.calRate = r; e.calRate = r;
e.amount = amount;
}); });
return cargoTypes; return _cargoTypes;
} }
double getTotal(Rate rate) { double getTotal(Rate rate) {
List<CargoType> cargoTypes = getCargoTypes(rate); List<CargoType> cargoTypes = getCargoTypes(rate);
var total = cargoTypes.fold(0.0, (p, c) => c.amount + p); var total = cargoTypes.fold(0.0, (p, c) => c.calAmount + p);
return total; return total;
} }
double getNetAmount(Rate rate) { double getNetAmount(Rate rate) {
List<CargoType> cargoTypes = getCargoTypes(rate); List<CargoType> cargoTypes = getCargoTypes(rate);
var total = cargoTypes.fold(0.0, (p, c) => c.amount + p); var total = cargoTypes.fold(0.0, (p, c) => c.calAmount + p);
total += getCustomFee(); total += getCustomFee();
total += getDeliveryFee(); total += getDeliveryFee();
total += getHandlingFee(); total += getHandlingFee();
@@ -78,7 +81,7 @@ class Invoice {
} }
double getHandlingFee() { double getHandlingFee() {
return shipments?.where((sh) => sh.isSelected)?.fold(0, (p, s) { return shipments?.where((sh) => sh.isSelected ?? false)?.fold(0, (p, s) {
return p + (s?.handlingFee ?? 0) - (s?.paidHandlingFee ?? 0); return p + (s?.handlingFee ?? 0) - (s?.paidHandlingFee ?? 0);
}); });
} }
@@ -97,10 +100,11 @@ class Invoice {
double getDiscount() => discount == null ? 0 : discount.amount; double getDiscount() => discount == null ? 0 : discount.amount;
Invoice({ Invoice(
this.id, {this.id,
this.invoiceNumber, this.invoiceNumber,
this.invoiceDate, this.invoiceDate,
this.fcsID,
this.userName, this.userName,
this.phoneNumber, this.phoneNumber,
this.amount, this.amount,
@@ -110,20 +114,51 @@ class Invoice {
this.cartons, this.cartons,
this.cargoTypes, this.cargoTypes,
this.handlingFee, this.handlingFee,
this.deliveryFee,
this.fcsShipmentID, this.fcsShipmentID,
this.shipments, this.shipments,
}); this.invoiceURL,
this.paymentMethod});
factory Invoice.fromMap(Map<String, dynamic> map, String docID) { factory Invoice.fromMap(Map<String, dynamic> map, String docID) {
var invd = (map['invoice_date'] as Timestamp);
var cargoTypesMaps =
List<Map<String, dynamic>>.from(map['cargo_types'] ?? []);
var cargoTypes =
cargoTypesMaps.map((e) => CargoType.fromMap(e, e["id"])).toList();
var customDutiesMap =
List<Map<String, dynamic>>.from(map['custom_duties'] ?? []);
var customDuties =
customDutiesMap.map((e) => CustomDuty.fromMap(e, e["id"])).toList();
var handlingShipmentsMap =
List<Map<String, dynamic>>.from(map['handling_fee_shipments'] ?? []);
var handingShipments =
handlingShipmentsMap.map((e) => Shipment.fromMap(e, e["id"])).toList();
var cartonsMap = List<Map<String, dynamic>>.from(map['cartons'] ?? []);
var cartons = cartonsMap.map((e) => Carton.fromMap(e, e["id"])).toList();
var paymentMethodMap = map['payment_method'];
var paymentMethod = paymentMethodMap != null
? PaymentMethod.fromMap(paymentMethodMap, paymentMethodMap['id'])
: null;
var discountMap = map['discount'];
var discount = Discount.fromMap(discountMap, discountMap['id']);
return Invoice( return Invoice(
id: docID, id: docID,
invoiceNumber: map['invoice_number'], invoiceNumber: map['invoice_number'],
invoiceDate: map['invoice_date'], invoiceDate: invd?.toDate(),
userName: map['user_name'], userName: map['user_name'],
fcsID: map['fcs_id'],
phoneNumber: map['phone_number'], phoneNumber: map['phone_number'],
amount: map['amount'], amount: map['amount'],
status: map['status'], status: map['status'],
discount: map['discount'], cartons: cartons,
cargoTypes: cargoTypes,
shipments: handingShipments,
customDuties: customDuties,
deliveryFee: map['delivery_fee'],
invoiceURL: map['invoice_url'],
paymentMethod: paymentMethod,
discount: discount,
); );
} }
@@ -131,17 +166,24 @@ class Invoice {
List _cargoTypes = cargoTypes.map((c) => c.toMap()).toList(); List _cargoTypes = cargoTypes.map((c) => c.toMap()).toList();
List _customDuties = customDuties?.map((c) => c.toMap())?.toList(); List _customDuties = customDuties?.map((c) => c.toMap())?.toList();
List _cartons = cartons?.map((c) => c.toMap())?.toList() ?? []; List _cartons = cartons?.map((c) => c.toMap())?.toList() ?? [];
List _shipments = shipments?.map((s) => s.toMap())?.toList() ?? [];
return { return {
"id": id, "id": id,
"invoice_date": invoiceDate, "invoice_date": invoiceDate?.toUtc()?.toIso8601String(),
"user_id": userID, "user_id": userID,
"user_name": userName,
"invoice_number": invoiceNumber,
'fcs_shipment_id': fcsShipmentID, 'fcs_shipment_id': fcsShipmentID,
'cargo_types': _cargoTypes, 'cargo_types': _cargoTypes,
'custom_duties': _customDuties, 'custom_duties': _customDuties,
'handling_fee_shipments': _shipments,
'cartons': _cartons, 'cartons': _cartons,
'discount': discount?.toMap(), 'discount': discount?.toMap(),
'amount': amount,
'handling_fee': handlingFee, 'handling_fee': handlingFee,
'delivery_fee': deliveryFee, 'delivery_fee': deliveryFee,
'invoice_url': invoiceURL,
'payment_method': paymentMethod?.toMap(),
}; };
} }
} }

View File

@@ -100,7 +100,7 @@ class Shipment {
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
List _boxes = boxes.map((l) => l.toMap()).toList(); List _boxes = boxes?.map((l) => l.toMap())?.toList() ?? [];
return { return {
"id": id, "id": id,

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
@@ -5,9 +6,11 @@ import 'package:device_info/device_info.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fcs/domain/vo/status.dart'; import 'package:fcs/domain/vo/status.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart';
import '../config.dart'; import '../config.dart';
import 'dev_info.dart'; import 'dev_info.dart';
import 'firebase_helper.dart';
final log = Logger('requestAPI'); final log = Logger('requestAPI');
@@ -146,3 +149,92 @@ Future<dynamic> requestDownloadPDFAPI(String path, method,
throw e; throw e;
} }
} }
typedef OnDownloadDone(File file);
// request makes http request
// if token is null
Future<dynamic> requestDownload(String path, method,
{dynamic payload,
String token,
String url,
String filePath,
OnDownloadDone onDownloadDone}) async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
String deviceName = "${androidInfo.model}(${androidInfo.id})";
log.info("device:${androidInfo.androidId},deviceName:$deviceName");
var bytes = utf8.encode(payload);
var base64Str = base64.encode(bytes);
String escapePayload = HtmlEscape().convert(base64Str);
try {
String baseUrl = url == null ? Config.instance.apiURL : url;
log.info("Path:$baseUrl$path");
HttpClient client = new HttpClient();
// var _downloadData = StringBuffer();
var request = await client.postUrl(Uri.parse("$baseUrl$path"));
request.headers.set("Project-ID", Config.instance.reportProjectID);
if (token != null) {
request.headers.set("Token", token);
}
if (androidInfo.androidId != null) {
request.headers.set("Device", androidInfo.androidId + ":" + deviceName);
}
request.headers
.set(HttpHeaders.contentTypeHeader, 'application/json; charset=utf-8');
request.headers.set("payload", escapePayload);
request.write(payload);
// request.write(escapePayload);
var response = await request.close();
print("headers:${response.headers}");
var _downloadData = List<int>();
var cd = response.headers.value("content-disposition");
String fileName = "download.csv";
if (cd != null && cd.contains("filename=")) {
fileName = cd.substring(cd.indexOf("=") + 1);
}
var file = filePath + "/" + fileName;
var fileSave = new File(filePath + "/" + fileName);
response.listen((d) => _downloadData.addAll(d), onDone: () async {
await fileSave.writeAsBytes(_downloadData);
if (onDownloadDone != null) {
onDownloadDone(fileSave);
}
// final message = await OpenFile.open(file);
// log.info("Open file result:${message.message}");
// if (message.message != "done") {
// throw Exception(message.message);
// }
// await Share.file(fileName, fileName, _downloadData,
// downloadType == DownloadType.CSV ? "text/csv" : "application/pdf");
});
} catch (e) {
e.toString();
log.warning("path:$path, api:$e");
throw e;
}
}
Future<File> downloadPDF(
String templateName, Map<String, dynamic> values) async {
final completer = Completer<File>();
final directory = await getApplicationSupportDirectory();
String path = ('${directory.path}');
log.info("download file path:$path");
var data = {"template_name": templateName, "data": values};
print("payload:$data");
await requestDownload("/api/pdf", "POST",
filePath: path,
url: Config.instance.reportURL,
token: await getToken(),
payload: jsonEncode(data), onDownloadDone: (f) async {
completer.complete(f);
});
return completer.future;
}

View File

@@ -0,0 +1,12 @@
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
class PdfCacheMgr {
static const key = 'pdfs';
static CacheManager pdfs = CacheManager(
Config(
key,
stalePeriod: const Duration(days: 7),
maxNrOfCacheObjects: 20,
),
);
}

View File

@@ -162,6 +162,18 @@ class _CartonEditorState extends State<CartonEditor> {
}); });
} }
_loadMixCartons() async {
if (_fcsShipment == null || _fcsShipment.id == null) return;
if (_selectedCartonType != carton_small_bag) return;
CartonModel cartonModel = Provider.of<CartonModel>(context, listen: false);
List<Carton> cartons =
await cartonModel.getMixCartonsByFcsShipment(_fcsShipment.id);
setState(() {
_mixCartons = cartons;
});
}
_calShipmentWeight() { _calShipmentWeight() {
double l = double.parse(_lengthController.text, (s) => 0); double l = double.parse(_lengthController.text, (s) => 0);
double w = double.parse(_widthController.text, (s) => 0); double w = double.parse(_widthController.text, (s) => 0);
@@ -196,6 +208,7 @@ class _CartonEditorState extends State<CartonEditor> {
setState(() { setState(() {
_fcsShipment = v; _fcsShipment = v;
}); });
_loadMixCartons();
}, },
labelKey: "shipment.pack.fcs.shipment", labelKey: "shipment.pack.fcs.shipment",
iconData: Ionicons.ios_airplane, iconData: Ionicons.ios_airplane,
@@ -291,7 +304,6 @@ class _CartonEditorState extends State<CartonEditor> {
values: boxModel.cartonTypes, values: boxModel.cartonTypes,
selectedValue: _selectedCartonType, selectedValue: _selectedCartonType,
callback: (v) { callback: (v) {
print(v);
setState(() { setState(() {
_selectedCartonType = v; _selectedCartonType = v;
}); });

View File

@@ -5,10 +5,10 @@ import 'package:fcs/pages/widgets/my_data_table.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class InvoiceDiscountTable extends StatelessWidget { class InvoiceDiscountList extends StatelessWidget {
final List<Discount> discounts; final List<Discount> discounts;
const InvoiceDiscountTable({ const InvoiceDiscountList({
Key key, Key key,
this.discounts, this.discounts,
}) : super(key: key); }) : super(key: key);

View File

@@ -1,3 +1,4 @@
import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/custom_duty.dart'; import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/entities/discount.dart'; import 'package:fcs/domain/entities/discount.dart';
@@ -8,12 +9,12 @@ import 'package:fcs/domain/entities/shipment.dart';
import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/carton/model/carton_model.dart'; import 'package:fcs/pages/carton/model/carton_model.dart';
import 'package:fcs/pages/discount/discount_list.dart';
import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/discount/model/discount_model.dart';
import 'package:fcs/pages/invoice/invoice_discount_table.dart'; import 'package:fcs/pages/invoice/editor/invoice_carton_table.dart';
import 'package:fcs/pages/invoice/invoice_shipment_table.dart'; import 'package:fcs/pages/invoice/editor/invoice_discount_list.dart';
import 'package:fcs/pages/invoice/editor/invoice_handling_fee_list.dart';
import 'package:fcs/pages/invoice/invoice_table.dart'; import 'package:fcs/pages/invoice/invoice_table.dart';
import 'package:fcs/pages/invoice/invoice_carton_table.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart';
import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/payment_methods/model/payment_method_model.dart'; import 'package:fcs/pages/payment_methods/model/payment_method_model.dart';
@@ -22,12 +23,11 @@ import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
import 'package:fcs/pages/shipment/model/shipment_model.dart'; import 'package:fcs/pages/shipment/model/shipment_model.dart';
import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/fcs_icons.dart'; import 'package:fcs/pages/widgets/fcs_icons.dart';
import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_dropdown.dart'; import 'package:fcs/pages/widgets/local_dropdown.dart';
import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart';
import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_popupmenu.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/local_title.dart';
import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -36,8 +36,6 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'invoice_custom_table.dart';
class InvoiceEditor extends StatefulWidget { class InvoiceEditor extends StatefulWidget {
final Invoice invoice; final Invoice invoice;
final User customer; final User customer;
@@ -49,15 +47,13 @@ class InvoiceEditor extends StatefulWidget {
} }
class _InvoiceEditorState extends State<InvoiceEditor> { class _InvoiceEditorState extends State<InvoiceEditor> {
User _user;
var dateFormatter = new DateFormat('dd MMM yyyy'); var dateFormatter = new DateFormat('dd MMM yyyy');
Invoice _invoice; Invoice _invoice;
bool _isLoading = false; bool _isLoading = false;
bool _isNew; bool _isNew;
User _user;
List<bool> isSelected = [false];
bool _showCartons = false; bool _showCartons = false;
@override @override
void initState() { void initState() {
@@ -141,11 +137,14 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
var rateModel = Provider.of<ShipmentRateModel>(context); var rateModel = Provider.of<ShipmentRateModel>(context);
var rate = rateModel.rate; var rate = rateModel.rate;
final invoiceNumberBox = DisplayText(
labelTextKey: 'invoice.number',
iconData: FontAwesomeIcons.fileInvoice,
text: _invoice?.invoiceNumber ?? "");
final statusBox = DisplayText( final statusBox = DisplayText(
text: _invoice?.status ?? "", text: _invoice?.status ?? "",
iconData: Icons.av_timer, iconData: Icons.av_timer,
labelTextKey: 'invoice.status'); labelTextKey: 'invoice.status');
final cartonTable = InvoiceCartonTable( final cartonTable = InvoiceCartonTable(
cartons: _invoice.cartons, cartons: _invoice.cartons,
rate: rate, rate: rate,
@@ -155,21 +154,6 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
}); });
}, },
); );
final customTableHeaderBox = LocalTitle(
textKey: "invoice.custom_fee",
trailing: IconButton(
icon: Icon(Icons.add_circle, color: primaryColor),
onPressed: () async {
CustomDuty customDuty = await Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => CustomList(selected: true)));
_addCustom(customDuty);
}));
final customTableBox = InvoiceCustomTable(
customDuties: _invoice.customDuties,
onAdd: (c) => _addCustom(c),
onRemove: (c) => _removeCustom(c),
);
final paymentTypesBox = LocalDropdown<PaymentMethod>( final paymentTypesBox = LocalDropdown<PaymentMethod>(
callback: (v) { callback: (v) {
setState(() { setState(() {
@@ -238,7 +222,6 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
}, },
isSelected: [_showCartons], isSelected: [_showCartons],
); );
final popupMenu = LocalPopupMenuButton( final popupMenu = LocalPopupMenuButton(
buttonIcon: Icons.add_circle, buttonIcon: Icons.add_circle,
selectable: false, selectable: false,
@@ -271,12 +254,12 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
Shipment shipment = await Navigator.of(context).push( Shipment shipment = await Navigator.of(context).push(
CupertinoPageRoute( CupertinoPageRoute(
builder: (context) => builder: (context) =>
InvoiceShipmentTable(shipments: _invoice.shipments))); InvoiceHandlingFeeList(shipments: _invoice.shipments)));
_addShipment(shipment); _addShipment(shipment);
} else if (p.id == 3) { } else if (p.id == 3) {
Discount discount = Discount discount =
await Navigator.of(context).push(CupertinoPageRoute( await Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => InvoiceDiscountTable( builder: (context) => InvoiceDiscountList(
discounts: discounts, discounts: discounts,
))); )));
if (discount != null) { if (discount != null) {
@@ -292,25 +275,7 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
}, },
); );
return LocalProgress( final headerBox = Row(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(CupertinoIcons.back, color: primaryColor),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: Colors.white,
shadowColor: Colors.transparent,
title: LocalText(context, 'invoice.form.title',
color: primaryColor, fontSize: 20),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Column( Column(
@@ -336,13 +301,33 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
], ],
), ),
], ],
);
final createBtn = LocalButton(
textKey: "invoice.issue.btn",
callBack: _save,
);
return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
leading: new IconButton(
icon: new Icon(CupertinoIcons.back, color: primaryColor),
onPressed: () => Navigator.of(context).pop(),
), ),
_isNew backgroundColor: Colors.white,
? Container() shadowColor: Colors.transparent,
: DisplayText( title: LocalText(context, 'invoice.form.title',
labelTextKey: 'invoice.number', color: primaryColor, fontSize: 20),
iconData: FontAwesomeIcons.fileInvoice, ),
text: _invoice?.invoiceNumber ?? ""), body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
headerBox,
_isNew ? Container() : invoiceNumberBox,
_isNew ? Container() : statusBox, _isNew ? Container() : statusBox,
_showCartons ? cartonTable : Container(), _showCartons ? cartonTable : Container(),
_showCartons _showCartons
@@ -360,15 +345,7 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
height: 10, height: 10,
), ),
_isNew _isNew
? Container() ? createBtn
: LocalTitle(
textKey: "invoice.payment_attachment",
trailing: IconButton(
icon: Icon(Icons.add_circle, color: primaryColor),
onPressed: () async {})),
_isNew
? fcsButton(
context, getLocalString(context, 'invoice.btn_create'))
: mainModel.isCustomer() : mainModel.isCustomer()
? Container() ? Container()
: Container( : Container(
@@ -421,5 +398,54 @@ class _InvoiceEditorState extends State<InvoiceEditor> {
}); });
} }
_save() {} _save() async {
var rateModel = Provider.of<ShipmentRateModel>(context, listen: false);
double amount = _invoice.getNetAmount(rateModel.rate);
if (_invoice.paymentMethod == null) {
showMsgDialog(context, "Error", "Payment method required");
return;
}
List<CargoType> cargoTypes = _invoice.getCargoTypes(rateModel.rate);
if (cargoTypes == null || cargoTypes.length == 0) {
showMsgDialog(context, "Error", "Expected at least one cargo type");
return;
}
if ((amount ?? 0) <= 0) {
showMsgDialog(context, "Error", "Expected positive amount");
return;
}
setState(() {
_isLoading = true;
});
try {
InvoiceModel invoiceModel =
Provider.of<InvoiceModel>(context, listen: false);
Invoice invoice = Invoice();
invoice.cargoTypes = cargoTypes;
invoice.amount = amount;
invoice.handlingFee = _invoice.getHandlingFee();
invoice.cartons = _invoice.cartons.where((c) => c.isChecked).toList();
invoice.shipments =
_invoice.shipments.where((s) => s.isSelected).toList();
invoice.discount = _invoice.discount;
invoice.deliveryFee = _invoice.deliveryFee;
invoice.userID = widget.customer.id;
invoice.fcsShipmentID = widget.fcsShipment.id;
invoice.invoiceDate = _invoice.invoiceDate;
invoice.paymentMethod = _invoice.paymentMethod;
await invoiceModel.createInvoice(invoice);
Navigator.pop(context, true);
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
} }

View File

@@ -8,12 +8,12 @@ import 'package:flutter/material.dart';
typedef OnAdd(Shipment shipment); typedef OnAdd(Shipment shipment);
typedef OnRemove(Shipment shipment); typedef OnRemove(Shipment shipment);
class InvoiceShipmentTable extends StatelessWidget { class InvoiceHandlingFeeList extends StatelessWidget {
final List<Shipment> shipments; final List<Shipment> shipments;
final OnAdd onAdd; final OnAdd onAdd;
final OnRemove onRemove; final OnRemove onRemove;
const InvoiceShipmentTable( const InvoiceHandlingFeeList(
{Key key, this.shipments, this.onAdd, this.onRemove}) {Key key, this.shipments, this.onAdd, this.onRemove})
: super(key: key); : super(key: key);

View File

@@ -1,107 +0,0 @@
import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/my_data_table.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
typedef OnAdd(CustomDuty customDuty);
typedef OnRemove(CustomDuty customDuty);
class InvoiceCustomTable extends StatelessWidget {
final List<CustomDuty> customDuties;
final OnAdd onAdd;
final OnRemove onRemove;
const InvoiceCustomTable(
{Key key, this.customDuties, this.onAdd, this.onRemove})
: super(key: key);
@override
Widget build(BuildContext context) {
return MyDataTable(
headingRowHeight: 40,
columns: [
MyDataColumn(
label: LocalText(
context,
"rate.cutom.product_type",
color: Colors.grey,
),
),
MyDataColumn(
label: LocalText(
context,
"rate.custom.fee",
color: Colors.grey,
),
),
],
rows: getRows(context),
);
}
List<MyDataRow> getRows(BuildContext context) {
if (customDuties == null) {
return [];
}
double total = 0;
var rows = customDuties.map((c) {
total += c.fee;
return MyDataRow(
cells: [
MyDataCell(new Text(
c.productType == null ? "" : c.productType,
style: textStyle,
)),
MyDataCell(
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(c.fee == null ? "0" : c.fee.toString(), style: textStyle),
onRemove == null
? SizedBox(
width: 50,
)
: IconButton(
icon: Icon(
Icons.remove_circle,
color: primaryColor,
),
onPressed: () {
if (onRemove != null) onRemove(c);
})
],
),
),
],
);
}).toList();
var totalRow = MyDataRow(
onSelectChanged: (bool selected) {},
cells: [
MyDataCell(Align(
alignment: Alignment.centerRight,
child: LocalText(
context,
"invoice.total_custom_fee",
color: Colors.black87,
fontWeight: FontWeight.bold,
),
)),
MyDataCell(
Padding(
padding: const EdgeInsets.only(right: 48.0),
child: Align(
alignment: Alignment.centerRight,
child: Text(total.toString(),
style: TextStyle(fontWeight: FontWeight.bold))),
),
),
],
);
rows.add(totalRow);
return rows;
}
}

View File

@@ -2,7 +2,7 @@ import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/customer/model/customer_model.dart'; import 'package:fcs/pages/customer/model/customer_model.dart';
import 'package:fcs/pages/invoice/invoice_editor.dart'; import 'package:fcs/pages/invoice/editor/invoice_editor.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@@ -82,12 +82,15 @@ class _InvoiceCustomerListState extends State<InvoiceCustomerList> {
Widget _item(User customer) { Widget _item(User customer) {
return InkWell( return InkWell(
onTap: () { onTap: () async {
Navigator.of(context).push(CupertinoPageRoute( bool created = await Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => InvoiceEditor( builder: (context) => InvoiceEditor(
customer: customer, customer: customer,
fcsShipment: widget.fcsShipment, fcsShipment: widget.fcsShipment,
))); )));
if (created ?? false) {
_load();
}
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12), padding: const EdgeInsets.only(left: 12.0, right: 12),

View File

@@ -1,170 +1,60 @@
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/entities/discount.dart';
import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/payment_method.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/carton/model/carton_model.dart';
import 'package:fcs/pages/discount/discount_list.dart'; import 'package:fcs/pages/invoice/editor/invoice_carton_table.dart';
import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/invoice/invoice_table.dart';
import 'package:fcs/pages/invoice/invoice_editor.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart';
import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/invoice/widgets.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/payment_methods/model/payment_method_model.dart';
import 'package:fcs/pages/rates/custom_list.dart';
import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
import 'package:fcs/pages/user_search/user_serach.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/pages/widgets/discount_dropdown.dart';
import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/fcs_icons.dart';
import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_dropdown.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/local_title.dart';
import 'package:fcs/pages/widgets/multi_img_controller.dart';
import 'package:fcs/pages/widgets/multi_img_file.dart';
import 'package:fcs/pages/widgets/my_data_table.dart';
import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class InvoiceInfoPage extends StatefulWidget { class InvoiceInfo extends StatefulWidget {
final Invoice invoice; final Invoice invoice;
final User customer; InvoiceInfo({this.invoice});
InvoiceInfoPage({this.invoice, this.customer});
@override @override
_InvoiceInfoPageState createState() => _InvoiceInfoPageState(); _InvoiceInfoState createState() => _InvoiceInfoState();
} }
class _InvoiceInfoPageState extends State<InvoiceInfoPage> { class _InvoiceInfoState extends State<InvoiceInfo> {
User user;
var dateFormatter = new DateFormat('dd MMM yyyy'); var dateFormatter = new DateFormat('dd MMM yyyy');
TextEditingController _invoiceNumberController = new TextEditingController();
TextEditingController _dateController = new TextEditingController();
TextEditingController _nameController = new TextEditingController();
TextEditingController _phoneController = new TextEditingController();
TextEditingController _discountController = new TextEditingController();
TextEditingController _amountController = new TextEditingController();
TextEditingController _statusController = new TextEditingController();
TextEditingController _customFeeController = new TextEditingController();
MultiImgController multiImgController = MultiImgController();
TextEditingController _descriptionController = new TextEditingController();
TextEditingController _balanceController = new TextEditingController();
Invoice _invoice; Invoice _invoice;
bool _isLoading = false; bool _isLoading = false;
List<Carton> _boxes = [];
bool isSwitched = false;
int deliveryfee = 0;
double customFee = 0;
double total = 0;
Discount _discount;
bool isNew = false;
Discount selectedDiscount;
int selectedDiscountAmt;
PaymentMethod paymentMethod;
double volumetricRatio = 0;
List<Carton> selectedBoxes = [];
List<CustomDuty> customs = [];
List<CargoType> _cargoTypes = [
CargoType(id: "1", name: 'General Cargo', weight: 33, rate: 6),
CargoType(id: "2", name: 'Medicine', weight: 33, rate: 7),
CargoType(id: "3", name: 'Dangerous Cargo', weight: 33, rate: 8)
];
List<String> _receipts = [
"assets/buying_online_with_first_last_name.png",
];
bool _showCartons = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
volumetricRatio = Provider.of<ShipmentRateModel>(context, listen: false)
.rate
.volumetricRatio;
if (widget.invoice != null) {
_invoice = widget.invoice; _invoice = widget.invoice;
_invoiceNumberController.text = _invoice.invoiceNumber; _invoice.shipments?.forEach((s) {
_dateController.text = dateFormatter.format(_invoice.invoiceDate); s.isSelected = true;
_nameController.text = _invoice.userName;
_phoneController.text = _invoice.phoneNumber;
// _amountController.text = _invoice.getAmount.toString();
_amountController.text = _invoice.amount.toString();
_statusController.text = _invoice.status.toString();
_customFeeController.text = '0';
// multiImgController.setImageUrls = _receipts;
_descriptionController.text = 'For Electronics goods';
// _boxes = _invoice.packages;
} else {
_dateController.text = dateFormatter.format(DateTime.now());
_amountController.text = '0';
_customFeeController.text = '0';
_descriptionController.text = '';
_balanceController.text = '0';
setState(() {
isNew = true;
}); });
_loadCartons();
} }
_boxes = [ _loadCartons() async {
Carton( CartonModel cartonModel = Provider.of<CartonModel>(context, listen: false);
shipmentNumber: "A202", List<Carton> cartons = [];
receiverNumber: "3", for (var c in _invoice?.cartons ?? []) {
receiverName: "Ko Myo Min", var _carton = await cartonModel.getCarton(c.id);
boxNumber: "1", _carton.isChecked = true;
rate: 7, cartons.add(_carton);
packageType: "General", }
weight: 75, setState(() {
status: "Packed", _invoice.cartons = cartons;
receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', });
cargoDesc: "Clothes",
arrivedDate: DateTime(2020, 6, 1),
width: 10,
height: 10,
length: 10,
// packages: packages,
// statusHistory: statusHistory,
cargoTypes: [
CargoType(name: 'General Cargo', weight: 25),
CargoType(name: 'Medicine', weight: 20),
CargoType(name: 'Dangerous Cargo', weight: 30)
]),
Carton(
shipmentNumber: "A202",
receiverNumber: "3",
receiverName: "Ko Myo Min",
boxNumber: "2",
rate: 7,
packageType: "General",
weight: 75,
status: "Packed",
cargoDesc: "Clothes",
arrivedDate: DateTime(2020, 6, 1),
width: 10,
height: 10,
length: 10,
// statusHistory: statusHistory,
// packages: packages,
receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon',
cargoTypes: [
CargoType(name: 'General Cargo', weight: 25),
CargoType(name: 'Medicine', weight: 20),
CargoType(name: 'Dangerous Cargo', weight: 30)
])
];
} }
@override @override
@@ -174,21 +64,91 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final nameBox = DisplayText( bool isCanceled = _invoice.status == invoice_cancel_status;
iconData: Feather.user, var rateModel = Provider.of<ShipmentRateModel>(context);
labelTextKey: 'invoice.customer_name', var rate = rateModel.rate;
text: user != null ? user.name : 'Ko Nyi');
final fcsIDBox = DisplayText( final cartonTable = InvoiceCartonTable(
text: user != null ? user.fcsID : "FCS-KRUTUG", cartons: _invoice.cartons,
labelTextKey: "box.fcs.id", rate: rate,
icon: FcsIDIcon(),
); );
final statusBox = DisplayText( final invoiceTableBox = InvoiceTable(
text: _statusController.text, invoice: _invoice,
iconData: Icons.av_timer, rate: rate,
labelTextKey: 'invoice.status'); deliveryFeeSelected: (selected) {
setState(() {
if (selected) {
_invoice.deliveryFee = rate.deliveryFee;
} else {
_invoice.deliveryFee = 0;
}
});
},
discountSelected: (discount) {
setState(() {
_invoice.discount = discount;
});
},
);
final toggleButtonsBox = ToggleButtons(
color: Colors.black45,
selectedColor: Colors.black45,
disabledColor: Colors.grey,
selectedBorderColor: primaryColor,
borderColor: Colors.transparent,
fillColor: Colors.transparent,
highlightColor: Colors.black45,
children: <Widget>[
Icon(cartonIconData),
],
onPressed: (int index) {
setState(() {
_showCartons = !_showCartons;
});
},
isSelected: [_showCartons],
);
final headerBox = Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(dateFormatter.format(_invoice.invoiceDate)),
SizedBox(
height: 5,
),
Text(_invoice?.userName ?? ""),
Text(
_invoice?.fcsID ?? "",
style: TextStyle(fontSize: 12),
)
],
),
Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
toggleButtonsBox,
],
),
],
);
final paymentMethodBox = DisplayText(
labelTextKey: "invoice.payment_method",
text: _invoice.paymentMethod.name,
);
final receiptsBtn = LocalButton(
textKey: "invoice.btn_payment_receipt",
callBack: _cancel,
);
final cancelBtn = LocalButton(
textKey: "invoice.cancel.btn",
callBack: _cancel,
);
return LocalProgress( return LocalProgress(
inAsyncCall: _isLoading, inAsyncCall: _isLoading,
@@ -203,600 +163,58 @@ class _InvoiceInfoPageState extends State<InvoiceInfoPage> {
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
title: LocalText(context, 'invoice.form.title', title: LocalText(context, 'invoice.form.title',
color: primaryColor, fontSize: 20), color: primaryColor, fontSize: 20),
actions: [
new IconButton(
icon: Icon(
Icons.delete,
color: primaryColor,
),
onPressed: () {}),
new IconButton(
icon: Icon(
Icons.edit,
color: primaryColor,
),
onPressed: () {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => InvoiceEditor(invoice: _invoice)));
})
],
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ListView( child: ListView(
children: <Widget>[ children: <Widget>[
LocalTitle(textKey: "invoice.customer_info"), getInvoiceStatus(context, _invoice),
DisplayText( headerBox,
labelTextKey: 'invoice.date', _showCartons ? cartonTable : Container(),
iconData: Icons.date_range, _showCartons
text: _dateController.text), ? Divider(
widget.invoice == null color: primaryColor,
? Container() thickness: 2,
: DisplayText(
labelTextKey: 'invoice.number',
iconData: FontAwesomeIcons.fileInvoice,
text: _invoiceNumberController.text),
fcsIDBox,
nameBox,
statusBox,
LocalTitle(textKey: "invoice.box_info"),
Center(child: Column(children: getCartonRows(context))),
SizedBox(height: 20),
LocalTitle(textKey: "invoice.custom_fee"),
Column(children: getCustomFeeRows(context)),
SizedBox(height: 20),
LocalTitle(textKey: "invoice.cargo_type"),
Column(children: getCargoTableByBox(context)),
SizedBox(height: 20),
Container(
padding: EdgeInsets.only(top: 5, left: 18),
child: Row(
children: <Widget>[
Expanded(
child: LocalText(context, 'invoice.payment_method',
fontSize: 16,
color: Colors.grey,
fontWeight: FontWeight.bold),
),
Text(
'${paymentMethod != null ? paymentMethod.accountName : "KBZ Bank"}',
style: TextStyle(fontSize: 16)),
],
),
),
SizedBox(height: 30),
!isNew
? LocalTitle(textKey: "invoice.payment_attachment")
: Container(),
],
),
),
),
);
}
getCartonRows(BuildContext context) {
List<Widget> dataRow = [];
dataRow = _boxes.map((box) {
return Container(
height: 50,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
padding:
const EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0, bottom: 5.0),
child: Row(
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(box.packageNumber),
Text(box.shipmentNumber),
],
)),
Expanded(
flex: 2,
child: Text(
box.length == null
? ""
: box.length.toString() +
' x ' +
box.length.toString() +
' x ' +
box.height.toString(),
textAlign: TextAlign.center)),
Expanded(
flex: 2,
child: Center(
child: Text(
box.getShipmentWeight(volumetricRatio).toString()))),
],
),
);
}).toList();
dataRow.insert(
0,
Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 5.0, bottom: 15.0),
child: Row(
children: [
Expanded(
flex: 1,
child: Center(
child: LocalText(
context,
"invoice.box.number",
color: Colors.grey,
),
)),
Expanded(
flex: 2,
child: Center(
child: Text('L x W x H',
style: TextStyle(color: Colors.grey)))),
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
"invoice.shipment_weight",
color: Colors.grey,
),
)),
],
),
));
return dataRow;
}
getCustomFeeRows(BuildContext context) {
customFee = 0;
List<Widget> dataRow = [];
dataRow = customs.map((custom) {
customFee += custom.fee;
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
padding:
const EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0, bottom: 5.0),
child: Row(
children: [
Expanded(flex: 2, child: Text('${custom.productType}')),
Expanded(
flex: 1,
child: Text('\$ ${custom.fee}', textAlign: TextAlign.center)),
Expanded(child: SizedBox(height: 40))
],
),
);
}).toList();
dataRow.insert(
0,
Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 15.0, bottom: 15.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Text('Product', style: TextStyle(color: Colors.grey))),
Expanded(
flex: 1,
child: Text('Fee',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey))),
Expanded(flex: 1, child: Container())
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 15.0, bottom: 15.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.total_custom_fee',
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
flex: 1,
child: Center(
child: Text('\$ $customFee',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold)))),
Expanded(
child: Container(),
) )
: Container(),
invoiceTableBox,
SizedBox(
height: 10,
),
paymentMethodBox,
SizedBox(
height: 10,
),
isCanceled ? Container() : receiptsBtn,
isCanceled ? Container() : cancelBtn,
], ],
), ),
)); ),
return dataRow;
}
getCargoTableByBox(BuildContext context) {
total = 0;
List<Widget> dataRow = _cargoTypes.map((cargo) {
var amount = cargo.weight * cargo.rate;
total += amount;
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 15.0, bottom: 15.0),
child: Row(
children: [
Expanded(flex: 2, child: Text('${cargo.rate}')),
Expanded(
flex: 2,
child: Text('${cargo.weight} x ${cargo.rate}',
textAlign: TextAlign.center)),
Expanded(
child: Text('\$ $amount',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
)))
],
), ),
); );
}).toList();
dataRow.insert(
0,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 15.0, bottom: 15.0),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.grey))),
child: Row(
children: [
Expanded(
flex: 2,
child: Text(getLocalString(context, 'invoice.box.cargo_type'),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.grey))),
Expanded(
flex: 2,
child: Text(
getLocalString(context, 'cargo.weight') +
' x ' +
getLocalString(context, 'cargo.rate'),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.grey))),
Expanded(
child: Text(getLocalString(context, 'invoice.amount'),
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.grey)))
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 10.0, bottom: 10.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.total',
color: Colors.black,
),
),
),
Expanded(
child: Text(
'\$ $total',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.end,
))
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.discount_value',
color: Colors.black,
),
),
),
Expanded(
child: Text(
'\$ ${_discount != null ? _discount.amount.toInt() : 0}',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
)))
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 10.0, bottom: 0.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.custom_fee',
color: Colors.black,
),
)),
Expanded(
child: Text('\$ $customFee',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
)),
),
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 20.0, bottom: 5.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.handling_fee',
color: Colors.black,
),
)),
Expanded(
child: Text('\$ 10.0',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
)),
),
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 10.0, bottom: 10.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.delivery_fee',
color: Colors.black,
),
),
),
Expanded(
child: Text('\$ $deliveryfee',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
)))
],
),
));
dataRow.insert(
dataRow.length,
Container(
child: Row(
children: [
Expanded(child: Text('')),
Expanded(
flex: 2,
child: Divider(
thickness: 3,
)),
],
)));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 10.0, bottom: 10.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.net_amount',
color: Colors.black,
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Text('\$ ${getTotalBalance(total)}',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: primaryColor)))
],
),
));
dataRow.insert(
dataRow.length,
Container(
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 10.0, bottom: 10.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Center(
child: LocalText(
context,
'invoice.balance',
color: Colors.black,
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Text('\$ ${getTotalBalance(total)}',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: primaryColor)))
],
),
));
return dataRow;
} }
getTotalBalance(total) { _cancel() {
double balance = 0; showConfirmDialog(context, "invoice.cancel.confirm", _cancelInvoice);
double custom = customFee != 0 ? customFee.toDouble() : 0;
double deliveryFee = deliveryfee != 0 ? deliveryfee.toDouble() : 0;
double discount = _discount != null ? _discount.amount.toDouble() : 0;
balance = (total + custom + deliveryFee) - discount;
return balance;
} }
List<MyDataRow> getBoxRow(BuildContext context) { _cancelInvoice() async {
return _boxes.map((p) {
p.cargoTypes.map((cargo) {
_cargoTypes.asMap().map((index, _cargo) {
if (_cargo.id == cargo.id) {
setState(() { setState(() {
_cargoTypes[index].weight += cargo.weight; _isLoading = true;
}); });
}
});
});
return MyDataRow(
onSelectChanged: (bool selected) {},
cells: [
MyDataCell(Checkbox(
value: true,
onChanged: (value) {
selectedBoxes.add(p);
},
)),
MyDataCell(new Text(
p.boxNumber == null
? ""
: '${p.shipmentNumber}-${p.receiverNumber} #${p.boxNumber}',
style: textStyle,
)),
MyDataCell(new Text(
p.length == null
? ""
: p.length.toString() +
' x ' +
p.length.toString() +
' x ' +
p.height.toString(),
style: textStyle,
)),
],
);
}).toList();
}
List<MyDataRow> getCargoDataRow(BuildContext context) { try {
return _cargoTypes.asMap().entries.map((c) { InvoiceModel invoiceModel =
var cargo = c.value; Provider.of<InvoiceModel>(context, listen: false);
var amt = cargo.weight * cargo.rate;
return MyDataRow( await invoiceModel.cancelInvoice(_invoice);
onSelectChanged: (bool selected) {}, Navigator.pop(context, true);
cells: [ } catch (e) {
MyDataCell(new Text( showMsgDialog(context, "Error", e.toString());
cargo.name, } finally {
style: textStyle, setState(() {
)), _isLoading = false;
MyDataCell(new Text( });
cargo.weight.toString() + ' x ' + cargo.rate.toString(), }
style: textStyle,
)),
MyDataCell(new Text(
"\$$amt",
style: textStyle,
)),
],
);
}).toList()
// .insert(_cargoTypes.length,MyDataRow(cells: [
// MyDataCell(new Text('')),
// MyDataCell(new Text('Total')),
// MyDataCell(new Text(
// "\$5000",
// style: textStyle,
// )),
// ])
// )
;
} }
} }

View File

@@ -1,6 +1,11 @@
import 'dart:io';
import 'package:fcs/helpers/api_helper.dart';
import 'package:fcs/helpers/firebase_helper.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/invoice/invoice_shipment_list.dart'; import 'package:fcs/pages/invoice/invoice_shipment_list.dart';
import 'package:fcs/pages/invoice/model/invoice_model.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart';
import 'package:fcs/pages/invoice/payment_pdf_screen.dart';
import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart';
import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_popupmenu.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
@@ -21,7 +26,6 @@ class InvoiceList extends StatefulWidget {
class _InvoiceListState extends State<InvoiceList> { class _InvoiceListState extends State<InvoiceList> {
bool _isLoading = false; bool _isLoading = false;
bool _showPaid = false;
var _controller = ScrollController(); var _controller = ScrollController();
@override @override
@@ -34,7 +38,8 @@ class _InvoiceListState extends State<InvoiceList> {
} }
}); });
Provider.of<InvoiceModel>(context, listen: false).initData(false); Provider.of<InvoiceModel>(context, listen: false)
.initData(widget.forCustomer, true, false);
} }
@override @override
@@ -51,15 +56,29 @@ class _InvoiceListState extends State<InvoiceList> {
popmenus: [ popmenus: [
LocalPopupMenu( LocalPopupMenu(
id: 1, id: 1,
textKey: "invoice.popupmenu.pending", textKey: "invoice.popupmenu.issused",
selected: invoiceModel.selectedIndex == 1), selected: invoiceModel.selectedIndex == 1),
LocalPopupMenu( LocalPopupMenu(
id: 2, id: 2,
textKey: "invoice.popupmenu.paid", textKey: "invoice.popupmenu.paid",
selected: invoiceModel.selectedIndex == 2) selected: invoiceModel.selectedIndex == 2),
LocalPopupMenu(
id: 3,
textKey: "invoice.popupmenu.cancel",
selected: invoiceModel.selectedIndex == 3)
], ],
popupMenuCallback: (p) => this.setState(() { popupMenuCallback: (p) => this.setState(() {
_showPaid = p.id == 2; invoiceModel.selectedIndex = p.id;
if (p.id == 2) {
Provider.of<InvoiceModel>(context, listen: false)
.initData(widget.forCustomer, false, true);
} else if (p.id == 3) {
Provider.of<InvoiceModel>(context, listen: false)
.initData(widget.forCustomer, true, false);
} else {
Provider.of<InvoiceModel>(context, listen: false)
.initData(widget.forCustomer, true, false);
}
}), }),
); );
@@ -131,7 +150,7 @@ class _InvoiceListState extends State<InvoiceList> {
); );
} }
_newInvoice() { _newInvoice() async {
Navigator.of(context) Navigator.of(context)
.push(CupertinoPageRoute(builder: (context) => InvoiceShipmentList())); .push(CupertinoPageRoute(builder: (context) => InvoiceShipmentList()));
} }

View File

@@ -1,10 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/invoice/invoice_info.dart'; import 'package:fcs/pages/invoice/invoice_info.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -12,7 +12,6 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'invoice_editor.dart';
import 'payment_page.dart'; import 'payment_page.dart';
import 'payment_pdf_screen.dart'; import 'payment_pdf_screen.dart';
@@ -81,11 +80,11 @@ class _InvoiceListRowState extends State<InvoiceListRow> {
owner owner
? Navigator.of(context).push(CupertinoPageRoute( ? Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => PaymentPDFScreen( builder: (context) => PaymentPDFScreen(
path: pdfPath, url: _invoice.invoiceURL,
))) )))
: Navigator.of(context).push(CupertinoPageRoute( : Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => PaymentPDFScreen( builder: (context) => PaymentPDFScreen(
path: pdfPath, url: _invoice.invoiceURL,
))); )));
}, },
child: new Row( child: new Row(
@@ -132,7 +131,7 @@ class _InvoiceListRowState extends State<InvoiceListRow> {
// padding: const EdgeInsets.all(0), // padding: const EdgeInsets.all(0),
// child: getStatus(_invoice.status), // child: getStatus(_invoice.status),
// ), // ),
_invoice.status == "Pending" _invoice.status == invoice_issued_status
? Padding( ? Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: InkWell( child: InkWell(
@@ -191,10 +190,11 @@ class _InvoiceListRowState extends State<InvoiceListRow> {
), ),
], ],
), ),
onPressed: () { onPressed: () async {
//to go invoice info page //to go invoice info page
Navigator.pop(context);
Navigator.of(context).push(CupertinoPageRoute( Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => InvoiceInfoPage(invoice: _invoice))); builder: (context) => InvoiceInfo(invoice: _invoice)));
}, },
) )
], ],

View File

@@ -1,13 +1,13 @@
import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart';
import 'package:fcs/pages/shipment/model/shipment_model.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'invoice_customer_list.dart';
import 'invoice_shipment_list_row.dart'; import 'invoice_shipment_list_row.dart';
class InvoiceShipmentList extends StatefulWidget { class InvoiceShipmentList extends StatefulWidget {
@@ -65,7 +65,14 @@ class _InvoiceShipmentListState extends State<InvoiceShipmentList> {
itemCount: _fcsShipments.length, itemCount: _fcsShipments.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return InvoiceShipmentListRow( return InvoiceShipmentListRow(
fcsShipment: _fcsShipments[index]); fcsShipment: _fcsShipments[index],
onSelect: (f) {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => InvoiceCustomerList(
fcsShipment: f,
)));
},
);
}), }),
), ),
), ),

View File

@@ -8,9 +8,12 @@ import 'package:intl/intl.dart';
import '../main/util.dart'; import '../main/util.dart';
import 'invoice_customer_list.dart'; import 'invoice_customer_list.dart';
typedef OnSelect(FcsShipment fcsShipment);
class InvoiceShipmentListRow extends StatefulWidget { class InvoiceShipmentListRow extends StatefulWidget {
final OnSelect onSelect;
final FcsShipment fcsShipment; final FcsShipment fcsShipment;
const InvoiceShipmentListRow({this.fcsShipment}); const InvoiceShipmentListRow({this.fcsShipment, this.onSelect});
@override @override
_InvoiceShipmentListRowState createState() => _InvoiceShipmentListRowState(); _InvoiceShipmentListRowState createState() => _InvoiceShipmentListRowState();
@@ -35,10 +38,7 @@ class _InvoiceShipmentListRowState extends State<InvoiceShipmentListRow> {
padding: EdgeInsets.only(left: 15, right: 15), padding: EdgeInsets.only(left: 15, right: 15),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navigator.of(context).push(CupertinoPageRoute( if (widget.onSelect != null) widget.onSelect(widget.fcsShipment);
builder: (context) => InvoiceCustomerList(
fcsShipment: _fcsShipment,
)));
}, },
child: Row( child: Row(
children: <Widget>[ children: <Widget>[

View File

@@ -63,14 +63,14 @@ class InvoiceTable extends StatelessWidget {
List<InvoiceTableRow> getTableRows() { List<InvoiceTableRow> getTableRows() {
List<InvoiceTableRow> tableRows = []; List<InvoiceTableRow> tableRows = [];
// add cargo types // add cargo types
List<CargoType> _cargoTypes = invoice.getCargoTypes(rate); List<CargoType> _cargoTypes = invoice.getCargoTypes(rate) ?? [];
_cargoTypes.forEach((c) { _cargoTypes.forEach((c) {
tableRows.add(InvoiceTableRow( tableRows.add(InvoiceTableRow(
invoiceDataType: InvoiceDataType.CargoDataType, invoiceDataType: InvoiceDataType.CargoDataType,
desc: c.name, desc: c.name,
rate: rate:
"${c.calWeight.toStringAsFixed(2)} x ${c.calRate.toStringAsFixed(2)}", "${c.calWeight.toStringAsFixed(2)} x ${c.calRate.toStringAsFixed(2)}",
amount: "${c.amount.toStringAsFixed(2)}")); amount: "${c.calAmount.toStringAsFixed(2)}"));
}); });
invoice.shipments.where((ss) => (ss.isSelected ?? false)).forEach((s) { invoice.shipments.where((ss) => (ss.isSelected ?? false)).forEach((s) {
tableRows.add(InvoiceTableRow( tableRows.add(InvoiceTableRow(
@@ -80,7 +80,7 @@ class InvoiceTable extends StatelessWidget {
rate: "", rate: "",
amount: "${s.handlingFee.toStringAsFixed(2)}")); amount: "${s.handlingFee.toStringAsFixed(2)}"));
}); });
// add custom fee // // add custom fee
invoice.customDuties.forEach((c) { invoice.customDuties.forEach((c) {
tableRows.add(InvoiceTableRow( tableRows.add(InvoiceTableRow(
data: c, data: c,
@@ -89,7 +89,7 @@ class InvoiceTable extends StatelessWidget {
rate: "", rate: "",
amount: "${c.fee.toStringAsFixed(2)}")); amount: "${c.fee.toStringAsFixed(2)}"));
}); });
// add delivery fee // // add delivery fee
tableRows.add(InvoiceTableRow( tableRows.add(InvoiceTableRow(
data: invoice.deliveryFee == null || invoice.deliveryFee == 0 data: invoice.deliveryFee == null || invoice.deliveryFee == 0
? null ? null
@@ -99,7 +99,7 @@ class InvoiceTable extends StatelessWidget {
rate: "", rate: "",
amount: "${invoice?.deliveryFee?.toStringAsFixed(2) ?? '0'}")); amount: "${invoice?.deliveryFee?.toStringAsFixed(2) ?? '0'}"));
// add discounts // // add discounts
if (invoice.discount != null) { if (invoice.discount != null) {
tableRows.add(InvoiceTableRow( tableRows.add(InvoiceTableRow(
data: invoice.discount, data: invoice.discount,

View File

@@ -1,33 +1,30 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/config.dart';
import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/invoice.dart'; import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/receipt.dart'; import 'package:fcs/helpers/api_helper.dart';
import 'package:fcs/helpers/firebase_helper.dart';
import 'package:fcs/helpers/paginator.dart'; import 'package:fcs/helpers/paginator.dart';
import 'package:fcs/pages/main/model/base_model.dart'; import 'package:fcs/pages/main/model/base_model.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart';
class InvoiceModel extends BaseModel { class InvoiceModel extends BaseModel {
final log = Logger('InvoiceModel'); final log = Logger('InvoiceModel');
StreamSubscription<QuerySnapshot> listener; StreamSubscription<QuerySnapshot> listener;
List<Invoice> _invoices = [ List<Invoice> _invoices = [];
Invoice(
invoiceNumber: 'A092(A)-33',
invoiceDate: DateTime(2020, 4, 6, 12, 15),
userName: 'Ko Myo Min',
phoneNumber: '+959 555555555',
amount: 300,
status: 'Pending',
)
];
List<Invoice> get invoices => List<Invoice> get invoices =>
_selectedIndex == 1 ? _invoices : List<Invoice>.from(_paid.values); _selectedIndex == 1 ? _invoices : List<Invoice>.from(_paginator.values);
Paginator _paid; Paginator _paginator;
bool endOfPaidInvoices = false; bool endOfPaidInvoices = false;
bool isLoading = false; bool isLoading = false;
@@ -45,15 +42,17 @@ class InvoiceModel extends BaseModel {
super.privilegeChanged(); super.privilegeChanged();
} }
initData(bool forCustomer) { initData(bool forCustomer, bool isCanceled, bool isPaid) {
_selectedIndex = 1; _loadInvoices(forCustomer);
// _loadFcsInvoices(forCustomer);
if (_paid != null) _paid.close(); if (_paginator != null) _paginator.close();
_paid = _getPaid(forCustomer); _paginator = _getPaginator(forCustomer, isCanceled, isPaid);
_paginator.load(onFinished: () {
notifyListeners();
});
} }
Future<void> _loadFcsInvoices(bool forCustomer) async { Future<void> _loadInvoices(bool forCustomer) async {
if (user == null) return; if (user == null) return;
if (!forCustomer && !user.hasInvoices()) return; if (!forCustomer && !user.hasInvoices()) return;
String path = "/$invoices_collection"; String path = "/$invoices_collection";
@@ -63,7 +62,7 @@ class InvoiceModel extends BaseModel {
try { try {
var q = Firestore.instance var q = Firestore.instance
.collection("$path") .collection("$path")
.where("is_paid", isEqualTo: false) .where("status", isEqualTo: invoice_issued_status)
.where("is_deleted", isEqualTo: false); .where("is_deleted", isEqualTo: false);
if (forCustomer) { if (forCustomer) {
@@ -84,18 +83,24 @@ class InvoiceModel extends BaseModel {
} }
} }
Paginator _getPaid(bool isCustomer) { Paginator _getPaginator(bool isCustomer, bool isCanceled, bool isPaid) {
if (!isCustomer) { if (!isCustomer) {
if (user == null || !(user.hasInvoices())) throw "No privilege"; if (user == null || !(user.hasInvoices())) throw "No privilege";
} }
var pageQuery = Firestore.instance var pageQuery = Firestore.instance
.collection("/$packages_collection") .collection("/$invoices_collection")
.where("is_delivered", isEqualTo: true)
.where("is_deleted", isEqualTo: false); .where("is_deleted", isEqualTo: false);
if (isCustomer) { if (isCustomer) {
pageQuery = pageQuery.where("user_id", isEqualTo: user.id); pageQuery = pageQuery.where("user_id", isEqualTo: user.id);
} }
pageQuery = pageQuery.orderBy("status_date", descending: true); if (isCanceled) {
pageQuery = pageQuery.where("status", isEqualTo: invoice_cancel_status);
}
if (isPaid) {
pageQuery = pageQuery.where("status", isEqualTo: invoice_paid_status);
}
pageQuery = pageQuery.orderBy("created_at", descending: true);
var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) {
return Invoice.fromMap(data, id); return Invoice.fromMap(data, id);
}); });
@@ -103,11 +108,11 @@ class InvoiceModel extends BaseModel {
} }
Future<void> loadMore({bool isCustomer}) async { Future<void> loadMore({bool isCustomer}) async {
if (_paid.ended || _selectedIndex == 1) if (_paginator.ended || _selectedIndex == 1)
return; // when paid menu is not selected return return; // when paid menu is not selected return
isLoading = true; isLoading = true;
notifyListeners(); notifyListeners();
await _paid.load(onFinished: () { await _paginator.load(onFinished: () {
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
}); });
@@ -115,7 +120,7 @@ class InvoiceModel extends BaseModel {
Future<void> refresh({bool isCustomer}) async { Future<void> refresh({bool isCustomer}) async {
if (_selectedIndex == 1) return; // when paid menu is not selected return if (_selectedIndex == 1) return; // when paid menu is not selected return
await _paid.refresh(onFinished: () { await _paginator.refresh(onFinished: () {
notifyListeners(); notifyListeners();
}); });
} }
@@ -125,16 +130,24 @@ class InvoiceModel extends BaseModel {
} }
logout() async { logout() async {
if (_paid != null) _paid.close(); if (_paginator != null) _paginator.close();
if (listener != null) await listener.cancel(); if (listener != null) await listener.cancel();
_invoices = []; _invoices = [];
} }
Future<void> createInvoice(Invoice invoice) { Future<void> createInvoice(Invoice invoice) async {
// return Services.instance.invoiceService.createInvoice(invoice); File file = await downloadPDF("invoice", invoice.toMap());
String url = await uploadStorage("pdfs", file);
print("uploaded url: $url");
invoice.invoiceURL = url;
return Services.instance.invoiceService.createInvoice(invoice);
} }
Future<void> updateInvoice(Invoice invoice) { Future<void> updateInvoice(Invoice invoice) {
// return Services.instance.invoiceService.updateInvoice(invoice); return Services.instance.invoiceService.updateInvoice(invoice);
}
Future<void> cancelInvoice(Invoice invoice) {
return Services.instance.invoiceService.cancelInvoice(invoice);
} }
} }

View File

@@ -1,23 +1,20 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:fcs/helpers/cache_mgr.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:share/share.dart'; import 'package:share/share.dart';
class PaymentPDFScreen extends StatefulWidget { class PaymentPDFScreen extends StatefulWidget {
final String path; final String url;
PaymentPDFScreen({Key key, this.path}) : super(key: key); PaymentPDFScreen({Key key, this.url}) : super(key: key);
_PaymentPDFScreenState createState() => _PaymentPDFScreenState(); _PaymentPDFScreenState createState() => _PaymentPDFScreenState();
} }
@@ -30,38 +27,60 @@ class _PaymentPDFScreenState extends State<PaymentPDFScreen>
int currentPage = 0; int currentPage = 0;
bool isReady = false; bool isReady = false;
String errorMessage = ''; String errorMessage = '';
bool _isLoading = true;
void initState() {
super.initState();
download();
}
File file;
Future<void> download() async {
try {
File f = await PdfCacheMgr.pdfs.getSingleFile(widget.url);
setState(() {
file = f;
});
} catch (e) {
showMsgDialog(context, "Error", e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return LocalProgress(
inAsyncCall: _isLoading,
child: Scaffold(
appBar: AppBar( appBar: AppBar(
centerTitle: true, centerTitle: true,
backgroundColor: primaryColor, backgroundColor: Colors.white,
shadowColor: Colors.transparent,
title: LocalText(context, 'invoice.pdf', title: LocalText(context, 'invoice.pdf',
color: Colors.white, fontSize: 20), color: Colors.white, fontSize: 20),
leading: new IconButton( leading: new IconButton(
icon: new Icon(CupertinoIcons.back), icon: new Icon(CupertinoIcons.back, color: primaryColor),
onPressed: () { onPressed: () => Navigator.of(context).pop(),
Navigator.of(context).pop(); ),
}),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.file_download), icon: Icon(
onPressed: () async { Icons.share,
var file = await copyAsset(); color: primaryColor,
print('file=> $file');
},
), ),
IconButton( onPressed: _share,
icon: Icon(Icons.share),
onPressed: () => _share(widget.path),
), ),
], ],
), ),
body: Stack( body: Stack(
children: <Widget>[ children: <Widget>[
PDFView( _isLoading
filePath: widget.path, ? Container()
: PDFView(
filePath: file?.path ?? "",
enableSwipe: true, enableSwipe: true,
swipeHorizontal: true, swipeHorizontal: true,
autoSpacing: false, autoSpacing: false,
@@ -93,25 +112,15 @@ class _PaymentPDFScreenState extends State<PaymentPDFScreen>
), ),
], ],
), ),
),
); );
} }
_share(String url) async { _share() async {
MainModel mainModel = Provider.of<MainModel>(context, listen: false);
String appUrl = mainModel.setting.appUrl;
final RenderBox box = context.findRenderObject(); final RenderBox box = context.findRenderObject();
await Share.share( await Share.shareFiles([file.path],
"Join us on FCS Logistics App. Here is the link:\n $appUrl\n" + url, mimeTypes: ["application/pdf"],
subject: "Invitation to FCS Logistics App", subject: "Invoice",
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size); sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);
} }
Future<File> copyAsset() async {
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
File tempFile = File('$tempPath/Invoice-A092(A)-32.pdf');
ByteData bd = await rootBundle.load('assets/Invoice-A092(A)-32.pdf');
await tempFile.writeAsBytes(bd.buffer.asUint8List(), flush: true);
return tempFile;
}
} }

View File

@@ -0,0 +1,24 @@
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/material.dart';
Widget getInvoiceStatus(BuildContext context, Invoice invoice) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LocalText(
context,
'',
text: invoice.invoiceNumber ?? "",
color: primaryColor,
fontSize: 18,
fontWeight: FontWeight.bold,
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Chip(label: Text(invoice.status ?? "")),
),
],
);
}

View File

@@ -16,7 +16,7 @@ import 'package:fcs/pages/delivery/delivery_list.dart';
import 'package:fcs/pages/discount/discount_list.dart'; import 'package:fcs/pages/discount/discount_list.dart';
import 'package:fcs/pages/faq/faq_list_page.dart'; import 'package:fcs/pages/faq/faq_list_page.dart';
import 'package:fcs/pages/fcs_shipment/fcs_shipment_list.dart'; import 'package:fcs/pages/fcs_shipment/fcs_shipment_list.dart';
import 'package:fcs/pages/invoice/invoce_list.dart'; import 'package:fcs/pages/invoice/invoice_list.dart';
import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/main/util.dart';
@@ -298,11 +298,11 @@ class _HomePageState extends State<HomePage> {
final invoicesBtn = TaskButton("invoices.btn", final invoicesBtn = TaskButton("invoices.btn",
icon: FontAwesomeIcons.fileInvoice, icon: FontAwesomeIcons.fileInvoice,
btnCallback: () => Navigator.of(context).push<void>(CupertinoPageRoute( btnCallback: () => Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => InvoiceList(forCustomer: false)))); builder: (context) => InvoiceList(forCustomer: true))));
final invoicesBtnFcs = TaskButton("invoices.btn", final invoicesBtnFcs = TaskButton("invoices.btn",
icon: FontAwesomeIcons.fileInvoice, icon: FontAwesomeIcons.fileInvoice,
btnCallback: () => Navigator.of(context).push<void>(CupertinoPageRoute( btnCallback: () => Navigator.of(context).push<void>(CupertinoPageRoute(
builder: (context) => InvoiceList(forCustomer: true)))); builder: (context) => InvoiceList(forCustomer: false))));
final discountBtn = TaskButton("discount.btn", final discountBtn = TaskButton("discount.btn",
icon: Entypo.price_ribbon, icon: Entypo.price_ribbon,

View File

@@ -68,9 +68,9 @@ class _ShipmentListState extends State<ShipmentList> {
if (p.id == 3) { if (p.id == 3) {
Provider.of<ShipmentModel>(context, listen: false) Provider.of<ShipmentModel>(context, listen: false)
.initData(widget.forCustomer, myPickup: true); .initData(widget.forCustomer, myPickup: true);
} else if (p.id == 1) { } else {
Provider.of<ShipmentModel>(context, listen: false) Provider.of<ShipmentModel>(context, listen: false)
.initData(widget.forCustomer); .initData(widget.forCustomer, myPickup: false);
} }
}), }),
); );

View File

@@ -28,7 +28,7 @@ packages:
name: cached_network_image name: cached_network_image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.2+1" version: "2.3.3"
camera: camera:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -176,6 +176,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
@@ -246,13 +253,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.6" version: "3.1.6"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.11"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@@ -266,12 +266,12 @@ packages:
source: hosted source: hosted
version: "0.5.0" version: "0.5.0"
flutter_cache_manager: flutter_cache_manager:
dependency: transitive dependency: "direct main"
description: description:
name: flutter_cache_manager name: flutter_cache_manager
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.2" version: "2.0.0"
flutter_datetime_picker: flutter_datetime_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -454,7 +454,7 @@ packages:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.14" version: "1.6.22"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -476,6 +476,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+1"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@@ -546,13 +553,6 @@ packages:
relative: true relative: true
source: path source: path
version: "0.0.1" version: "0.0.1"
protobuf:
dependency: transitive
description:
name: protobuf
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
provider: provider:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -768,6 +768,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.8" version: "2.0.8"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@@ -56,6 +56,7 @@ dependencies:
flutter_local_notifications: ^1.4.4+4 flutter_local_notifications: ^1.4.4+4
share: ^0.6.5 share: ^0.6.5
cached_network_image: ^2.3.2+1 cached_network_image: ^2.3.2+1
flutter_cache_manager: ^2.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: