update carton and cargo type

This commit is contained in:
tzw
2025-03-12 17:49:27 +06:30
parent 05e912ea68
commit e208734dfa
32 changed files with 1141 additions and 462 deletions

View File

@@ -1,3 +1,5 @@
// ignore_for_file: use_build_context_synchronously
import 'package:fcs/constants.dart';
import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/carton.dart';
@@ -24,12 +26,14 @@ import '../fcs_shipment/model/fcs_shipment_model.dart';
import '../widgets/local_button.dart';
import 'carton_package_editor.dart';
import 'mix_carton/mix_carton_editor.dart';
import 'mix_carton_detail_list.dart';
import 'model/carton_model.dart';
import 'package_detail_list.dart';
import 'print_qr_code_page.dart';
class CartonInfo extends StatefulWidget {
final Carton carton;
CartonInfo({required this.carton});
const CartonInfo({super.key, required this.carton});
@override
_CartonInfoState createState() => _CartonInfoState();
@@ -176,14 +180,28 @@ class _CartonInfoState extends State<CartonInfo> {
showLabelLink: true,
subText: Text(numberFormatter.format(_packages.length)),
labelTextKey: "box.package",
onTapLabel: () {},
onTapLabel: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => PackageDetailList(
cartonNumber: _carton.cartonNumber ?? '',
packages: _packages)));
},
);
final mixCartonLengthBox = DisplayText(
showLabelLink: true,
subText: Text(numberFormatter.format(_mixCartons.length)),
labelTextKey: "box.shipment.boxes",
onTapLabel: () {},
onTapLabel: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => MixCartonDetailList(
cartonNumber: _carton.cartonNumber ?? '',
cartons: _mixCartons)));
},
);
final senderBox = userDisplayBox(context,
@@ -315,18 +333,20 @@ class _CartonInfoState extends State<CartonInfo> {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Container(
color: e.key.isEven ? Colors.grey.shade300 : oddColor,
color: e.key.isEven ? Colors.grey.shade300 : oddColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
e.value.name ?? "",
style: TextStyle(color: Colors.black, fontSize: 15),
style:
TextStyle(color: Colors.black, fontSize: 15),
),
Text("${removeTrailingZeros((e.value.qty).toDouble())} pc",
Text(
"${removeTrailingZeros((e.value.qty).toDouble())} pc",
textAlign: TextAlign.end,
style:
TextStyle(color: Colors.black, fontSize: 15))
style: TextStyle(
color: Colors.black, fontSize: 15))
],
),
),
@@ -482,10 +502,16 @@ class _CartonInfoState extends State<CartonInfo> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: cartonSizeBox),
Flexible(child: packageLengthBox),
_packages.isEmpty
? const SizedBox()
: Flexible(child: packageLengthBox),
],
),
fromPackage ? const SizedBox() : mixCartonLengthBox,
fromPackage
? const SizedBox()
: _mixCartons.isEmpty
? const SizedBox()
: mixCartonLengthBox,
shipmentBox,
// _packages.isEmpty
// ? const SizedBox()
@@ -541,9 +567,7 @@ class _CartonInfoState extends State<CartonInfo> {
return list.map((p) {
return Container(
padding: EdgeInsets.only(top: 0),
child: Container(
child: Row(children: <Widget>[new Text(p.trackingID ?? "")]),
));
child: Row(children: <Widget>[Text(p.trackingID ?? "")]));
}).toList();
}
@@ -551,9 +575,7 @@ class _CartonInfoState extends State<CartonInfo> {
return list.map((c) {
return Container(
padding: EdgeInsets.only(top: 0),
child: Container(
child: Row(children: <Widget>[new Text(c.cartonNumber ?? '')]),
));
child: Row(children: <Widget>[Text(c.cartonNumber ?? '')]));
}).toList();
}

View File

@@ -134,9 +134,9 @@ class _CartonListState extends State<CartonList> {
FadeTransition(
opacity: animation,
child: SizeTransition(
child: child,
sizeFactor: animation,
axis: Axis.vertical,
child: child,
),
),
child: _down
@@ -289,36 +289,43 @@ class _CartonListState extends State<CartonList> {
Widget _filterWidget(BuildContext context) {
var model = Provider.of<CartonModel>(context);
return IconButton(
icon: Stack(
alignment: Alignment.center,
children: <Widget>[
const Icon(
Icons.filter_list,
color: Colors.white,
return Padding(
padding: const EdgeInsets.only(right: 5),
child: IconButton(
icon: SizedBox(
width: 30,
height: 30,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
const Icon(
Icons.filter_list,
color: Colors.white,
),
model.filterByStatus != null ||
model.filterBySender != null ||
model.filterByConsingee != null ||
model.shipment != null
? Positioned(
bottom: 15,
right: 0,
child: Container(
width: 10,
height: 10,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
)
: Container()
],
),
model.filterByStatus != null ||
model.filterBySender != null ||
model.filterByConsingee != null ||
model.shipment != null
? Positioned(
bottom: 15,
right: 0,
child: Container(
width: 10,
height: 10,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
)
: Container()
],
),
onPressed: () {
_showFilter();
});
),
onPressed: () {
_showFilter();
}),
);
}
_showFilter() async {

View File

@@ -1,4 +1,4 @@
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use, use_build_context_synchronously
import 'package:fcs/pages/carton/model/carton_model.dart';
import 'package:flutter/cupertino.dart';
@@ -26,7 +26,7 @@ import 'cargo_widget.dart';
import 'carton_size_widget.dart';
import 'carton_submit.dart';
import 'model/package_selection_model.dart';
import 'package_selection_widget.dart';
import 'packages_widget.dart';
class CartonPackageEditor extends StatefulWidget {
final Carton carton;
@@ -233,11 +233,10 @@ class _CartonPackageEditorState extends State<CartonPackageEditor> {
));
} else if (step.stepType == StepType.PACKAGES) {
return Expanded(
child: PackageSelectionWidget(
child: PackagesWidget(
sender: _sender!,
consignee: _consignee!,
shipment: _shipment!,
packages: _packages,
onContinue: (packages) {
setState(() {
_packages = List.from(packages);

View File

@@ -23,7 +23,7 @@ import 'carton_size_widget.dart';
import 'carton_submit.dart';
import 'model/carton_model.dart';
import 'model/package_selection_model.dart';
import 'package_selection_widget.dart';
import 'packages_widget.dart';
class CartonPackageForm extends StatefulWidget {
final User sender;
@@ -166,11 +166,10 @@ class _CartonPackageFormState extends State<CartonPackageForm> {
));
} else if (step.stepType == StepType.PACKAGES) {
return Expanded(
child: PackageSelectionWidget(
child: PackagesWidget(
sender: widget.sender,
consignee: widget.consignee,
shipment: _shipment!,
packages: _packages,
onContinue: (packages) {
setState(() {
_packages = List.from(packages);

View File

@@ -522,7 +522,7 @@ class _CartonSizeWidgetState extends State<CartonSizeWidget> {
children: [
const SizedBox(height: 8),
userRow,
LocalTitle(textKey: "box.bill_to", topPadding: 8),
LocalTitle(textKey: "box.bill_to", topPadding: 5),
const SizedBox(height: 5),
billRadioBox,
const SizedBox(height: 8),

View File

@@ -0,0 +1,114 @@
import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/widgets/local_app_bar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:intl/intl.dart';
import '../widgets/local_text.dart';
import 'carton_info.dart';
class MixCartonDetailList extends StatelessWidget {
final String cartonNumber;
final List<Carton> cartons;
MixCartonDetailList(
{super.key, required this.cartonNumber, required this.cartons});
final NumberFormat numberFormatter = NumberFormat("#,###");
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: LocalAppBar(
backgroundColor: Colors.white,
arrowColor: primaryColor,
labelColor: primaryColor,
titleWidget: Column(
children: [
LocalText(
context,
"box.cartion.count",
fontSize: 20,
color: primaryColor,
translationVariables: [numberFormatter.format(cartons.length)],
),
Text(cartonNumber,
style: TextStyle(fontSize: 15, color: Colors.black))
],
),
),
body: ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1, color: dividerColor),
itemCount: cartons.length,
itemBuilder: (BuildContext context, int index) {
var carton = cartons[index];
return InkWell(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => CartonInfo(carton: carton)),
);
},
child: Container(
padding: EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
children: <Widget>[
Icon(MaterialCommunityIcons.package,
color: primaryColor),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
carton.cartonNumber == null
? ''
: carton.cartonNumber!,
style: TextStyle(
fontSize: 15.0,
color: Colors.black),
),
Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(
carton.consigneeName ?? '',
style: TextStyle(
fontSize: 15.0,
color: Colors.grey),
),
),
],
),
),
),
],
),
),
),
Text(
"${carton.cartonWeight.toStringAsFixed(2)} lb",
style: TextStyle(fontSize: 14.0, color: Colors.grey),
)
],
),
],
),
),
);
},
));
}
}

View File

@@ -145,4 +145,33 @@ class PackageSelectionModel extends BaseModel {
}
return list;
}
Future<List<Package>> getActivePackages(
{required String shipmentId,
required String senderId,
required String consigneeId}) async {
List<Package> list = [];
try {
String path = "/$packages_collection";
var snaps = await FirebaseFirestore.instance
.collection(path)
.where("status",
whereIn: [package_processed_status, package_packed_status])
.where("sender_id", isEqualTo: senderId)
.where("user_id", isEqualTo: consigneeId)
// .where("fcs_shipment_id", isEqualTo: shipmentId)
.where("is_deleted", isEqualTo: false)
.orderBy("created_date", descending: true)
.get(const GetOptions(source: Source.server));
list = snaps.docs
.map((documentSnapshot) =>
Package.fromMap(documentSnapshot.data(), documentSnapshot.id))
.toList();
} catch (e) {
log.warning("Error!! $e");
list = [];
}
return list;
}
}

View File

@@ -0,0 +1,111 @@
import 'package:fcs/domain/entities/package.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/package/package_info.dart';
import 'package:fcs/pages/widgets/local_app_bar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:intl/intl.dart';
import '../widgets/local_text.dart';
class PackageDetailList extends StatelessWidget {
final String cartonNumber;
final List<Package> packages;
PackageDetailList(
{super.key, required this.cartonNumber, required this.packages});
final NumberFormat numberFormatter = NumberFormat("#,###");
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: LocalAppBar(
backgroundColor: Colors.white,
arrowColor: primaryColor,
labelColor: primaryColor,
titleWidget: Column(
children: [
LocalText(
context,
"box.package.count",
fontSize: 20,
color: primaryColor,
translationVariables: [numberFormatter.format(packages.length)],
),
Text(cartonNumber,
style: TextStyle(fontSize: 15, color: Colors.black))
],
),
),
body: ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1, color: dividerColor),
itemCount: packages.length,
itemBuilder: (BuildContext context, int index) {
var package = packages[index];
return InkWell(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => PackageInfo(package: package)),
);
},
child: Container(
padding: EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
children: <Widget>[
Icon(Octicons.package, color: primaryColor),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
package.id == null
? ''
: package.trackingID!,
style: TextStyle(
fontSize: 15.0,
color: Colors.black),
),
Padding(
padding:
const EdgeInsets.only(top: 5),
child: Text(
package.market == null
? ''
: package.market!,
style: TextStyle(
fontSize: 15.0,
color: Colors.grey),
),
),
],
),
),
),
],
),
),
),
],
),
],
),
),
);
},
));
}
}

View File

@@ -0,0 +1,211 @@
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart';
import 'package:provider/provider.dart';
import '../../domain/entities/package.dart';
import '../../domain/entities/user.dart';
import '../main/util.dart';
import '../widgets/continue_button.dart';
import '../widgets/local_title.dart';
import '../widgets/previous_button.dart';
import 'model/package_selection_model.dart';
import 'package_selection_result.dart';
typedef OnPrevious = Function(List<Package> packages);
typedef OnContinue = Function(List<Package> packages);
class PackagesWidget extends StatefulWidget {
final User sender;
final User consignee;
final FcsShipment shipment;
final OnPrevious? onPrevious;
final OnContinue? onContinue;
const PackagesWidget({
super.key,
this.onPrevious,
this.onContinue,
required this.shipment,
required this.sender,
required this.consignee,
});
@override
State<PackagesWidget> createState() => _PackagesWidgetState();
}
class _PackagesWidgetState extends State<PackagesWidget> {
final _scrollController = ScrollController();
bool _down = true;
List<Package> _packages = [];
@override
void initState() {
_init();
super.initState();
_scrollController.addListener(() {
setState(() {
_down = _scrollController.position.userScrollDirection ==
ScrollDirection.forward;
});
});
}
_init() async {
_packages.clear();
var packageModel = context.read<PackageSelectionModel>();
var list = await packageModel.getActivePackages(
shipmentId: widget.shipment.id!,
senderId: widget.sender.id!,
consigneeId: widget.consignee.id!);
_packages = List.from(list);
if (mounted) {
setState(() {});
}
}
@override
Widget build(BuildContext context) {
final senderBox = userDisplayBox(context,
lableKey: "box.sender.title",
icon: MaterialCommunityIcons.account_arrow_right,
showLink: false,
name: widget.sender.name ?? "",
fcsID: widget.sender.fcsID ?? "");
final consigneeBox = userDisplayBox(context,
showLink: false,
lableKey: "box.consignee.title",
icon: MaterialCommunityIcons.account_arrow_left,
name: widget.consignee.name,
fcsID: widget.consignee.fcsID);
final userRow = Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(flex: 2, child: consigneeBox),
Flexible(child: senderBox)
],
);
final continueBtn = ContinueButton(
onTap: () {
if (widget.onContinue != null) {
widget.onContinue!(_packages);
}
},
);
final previousBtn = PreviousButton(onTap: () {
if (widget.onPrevious != null) {
widget.onPrevious!(_packages);
}
});
return Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: Column(
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder:
(Widget child, Animation<double> animation) =>
FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axis: Axis.vertical,
child: child,
),
),
child: _down
? Column(children: [
const SizedBox(height: 8),
userRow,
LocalTitle(
textKey: "box.select.package", topPadding: 5),
const SizedBox(height: 10),
])
: const SizedBox(),
),
Expanded(
child: RefreshIndicator(
color: primaryColor,
onRefresh: () async {
_init();
},
child: ListView.builder(
padding: const EdgeInsets.only(top: 10),
controller: _scrollController,
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
Package package = _packages[index];
return packageRow(context, package);
},
itemCount: _packages.length)),
),
],
),
),
),
widget.onContinue != null
? Padding(
padding: const EdgeInsets.only(left: 15, right: 15, top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
previousBtn,
continueBtn,
],
),
)
: const SizedBox(),
const SizedBox(height: 20)
],
);
}
Widget packageRow(BuildContext context, Package package) {
return Padding(
padding: const EdgeInsets.only(top: 5, bottom: 5),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5)),
border: Border.all(color: Colors.grey.shade300)),
padding: EdgeInsets.only(left: 10, right: 10),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(package.trackingID ?? "",
style: TextStyle(fontSize: 15.0, color: Colors.black)),
Text(
package.cartonIds.isEmpty
? "-"
: "${numberFormatter.format(package.cartonIds.length)} Boxes",
style: TextStyle(fontSize: 15.0, color: Colors.grey),
),
],
),
),
),
package.isChecked
? Icon(Icons.check, color: primaryColor)
: const SizedBox()
],
),
),
);
}
}