Aidra Connect 10.0.2+16
Aidra Connect Mobile Application
Loading...
Searching...
No Matches
generate_mainifest_pdf.dart
Go to the documentation of this file.
1// import 'dart:convert';
2// import 'dart:developer';
3// import 'dart:io';
4
5// import 'package:another_flushbar/flushbar.dart';
6// import 'package:connect/core/constants/assets.dart';
7// import 'package:connect/core/ui/widgets/custom_snackbar.dart';
8// import 'package:connect/core/utils/number_conversion.dart';
9// import 'package:flutter/material.dart';
10// import 'package:flutter/services.dart';
11// import 'package:flutter_screenutil/flutter_screenutil.dart';
12// import 'package:open_filex/open_filex.dart';
13// import 'package:path_provider/path_provider.dart';
14// import 'package:pdf/pdf.dart';
15// import 'package:pdf/widgets.dart' as pw;
16
17// import '../../../../../../../../../../core/api/api_client.dart';
18// import '../../../../../../../../../../core/services/service_locator.dart';
19
20// Future generateManifest({
21// required BuildContext context,
22// required String collectionName,
23// }) async {
24// final data = await fetchData(collectionName: collectionName);
25// if (data == null) {
26// Flushbar(
27// margin: EdgeInsets.all(10),
28// borderRadius: BorderRadius.circular(10),
29// backgroundColor: Theme.of(context).colorScheme.error,
30// message: "E-Manifest generation failed. Please try again",
31// duration: Duration(seconds: 2),
32// ).show(context);
33// return;
34// }
35
36// final pdf = pw.Document();
37
38// // Load the logo image
39// final ByteData logoBytes = await rootBundle.load(Assets.tajmieLogo);
40// final Uint8List logoData = logoBytes.buffer.asUint8List();
41// final pw.MemoryImage logoImage = pw.MemoryImage(logoData);
42
43// //status of collection
44// String adaptstatus({required String status}) {
45// switch (status) {
46// case 'draft':
47// return 'Ongoing';
48// case 'done':
49// return 'Completed';
50// default:
51// return '';
52// }
53// }
54
55// // Define colors
56// final PdfColor headerBlue = PdfColor.fromInt(0xFF9DCDE7);
57
58// // Load custom font with Unicode support
59// final fontData = await rootBundle.load('assets/fonts/notokufi_font.ttf');
60// final ttf = pw.Font.ttf(fontData);
61
62// final boldyFont =
63// await rootBundle.load("assets/fonts/NotoKufiArabic-Bold.ttf");
64// final ttf2 = pw.Font.ttf(boldyFont);
65
66// // Create theme with the custom font
67// final theme = pw.ThemeData.withFont(
68// base: ttf,
69// bold:
70// ttf, // Use the same font for bold since we don't have a separate bold variant
71// italic: ttf,
72// boldItalic: ttf,
73// );
74
75// String _formatDate(DateTime? date) {
76// if (date == null) return '--'; // Handle null case
77// return '${date.day}/${date.month}/${date.year}';
78// }
79
80// pdf.addPage(
81// pw.Page(
82// theme: theme,
83// pageFormat: PdfPageFormat.a4,
84// //textDirection: pw.TextDirection.rtl,
85// margin: const pw.EdgeInsets.all(5),
86// build: (context) => pw.Column(
87// crossAxisAlignment: pw.CrossAxisAlignment.start,
88// children: [
89// // Header with logo and title
90// pw.Row(
91// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
92// children: [
93// pw.Image(logoImage, width: 60, height: 60),
94// pw.Column(
95// crossAxisAlignment: pw.CrossAxisAlignment.center,
96// children: [
97// pw.Text(
98// 'WASTE E-MANIFEST',
99// style: pw.TextStyle(
100// fontSize: 16,
101// fontWeight: pw.FontWeight.bold,
102// ),
103// ),
104// ],
105// ),
106// pw.Row(
107// children: [
108// pw.Column(children: [
109// pw.Text('Document No: ${data?.id}',
110// style: pw.TextStyle(fontSize: 9)),
111// pw.Text(
112// 'Status: ${adaptstatus(status: data?.status ?? '')}',
113// style: pw.TextStyle(fontSize: 9)),
114// ]),
115// pw.Padding(
116// padding: const pw.EdgeInsets.only(left: 10),
117// child: pw.Container(
118// width: 30,
119// height: 30,
120// child: pw.BarcodeWidget(
121// barcode: pw.Barcode.qrCode(),
122// data:
123// 'WASTE E-MANIFEST - Document No: ${data?.id} - Status: ${adaptstatus(status: data?.status ?? '')} - origin: Aidra Connect',
124// width: 30,
125// height: 30,
126// ),
127// ),
128// ),
129// ],
130// ),
131// ],
132// ),
133// pw.SizedBox(height: 5),
134// // Part A
135// _buildSectionHeader(
136// 'Part - A : Waste Generator Information', headerBlue, ttf2),
137// _buildInfoField(
138// '1. Generator ID. No:',
139// data?.partner?.internalCode,
140// ttf2,
141// ),
142// _buildInfoField(
143// '2. Generator\'s Name and Address:',
144// ' ${data?.partner?.name} ${data?.partner?.street ?? ''}',
145// ttf2,
146// pw.TextDirection.rtl,
147// ),
148// _buildInfoField(
149// '3. Generator\'s Phone No. and Person To Contact:',
150// '${data?.partner?.phone ?? ''} ${data?.partner?.contactName ?? ''}',
151// ttf2,
152// ),
153
154// _buildInfoField(
155// '4. Transporter\'s Name:',
156// data?.company?.partner?.name ?? '',
157// ttf2,
158// ),
159
160// pw.Padding(
161// padding: const pw.EdgeInsets.only(left: 20),
162// child: pw.Column(
163// crossAxisAlignment: pw.CrossAxisAlignment.start,
164// children: [
165// _buildInfoField(
166// 'Mailing Address:',
167// data?.company?.partner?.street,
168// ttf2,
169// ),
170// pw.Row(
171// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
172// children: [
173// pw.Expanded(
174// child: _buildInfoField(
175// 'Tel. No',
176// data?.company?.partner?.phone,
177// ttf2,
178// ),
179// ),
180// pw.Expanded(
181// child: _buildInfoField(
182// 'Person to Contact:',
183// data?.partner?.salesPerson?.partnerId?.name,
184// ttf2,
185// pw.TextDirection.rtl,
186// ),
187// )
188// ])
189// ],
190// ),
191// ),
192
193// // Shipping info table
194// pw.SizedBox(height: 10),
195// _buildShippingTable(data: data, font: ttf2),
196// pw.SizedBox(height: 10),
197
198// // Generator's certification
199// pw.Padding(
200// padding: const pw.EdgeInsets.symmetric(horizontal: 10, vertical: 2),
201// child: pw.Column(
202// crossAxisAlignment: pw.CrossAxisAlignment.start,
203// children: [
204// pw.Text(
205// '10. Generator\'s Certification:',
206// style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
207// ),
208// pw.SizedBox(height: 5),
209// pw.Row(
210// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
211// children: [
212// pw.Expanded(
213// child: pw.Text(
214// 'I hereby declare that the contents of this consignment are fully and accurately described above by proper shipping name and classified, packed, marked, and labeled, and are in all respects in proper condition for transport by highway according to applicable laws and regulations of the Kingdom.',
215// style: pw.TextStyle(fontSize: 9),
216// ),
217// ),
218// pw.SizedBox(width: 10),
219// pw.Column(
220// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
221// children: [
222// pw.Column(
223// crossAxisAlignment: pw.CrossAxisAlignment.start,
224// children: [
225// pw.Text(
226// 'Name of the Authorized Representative: ${data?.partner?.contactName ?? ''}',
227// style: pw.TextStyle(fontSize: 9)),
228// pw.SizedBox(height: 4),
229// pw.Padding(
230// padding: const pw.EdgeInsets.only(right: 50),
231// child: pw.Text(
232// 'Date: ${_formatDate(data?.collectionDate)}',
233// style: pw.TextStyle(fontSize: 9)),
234// ),
235// pw.SizedBox(height: 4),
236// pw.Padding(
237// padding: const pw.EdgeInsets.only(right: 50),
238// child: pw.Text('Signature',
239// style: pw.TextStyle(fontSize: 9)),
240// ),
241// ],
242// ),
243// ],
244// ),
245// ],
246// ),
247// ],
248// ),
249// ),
250
251// // Part B
252// _buildSectionHeader(
253// 'Part - B : Transporter Information', headerBlue, ttf2),
254// pw.Padding(
255// padding: const pw.EdgeInsets.symmetric(horizontal: 10, vertical: 5),
256// child: pw.Column(
257// crossAxisAlignment: pw.CrossAxisAlignment.start,
258// children: [
259// pw.Text(
260// '11. Transporter\'s Acknowledgement of Receipt of Materials'),
261// pw.SizedBox(height: 5),
262// pw.Row(
263// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
264// children: [
265// pw.Column(
266// crossAxisAlignment: pw.CrossAxisAlignment.start,
267// children: [
268// pw.Text('Driver Name: ${data?.driver?.name ?? ''}',
269// style: pw.TextStyle(fontSize: 9)),
270// pw.SizedBox(height: 7),
271// pw.Text(
272// 'Vehicle Plate No.: ${data?.vehiclePlate ?? ''}',
273// style: pw.TextStyle(fontSize: 9)),
274// ],
275// ),
276// pw.Column(
277// crossAxisAlignment: pw.CrossAxisAlignment.start,
278// children: [
279// pw.Padding(
280// padding: const pw.EdgeInsets.only(right: 60),
281// child: pw.Text(
282// 'Date: ${_formatDate(data?.collectionVoucher?.confirmationDate)}',
283// style: pw.TextStyle(fontSize: 9)),
284// ),
285// pw.SizedBox(height: 7),
286// pw.Padding(
287// padding: const pw.EdgeInsets.only(right: 60),
288// child: pw.Text('Signature of Drive:',
289// style: pw.TextStyle(fontSize: 9)),
290// ),
291// ],
292// ),
293// ],
294// ),
295// ],
296// ),
297// ),
298
299// // Part C
300// _buildSectionHeader(
301// 'Part - C : Warehouse Facility Information', headerBlue, ttf2),
302// pw.Padding(
303// padding: const pw.EdgeInsets.symmetric(horizontal: 2),
304// child: pw.Column(
305// crossAxisAlignment: pw.CrossAxisAlignment.start,
306// children: [
307// pw.Text('12. Discrepancy Indication Space',
308// style: pw.TextStyle(fontSize: 10)),
309// pw.SizedBox(height: 3),
310// pw.Text(
311// '13. Facility Owner/Operator certification of material covered by this manifest except as noted in item',
312// style: pw.TextStyle(fontSize: 10)),
313// pw.SizedBox(height: 5),
314// pw.Row(
315// mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
316// children: [
317// pw.Column(
318// crossAxisAlignment: pw.CrossAxisAlignment.start,
319// children: [
320// pw.Text('Receiver Name:',
321// style: pw.TextStyle(fontSize: 9)),
322// pw.SizedBox(height: 5),
323// pw.Text('Signature:', style: pw.TextStyle(fontSize: 9)),
324// ],
325// ),
326// pw.Padding(
327// padding: const pw.EdgeInsets.only(right: 60),
328// child: pw.Text('Date:', style: pw.TextStyle(fontSize: 9)),
329// ),
330// ],
331// ),
332// ],
333// ),
334// ),
335// pw.SizedBox(height: 5),
336// pw.Align(
337// alignment: pw.Alignment.bottomRight,
338// child: pw.Text(
339// 'POWERED BY\nAidra Connect',
340// style: pw.TextStyle(fontSize: 8, color: PdfColors.grey),
341// textAlign: pw.TextAlign.right,
342// ),
343// ),
344// ],
345// ),
346// ),
347// );
348
349// final output = await getTemporaryDirectory();
350// final file = File('${output.path}/E-Manifest_$collectionName.pdf');
351// await file.writeAsBytes(await pdf.save());
352
353// OpenFilex.open(file.path);
354// }
355
356// pw.Widget _buildSectionHeader(String title, PdfColor color, pw.Font font) {
357// return pw.Container(
358// width: double.infinity,
359// color: color,
360// padding: const pw.EdgeInsets.symmetric(vertical: 4, horizontal: 10),
361// margin: const pw.EdgeInsets.only(bottom: 2, top: 3),
362// child: pw.Text(
363// title,
364// style: pw.TextStyle(
365// font: font,
366// fontSize: 10,
367// ),
368// ),
369// );
370// }
371
372// pw.Widget _buildInfoField(
373// String label,
374// String? info,
375// pw.Font font, [
376// pw.TextDirection? textdirection,
377// ]) {
378// return pw.Container(
379// width: double.infinity,
380// decoration: pw.BoxDecoration(
381// border: pw.Border(
382// bottom: pw.BorderSide(color: PdfColors.grey300),
383// ),
384// ),
385// padding: const pw.EdgeInsets.symmetric(vertical: 5, horizontal: 10),
386// child: pw.Column(
387// crossAxisAlignment: pw.CrossAxisAlignment.start,
388// children: [
389// pw.Text(
390// label,
391// style: pw.TextStyle(fontSize: 9, font: font),
392// ),
393// pw.Padding(
394// padding: pw.EdgeInsets.symmetric(horizontal: 5.sp),
395// child: pw.Text(
396// info ?? '',
397// style: pw.TextStyle(fontSize: 8),
398// textDirection: textdirection,
399// ),
400// ),
401// ],
402// ),
403// );
404// }
405
406// pw.Widget _buildShippingTable({
407// required MainifestEntity? data,
408// required pw.Font font,
409// }) {
410// return pw.Table(
411// border: pw.TableBorder.all(color: PdfColors.grey700),
412// columnWidths: {
413// 0: pw.FlexColumnWidth(3),
414// 1: pw.FlexColumnWidth(2),
415// 2: pw.FlexColumnWidth(1),
416// 3: pw.FlexColumnWidth(1),
417// 4: pw.FlexColumnWidth(1),
418// },
419// children: [
420// // Header row
421// pw.TableRow(
422// decoration: pw.BoxDecoration(color: PdfColors.blue50),
423// children: [
424// pw.Padding(
425// padding: const pw.EdgeInsets.all(2),
426// child: pw.Text(
427// '5.(Shipping Name, Hazard Class, and PIN)',
428// style: pw.TextStyle(
429// fontSize: 9,
430// font: font,
431// ),
432// ),
433// ),
434// pw.Column(
435// children: [
436// // Main Containers header
437// pw.Container(
438// alignment: pw.Alignment.center,
439// padding: const pw.EdgeInsets.all(5),
440// child: pw.Text(
441// '6.Containers',
442// style: pw.TextStyle(
443// fontSize: 9,
444// font: font,
445// ),
446// ),
447// ),
448// // Nested table for No. and Type
449// pw.Table(
450// border: pw.TableBorder(
451// top: pw.BorderSide(color: PdfColors.grey700),
452// left: pw.BorderSide(color: PdfColors.grey700, width: 0),
453// right: pw.BorderSide(color: PdfColors.grey700, width: 0),
454// ),
455// columnWidths: {
456// 0: pw.FlexColumnWidth(1), // No. sub-column
457// 1: pw.FlexColumnWidth(1), // Type sub-column
458// },
459// children: [
460// // Sub-header row
461// pw.TableRow(
462// decoration: pw.BoxDecoration(color: PdfColors.blue50),
463// children: [
464// pw.Container(
465// alignment: pw.Alignment.center,
466// padding: const pw.EdgeInsets.all(5),
467// child: pw.Text('No.',
468// style: pw.TextStyle(
469// fontSize: 9,
470// font: font,
471// )),
472// ),
473// pw.Container(
474// alignment: pw.Alignment.center,
475// padding: const pw.EdgeInsets.all(5),
476// child: pw.Text('Type',
477// style: pw.TextStyle(
478// fontSize: 9,
479// font: font,
480// )),
481// ),
482// ],
483// ),
484// ],
485// ),
486// ],
487// ),
488// pw.Padding(
489// padding: const pw.EdgeInsets.all(5),
490// child: pw.Column(
491// crossAxisAlignment: pw.CrossAxisAlignment.center,
492// children: [
493// pw.Text('7.Total Qty',
494// style: pw.TextStyle(
495// fontSize: 9,
496// font: font,
497// )),
498// ],
499// ),
500// ),
501// pw.Padding(
502// padding: const pw.EdgeInsets.all(5),
503// child: pw.Text('8.Unit Wt/Vol',
504// style: pw.TextStyle(
505// fontSize: 9,
506// font: font,
507// )),
508// ),
509// pw.Padding(
510// padding: const pw.EdgeInsets.all(5),
511// child: pw.Text('9.WPS',
512// style: pw.TextStyle(
513// fontSize: 9,
514// font: font,
515// )),
516// ),
517// ],
518// ),
519// // Empty data rows
520// _buildTableRow(data: data),
521// _buildEmptyTableRow(),
522// ],
523// );
524// }
525
526// String extractName(String? productName) {
527// if (productName == null || productName.isEmpty) {
528// return '';
529// }
530
531// final Map<String, dynamic> decoded = jsonDecode(productName);
532// return decoded['en_US'] ?? '';
533// }
534
535// // pw.TableRow _buildTableRow({required MainifestEntity? data}) {
536// // final datalist = [
537// // extractProductName(data?.productName),
538// // '${data?.containerNumber} | ${data?.containerType}',
539// // '${data?.totalQuantity}',
540// // '${data?.uom}',
541// // '',
542// // ];
543// // return pw.TableRow(
544// // children: List.generate(
545// // datalist.length,
546// // (index) => pw.Container(
547// // padding: pw.EdgeInsets.only(top: 3),
548// // height: 25,
549// // child: pw.Text(" ${datalist[index]}"),
550// // ),
551// // ),
552// // );
553// // }
554
555// pw.TableRow _buildTableRow({required MainifestEntity? data}) {
556// return pw.TableRow(
557// children: [
558// // Column 1: Product Name
559// pw.Padding(
560// padding: const pw.EdgeInsets.all(3),
561// child: pw.Text(extractName(data?.productName),
562// style: pw.TextStyle(fontSize: 9)),
563// ),
564// // Column 2: Container (this should be a nested table with two sub-columns)
565// pw.Table(
566// border: pw.TableBorder(
567// horizontalInside: pw.BorderSide(color: PdfColors.grey700),
568// verticalInside: pw.BorderSide(color: PdfColors.grey700),
569// ),
570// columnWidths: {
571// 0: pw.FlexColumnWidth(1), // No. sub-column
572// 1: pw.FlexColumnWidth(1), // Type sub-column
573// },
574// children: [
575// pw.TableRow(
576// children: [
577// // No. column
578// pw.Container(
579// alignment: pw.Alignment.center,
580// padding: const pw.EdgeInsets.all(3),
581// child: pw.Text('${data?.containerNumber}',
582// style: pw.TextStyle(fontSize: 9)),
583// ),
584// // Type column
585// pw.Container(
586// alignment: pw.Alignment.center,
587// padding: const pw.EdgeInsets.all(3),
588// child: pw.Text('${data?.containerType}',
589// style: pw.TextStyle(fontSize: 9)),
590// ),
591// ],
592// ),
593// ],
594// ),
595// // Column 3: Total Quantity
596// pw.Padding(
597// padding: const pw.EdgeInsets.all(3),
598// child: pw.Container(
599// alignment: pw.Alignment.center,
600// child: pw.Text(
601// '${NumberConversionService.convertAndFormatWeight(data?.totalQuantity)}',
602// style: pw.TextStyle(fontSize: 9)),
603// ),
604// ),
605// // Column 4: UOM
606// pw.Padding(
607// padding: const pw.EdgeInsets.all(3),
608// child: pw.Container(
609// alignment: pw.Alignment.center,
610// child: pw.Text('Kg', style: pw.TextStyle(fontSize: 9)),
611// ),
612// ),
613// // Column 5: WASTE No.
614// pw.Padding(
615// padding: const pw.EdgeInsets.all(3),
616// child: pw.Text('', style: pw.TextStyle(fontSize: 9)),
617// ),
618// ],
619// );
620// }
621
622// // pw.TableRow _buildEmptyTableRow() {
623// // return pw.TableRow(
624// // children: List.generate(
625// // 5,
626// // (index) => pw.Container(
627// // height: 25,
628// // child: pw.Text(''),
629// // ),
630// // ),
631// // );
632// // }
633// pw.TableRow _buildEmptyTableRow() {
634// return pw.TableRow(
635// children: [
636// // Column 1: Product Name
637// pw.Container(height: 25, child: pw.Text('')),
638// // Column 2: Container (nested table)
639// pw.Table(
640// border: pw.TableBorder(
641// horizontalInside: pw.BorderSide(color: PdfColors.grey700),
642// verticalInside: pw.BorderSide(color: PdfColors.grey700),
643// ),
644// columnWidths: {
645// 0: pw.FlexColumnWidth(1),
646// 1: pw.FlexColumnWidth(1),
647// },
648// children: [
649// pw.TableRow(
650// children: [
651// pw.Container(height: 25, child: pw.Text('')),
652// pw.Container(height: 25, child: pw.Text('')),
653// ],
654// ),
655// ],
656// ),
657// // Column 3: Total Quantity
658// pw.Container(height: 25, child: pw.Text('')),
659// // Column 4: UOM
660// pw.Container(height: 25, child: pw.Text('')),
661// // Column 5: WASTE No.
662// pw.Container(height: 25, child: pw.Text('')),
663// ],
664// );
665// }
666
667// Future<MainifestEntity?>? fetchData({required String collectionName}) async {
668// try {
669// final apiClient = sl<ApiClient>();
670// final response = await apiClient.get(
671// '',
672// {},
673// false,
674// 'https://dev-api.aidra.tech/document/ManifestDocument/$collectionName',
675// );
676// if (response == {}) {
677// return null;
678// }
679// log(response.toString());
680// return MainifestEntity.fromJson(response);
681// } catch (e) {
682// print(e);
683// return null;
684// }
685// }
686
687// class MainifestEntity {
688// final DateTime? collectionDate;
689// final CollectionVoucher? collectionVoucher;
690// final Company? company;
691// final String? containerNumber;
692// final String? containerType;
693// final Partner? driver;
694// final String? generatorId;
695// final int? id;
696// final Partner? partner;
697// final String? productName;
698// final String? status;
699// final int? totalQuantity;
700// final String? uom;
701// final String? vehiclePlate;
702
703// MainifestEntity({
704// this.collectionDate,
705// this.collectionVoucher,
706// this.company,
707// this.containerNumber,
708// this.containerType,
709// this.driver,
710// this.generatorId,
711// this.id,
712// this.partner,
713// this.productName,
714// this.status,
715// this.totalQuantity,
716// this.uom,
717// this.vehiclePlate,
718// });
719
720// factory MainifestEntity.fromJson(Map<String, dynamic> json) {
721// return MainifestEntity(
722// collectionDate: json['collectionDate'] != null
723// ? DateTime.parse(json['collectionDate'])
724// : null,
725// collectionVoucher: json['collectionVoucher'] != null
726// ? CollectionVoucher.fromJson(json['collectionVoucher'])
727// : null,
728// company:
729// json['company'] != null ? Company.fromJson(json['company']) : null,
730// containerNumber: json['containerNumber'],
731// containerType: json['containerType'],
732// driver: json['driver'] != null ? Partner.fromJson(json['driver']) : null,
733// generatorId: json['generatorId'],
734// id: json['id'],
735// partner:
736// json['partner'] != null ? Partner.fromJson(json['partner']) : null,
737// productName: json['productName'],
738// status: json['status'],
739// totalQuantity: json['totalQuantity'],
740// uom: json['uom'],
741// vehiclePlate: json['vehiclePlate'],
742// );
743// }
744
745// Map<String, dynamic> toJson() {
746// final Map<String, dynamic> data = <String, dynamic>{};
747// if (collectionDate != null) {
748// data['collectionDate'] = collectionDate!.toIso8601String();
749// }
750// if (collectionVoucher != null) {
751// data['collectionVoucher'] = collectionVoucher!.toJson();
752// }
753// if (company != null) {
754// data['company'] = company!.toJson();
755// }
756// data['containerNumber'] = containerNumber;
757// data['containerType'] = containerType;
758// if (driver != null) {
759// data['driver'] = driver!.toJson();
760// }
761// data['generatorId'] = generatorId;
762// data['id'] = id;
763// if (partner != null) {
764// data['partner'] = partner!.toJson();
765// }
766// data['productName'] = productName;
767// data['status'] = status;
768// data['totalQuantity'] = totalQuantity;
769// data['uom'] = uom;
770// data['vehiclePlate'] = vehiclePlate;
771// return data;
772// }
773// }
774
775// class CollectionVoucher {
776// final String? billStatus;
777// final String? collectionConfirmRef;
778// final String? collectionOrderRef;
779// final DateTime? confirmationDate;
780// final double? cvAmountTotal;
781// final int? id;
782// final String? name;
783// final String? paymentBillRef;
784// final String? receiptStatus;
785// final String? status;
786
787// CollectionVoucher({
788// this.billStatus,
789// this.collectionConfirmRef,
790// this.collectionOrderRef,
791// this.confirmationDate,
792// this.cvAmountTotal,
793// this.id,
794// this.name,
795// this.paymentBillRef,
796// this.receiptStatus,
797// this.status,
798// });
799
800// factory CollectionVoucher.fromJson(Map<String, dynamic> json) {
801// return CollectionVoucher(
802// billStatus: json['billStatus'],
803// collectionConfirmRef: json['collectionConfirmRef'],
804// collectionOrderRef: json['collectionOrderRef'],
805// confirmationDate: json['confirmationDate'] != null
806// ? DateTime.parse(json['confirmationDate'])
807// : null,
808// cvAmountTotal: json['cvAmountTotal']?.toDouble(),
809// id: json['id'],
810// name: json['name'],
811// paymentBillRef: json['paymentBillRef'],
812// receiptStatus: json['receiptStatus'],
813// status: json['status'],
814// );
815// }
816
817// Map<String, dynamic> toJson() {
818// final Map<String, dynamic> data = <String, dynamic>{};
819// data['billStatus'] = billStatus;
820// data['collectionConfirmRef'] = collectionConfirmRef;
821// data['collectionOrderRef'] = collectionOrderRef;
822// if (confirmationDate != null) {
823// data['confirmationDate'] = confirmationDate!.toIso8601String();
824// }
825// data['cvAmountTotal'] = cvAmountTotal;
826// data['id'] = id;
827// data['name'] = name;
828// data['paymentBillRef'] = paymentBillRef;
829// data['receiptStatus'] = receiptStatus;
830// data['status'] = status;
831// return data;
832// }
833// }
834
835// class Company {
836// final int? id;
837// final String? name;
838// final Partner? partner;
839
840// Company({
841// this.id,
842// this.name,
843// this.partner,
844// });
845
846// factory Company.fromJson(Map<String, dynamic> json) {
847// return Company(
848// id: json['id'],
849// name: json['name'],
850// partner:
851// json['partner'] != null ? Partner.fromJson(json['partner']) : null,
852// );
853// }
854
855// Map<String, dynamic> toJson() {
856// final Map<String, dynamic> data = <String, dynamic>{};
857// data['id'] = id;
858// data['name'] = name;
859// if (partner != null) {
860// data['partner'] = partner!.toJson();
861// }
862// return data;
863// }
864// }
865
866// class Partner {
867// final String? contactName;
868// final int? id;
869// final String? internalCode;
870// final bool? isCompany;
871// final double? monthlyCapacity;
872// final String? name;
873// final int? parentId;
874// final String? partnerLatitude;
875// final String? partnerLongitude;
876// final String? phone;
877// final SalesPerson? salesPerson;
878// final String? street;
879// final double? tokenTotalValue;
880
881// Partner({
882// this.contactName,
883// this.id,
884// this.internalCode,
885// this.isCompany,
886// this.monthlyCapacity,
887// this.name,
888// this.parentId,
889// this.partnerLatitude,
890// this.partnerLongitude,
891// this.phone,
892// this.salesPerson,
893// this.street,
894// this.tokenTotalValue,
895// });
896
897// factory Partner.fromJson(Map<String, dynamic> json) {
898// return Partner(
899// contactName: json['contactName'],
900// id: json['id'],
901// internalCode: json['internalCode'],
902// isCompany: json['isCompany'],
903// monthlyCapacity: json['monthlyCapacity']?.toDouble(),
904// name: json['name'],
905// parentId: json['parentId'],
906// partnerLatitude: json['partnerLatitude'],
907// partnerLongitude: json['partnerLongitude'],
908// phone: json['phone'],
909// salesPerson: json['salesPerson'] != null
910// ? SalesPerson.fromJson(json['salesPerson'])
911// : null,
912// street: json['street'],
913// tokenTotalValue: json['tokenTotalValue']?.toDouble(),
914// );
915// }
916
917// Map<String, dynamic> toJson() {
918// final Map<String, dynamic> data = <String, dynamic>{};
919// data['contactName'] = contactName;
920// data['id'] = id;
921// data['internalCode'] = internalCode;
922// data['isCompany'] = isCompany;
923// data['monthlyCapacity'] = monthlyCapacity;
924// data['name'] = name;
925// data['parentId'] = parentId;
926// data['partnerLatitude'] = partnerLatitude;
927// data['partnerLongitude'] = partnerLongitude;
928// data['phone'] = phone;
929// if (salesPerson != null) {
930// data['salesPerson'] = salesPerson!.toJson();
931// }
932// data['street'] = street;
933// data['tokenTotalValue'] = tokenTotalValue;
934// return data;
935// }
936// }
937
938// class SalesPerson {
939// final Company? company;
940// final int? id;
941// final PartnerId? partnerId;
942
943// SalesPerson({
944// this.company,
945// this.id,
946// this.partnerId,
947// });
948
949// factory SalesPerson.fromJson(Map<String, dynamic> json) {
950// return SalesPerson(
951// company:
952// json['company'] != null ? Company.fromJson(json['company']) : null,
953// id: json['id'],
954// partnerId: json['partnerId'] != null
955// ? PartnerId.fromJson(json['partnerId'])
956// : null,
957// );
958// }
959
960// Map<String, dynamic> toJson() {
961// final Map<String, dynamic> data = <String, dynamic>{};
962// if (company != null) {
963// data['company'] = company!.toJson();
964// }
965// data['id'] = id;
966// if (partnerId != null) {
967// data['partnerId'] = partnerId!.toJson();
968// }
969// return data;
970// }
971// }
972
973// class PartnerId {
974// final int? id;
975// final bool? isCompany;
976// final double? monthlyCapacity;
977// final String? name;
978// final String? partnerLatitude;
979// final String? partnerLongitude;
980// final double? tokenTotalValue;
981
982// PartnerId({
983// this.id,
984// this.isCompany,
985// this.monthlyCapacity,
986// this.name,
987// this.partnerLatitude,
988// this.partnerLongitude,
989// this.tokenTotalValue,
990// });
991
992// factory PartnerId.fromJson(Map<String, dynamic> json) {
993// return PartnerId(
994// id: json['id'],
995// isCompany: json['isCompany'],
996// monthlyCapacity: json['monthlyCapacity']?.toDouble(),
997// name: json['name'],
998// partnerLatitude: json['partnerLatitude'],
999// partnerLongitude: json['partnerLongitude'],
1000// tokenTotalValue: json['tokenTotalValue']?.toDouble(),
1001// );
1002// }
1003
1004// Map<String, dynamic> toJson() {
1005// final Map<String, dynamic> data = <String, dynamic>{};
1006// data['id'] = id;
1007// data['isCompany'] = isCompany;
1008// data['monthlyCapacity'] = monthlyCapacity;
1009// data['name'] = name;
1010// data['partnerLatitude'] = partnerLatitude;
1011// data['partnerLongitude'] = partnerLongitude;
1012// data['tokenTotalValue'] = tokenTotalValue;
1013// return data;
1014// }
1015// }
1016
1017import 'dart:convert';
1018import 'dart:developer';
1019import 'dart:io';
1020
1021import 'package:another_flushbar/flushbar.dart';
1022import 'package:connect/core/constants/assets.dart';
1023import 'package:connect/core/ui/widgets/custom_snackbar.dart';
1024import 'package:connect/core/utils/number_conversion.dart';
1025import 'package:flutter/material.dart';
1026import 'package:flutter/services.dart';
1027import 'package:flutter_screenutil/flutter_screenutil.dart';
1028import 'package:open_filex/open_filex.dart';
1029import 'package:path_provider/path_provider.dart';
1030import 'package:pdf/pdf.dart';
1031import 'package:pdf/widgets.dart' as pw;
1032
1033import '../../../../../../../../../../core/api/api_client.dart';
1034import '../../../../../../../../../../core/services/service_locator.dart';
1035
1037 required BuildContext context,
1038 required String collectionName,
1039}) async {
1040 final data = await fetchData(collectionName: collectionName);
1041 if (data == null) {
1042 Flushbar(
1043 margin: EdgeInsets.all(10),
1044 borderRadius: BorderRadius.circular(10),
1045 backgroundColor: Theme.of(context).colorScheme.error,
1046 message: "E-Manifest generation failed. Please try again",
1047 duration: Duration(seconds: 2),
1048 ).show(context);
1049 return;
1050 }
1051
1052 final pdf = pw.Document();
1053
1054 // Load the logo image
1055 final ByteData logoBytes = await rootBundle.load(Assets.tajmieLogo);
1056 final Uint8List logoData = logoBytes.buffer.asUint8List();
1057 final pw.MemoryImage logoImage = pw.MemoryImage(logoData);
1058
1059 // Status of collection
1060 String adaptStatus({required String status}) {
1061 switch (status) {
1062 case 'draft':
1063 return 'Ongoing';
1064 case 'done':
1065 return 'Completed';
1066 default:
1067 return '';
1068 }
1069 }
1070
1071 // Define colors
1072 final PdfColor headerBlue = PdfColor.fromInt(0xFF9DCDE7);
1073
1074 // Load custom font with Unicode support
1075 final fontData = await rootBundle.load('assets/fonts/notokufi_font.ttf');
1076 final ttf = pw.Font.ttf(fontData);
1077
1078 final boldyFont =
1079 await rootBundle.load("assets/fonts/NotoKufiArabic-Bold.ttf");
1080 final boldFont = pw.Font.ttf(boldyFont);
1081
1082 // Create theme with the custom font
1083 final theme = pw.ThemeData.withFont(
1084 base: ttf,
1085 bold: boldFont,
1086 italic: ttf,
1087 boldItalic: boldFont,
1088 );
1089
1090 String _formatDate(DateTime? date) {
1091 if (date == null) return '--';
1092 return '${date.day}/${date.month}/${date.year}';
1093 }
1094
1095 pdf.addPage(
1096 pw.Page(
1097 theme: theme,
1098 pageFormat: PdfPageFormat.a4,
1099 margin: const pw.EdgeInsets.all(16),
1100 build: (context) => pw.Column(
1101 crossAxisAlignment: pw.CrossAxisAlignment.start,
1102 children: [
1103 // Header with logo and title
1104 pw.Row(
1105 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
1106 children: [
1107 pw.Image(logoImage, width: 60, height: 60),
1108 pw.Column(
1109 crossAxisAlignment: pw.CrossAxisAlignment.center,
1110 children: [
1111 pw.Text(
1112 'Waste Electronic Manifest',
1113 style: pw.TextStyle(
1114 fontSize: 16,
1115 fontWeight: pw.FontWeight.bold,
1116 ),
1117 ),
1118 pw.Text(
1119 '(E-Manifest)',
1120 style: pw.TextStyle(
1121 fontSize: 14,
1122 fontWeight: pw.FontWeight.bold,
1123 ),
1124 ),
1125 ],
1126 ),
1127 pw.Column(
1128 crossAxisAlignment: pw.CrossAxisAlignment.end,
1129 children: [
1130 pw.Row(
1131 children: [
1132 pw.Text('Document No. ',
1133 style: pw.TextStyle(fontSize: 10)),
1134 pw.Text('${data?.id}',
1135 style:
1136 pw.TextStyle(fontSize: 10, color: PdfColors.red)),
1137 ],
1138 ),
1139 pw.Row(
1140 children: [
1141 pw.Text('Status : ', style: pw.TextStyle(fontSize: 10)),
1142 pw.Text('${adaptStatus(status: data?.status ?? '')}',
1143 style: pw.TextStyle(fontSize: 10)),
1144 ],
1145 ),
1146 pw.SizedBox(height: 5),
1147 pw.Container(
1148 width: 50,
1149 height: 50,
1150 child: pw.BarcodeWidget(
1151 barcode: pw.Barcode.qrCode(),
1152 data:
1153 'WASTE E-MANIFEST - Document No: ${data?.id} - Status: ${adaptStatus(status: data?.status ?? '')} - origin: Aidra Connect',
1154 width: 50,
1155 height: 50,
1156 ),
1157 ),
1158 ],
1159 ),
1160 ],
1161 ),
1162 pw.SizedBox(height: 15),
1163
1164 // Part A
1165 _buildSectionHeader(
1166 'Part - A : Waste Generator Information', headerBlue),
1167 pw.Table(
1168 border: pw.TableBorder.all(),
1169 columnWidths: {
1170 0: pw.FlexColumnWidth(1),
1171 1: pw.FlexColumnWidth(1),
1172 2: pw.FlexColumnWidth(1.5),
1173 },
1174 children: [
1175 pw.TableRow(
1176 children: [
1177 pw.Padding(
1178 padding: const pw.EdgeInsets.all(5),
1179 child: pw.Text('1.Generator ID. No',
1180 style: pw.TextStyle(fontSize: 10)),
1181 ),
1182 pw.Padding(
1183 padding: const pw.EdgeInsets.all(5),
1184 child: pw.Text('2. Generator\'s Name',
1185 style: pw.TextStyle(fontSize: 10)),
1186 ),
1187 pw.Padding(
1188 padding: const pw.EdgeInsets.all(5),
1189 child: pw.Text(
1190 '3. Generator\'s Address, Phone No.\nand Person To Contact',
1191 style: pw.TextStyle(fontSize: 10)),
1192 ),
1193 ],
1194 ),
1195 pw.TableRow(
1196 children: [
1197 pw.Padding(
1198 padding: const pw.EdgeInsets.all(5),
1199 child: pw.Text(data?.partner?.internalCode ?? '',
1200 style: pw.TextStyle(fontSize: 9)),
1201 ),
1202 pw.Padding(
1203 padding: const pw.EdgeInsets.all(5),
1204 child: pw.Text(data?.partner?.name ?? '',
1205 style: pw.TextStyle(fontSize: 9)),
1206 ),
1207 pw.Padding(
1208 padding: const pw.EdgeInsets.all(5),
1209 child: pw.Text(
1210 '${data?.partner?.street ?? ''}\n${data?.partner?.phone ?? ''}\n${data?.partner?.contactName ?? ''}',
1211 style: pw.TextStyle(fontSize: 9),
1212 ),
1213 ),
1214 ],
1215 ),
1216 // Add empty rows for the generator information section
1217 for (int i = 0; i < 7; i++)
1218 pw.TableRow(
1219 children: [
1220 pw.Container(height: 20),
1221 pw.Container(height: 20),
1222 pw.Container(height: 20),
1223 ],
1224 ),
1225 ],
1226 ),
1227
1228 // Transporter info
1229 pw.Container(
1230 padding: const pw.EdgeInsets.all(5),
1231 child: pw.Column(
1232 crossAxisAlignment: pw.CrossAxisAlignment.start,
1233 children: [
1234 pw.Text('4. Transporter\'s Name :',
1235 style: pw.TextStyle(fontSize: 10)),
1236 pw.Padding(
1237 padding: const pw.EdgeInsets.only(left: 10),
1238 child: pw.Text(data?.company?.partner?.name ?? '',
1239 style: pw.TextStyle(fontSize: 9)),
1240 ),
1241 pw.SizedBox(height: 5),
1242 pw.Text(' Mailing Address:',
1243 style: pw.TextStyle(fontSize: 10)),
1244 pw.Padding(
1245 padding: const pw.EdgeInsets.only(left: 10),
1246 child: pw.Text(data?.company?.partner?.street ?? '',
1247 style: pw.TextStyle(fontSize: 9)),
1248 ),
1249 pw.SizedBox(height: 5),
1250 pw.Row(
1251 children: [
1252 pw.Expanded(
1253 child: pw.Column(
1254 crossAxisAlignment: pw.CrossAxisAlignment.start,
1255 children: [
1256 pw.Text(' Tel. No:',
1257 style: pw.TextStyle(fontSize: 10)),
1258 pw.Padding(
1259 padding: const pw.EdgeInsets.only(left: 10),
1260 child: pw.Text(data?.company?.partner?.phone ?? '',
1261 style: pw.TextStyle(fontSize: 9)),
1262 ),
1263 ],
1264 ),
1265 ),
1266 pw.Expanded(
1267 child: pw.Column(
1268 crossAxisAlignment: pw.CrossAxisAlignment.start,
1269 children: [
1270 pw.Text(' Person to Contact:',
1271 style: pw.TextStyle(fontSize: 10)),
1272 pw.Padding(
1273 padding: const pw.EdgeInsets.only(left: 10),
1274 child: pw.Text(
1275 data?.partner?.salesPerson?.partnerId?.name ??
1276 '',
1277 style: pw.TextStyle(fontSize: 9)),
1278 ),
1279 ],
1280 ),
1281 ),
1282 ],
1283 ),
1284 ],
1285 ),
1286 ),
1287
1288 // Shipping Table
1289 pw.SizedBox(height: 10),
1290 _buildShippingTable(data: data),
1291
1292 // Generator's certification
1293 pw.Container(
1294 padding: const pw.EdgeInsets.all(8),
1295 decoration: pw.BoxDecoration(
1296 border: pw.Border.all(),
1297 ),
1298 child: pw.Column(
1299 crossAxisAlignment: pw.CrossAxisAlignment.start,
1300 children: [
1301 pw.Text(
1302 '10. Generator\'s Certification: I hereby declare that the containers of this consignment are fully and accurately described above by proper shipping name and classified, packed, and labelled, and are in all respect in proper condition for transport by highway according to applicable laws and regulations of the Kingdom.',
1303 style: pw.TextStyle(fontSize: 9),
1304 ),
1305 pw.SizedBox(height: 10),
1306 pw.Row(
1307 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
1308 children: [
1309 pw.Column(
1310 crossAxisAlignment: pw.CrossAxisAlignment.start,
1311 children: [
1312 pw.Text('Name of the Authorized Representative :',
1313 style: pw.TextStyle(fontSize: 9)),
1314 pw.SizedBox(height: 5),
1315 pw.Text(data?.partner?.contactName ?? '',
1316 style: pw.TextStyle(fontSize: 9)),
1317 pw.SizedBox(height: 10),
1318 pw.Text('Signature :',
1319 style: pw.TextStyle(fontSize: 9)),
1320 ],
1321 ),
1322 pw.Column(
1323 crossAxisAlignment: pw.CrossAxisAlignment.start,
1324 children: [
1325 pw.Text('Date:', style: pw.TextStyle(fontSize: 9)),
1326 pw.SizedBox(height: 5),
1327 pw.Text(_formatDate(data?.collectionDate),
1328 style: pw.TextStyle(fontSize: 9)),
1329 ],
1330 ),
1331 ],
1332 ),
1333 ],
1334 ),
1335 ),
1336 ],
1337 ),
1338 ),
1339 );
1340
1341 // Second page
1342 pdf.addPage(
1343 pw.Page(
1344 theme: theme,
1345 pageFormat: PdfPageFormat.a4,
1346 margin: const pw.EdgeInsets.all(16),
1347 build: (context) => pw.Column(
1348 crossAxisAlignment: pw.CrossAxisAlignment.start,
1349 children: [
1350 // Header with logo and title (repeated on second page)
1351 pw.Row(
1352 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
1353 children: [
1354 pw.Image(logoImage, width: 60, height: 60),
1355 pw.Column(
1356 crossAxisAlignment: pw.CrossAxisAlignment.center,
1357 children: [
1358 pw.Text(
1359 'Waste Electronic Manifest',
1360 style: pw.TextStyle(
1361 fontSize: 16,
1362 fontWeight: pw.FontWeight.bold,
1363 ),
1364 ),
1365 pw.Text(
1366 '(E-Manifest)',
1367 style: pw.TextStyle(
1368 fontSize: 14,
1369 fontWeight: pw.FontWeight.bold,
1370 ),
1371 ),
1372 ],
1373 ),
1374 pw.Column(
1375 crossAxisAlignment: pw.CrossAxisAlignment.end,
1376 children: [
1377 pw.Row(
1378 children: [
1379 pw.Text('Document No. ',
1380 style: pw.TextStyle(fontSize: 10)),
1381 pw.Text('${data?.id}',
1382 style:
1383 pw.TextStyle(fontSize: 10, color: PdfColors.red)),
1384 ],
1385 ),
1386 pw.Row(
1387 children: [
1388 pw.Text('Status : ', style: pw.TextStyle(fontSize: 10)),
1389 pw.Text('${adaptStatus(status: data?.status ?? '')}',
1390 style: pw.TextStyle(fontSize: 10)),
1391 ],
1392 ),
1393 pw.SizedBox(height: 5),
1394 pw.Container(
1395 width: 50,
1396 height: 50,
1397 child: pw.BarcodeWidget(
1398 barcode: pw.Barcode.qrCode(),
1399 data:
1400 'WASTE E-MANIFEST - Document No: ${data?.id} - Status: ${adaptStatus(status: data?.status ?? '')} - origin: Aidra Connect',
1401 width: 50,
1402 height: 50,
1403 ),
1404 ),
1405 ],
1406 ),
1407 ],
1408 ),
1409 pw.SizedBox(height: 15),
1410
1411 // Part B
1412 _buildSectionHeader(
1413 'Part - B : Transporter Informations', headerBlue),
1414 pw.Container(
1415 decoration: pw.BoxDecoration(
1416 border: pw.Border.all(),
1417 ),
1418 padding: const pw.EdgeInsets.all(8),
1419 child: pw.Column(
1420 crossAxisAlignment: pw.CrossAxisAlignment.start,
1421 children: [
1422 pw.Text(
1423 '11. Transporter\'s Acknowledgement of Receipt of Materials',
1424 style: pw.TextStyle(fontSize: 10)),
1425 pw.SizedBox(height: 10),
1426 pw.Row(
1427 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
1428 children: [
1429 pw.Column(
1430 crossAxisAlignment: pw.CrossAxisAlignment.start,
1431 children: [
1432 pw.Text('Driver Name:',
1433 style: pw.TextStyle(fontSize: 9)),
1434 pw.SizedBox(height: 5),
1435 pw.Text(data?.driver?.name ?? '',
1436 style: pw.TextStyle(fontSize: 9)),
1437 pw.SizedBox(height: 15),
1438 pw.Text('Signature of Drive:',
1439 style: pw.TextStyle(fontSize: 9)),
1440 ],
1441 ),
1442 pw.Column(
1443 crossAxisAlignment: pw.CrossAxisAlignment.start,
1444 children: [
1445 pw.Row(
1446 children: [
1447 pw.Text('Date:', style: pw.TextStyle(fontSize: 9)),
1448 pw.SizedBox(width: 10),
1449 pw.Text(
1450 _formatDate(
1451 data?.collectionVoucher?.confirmationDate),
1452 style: pw.TextStyle(fontSize: 9)),
1453 ],
1454 ),
1455 pw.SizedBox(height: 15),
1456 pw.Row(
1457 children: [
1458 pw.Text('Vehicle Plate No:',
1459 style: pw.TextStyle(fontSize: 9)),
1460 pw.SizedBox(width: 10),
1461 pw.Text(data?.vehiclePlate ?? '',
1462 style: pw.TextStyle(fontSize: 9)),
1463 ],
1464 ),
1465 ],
1466 ),
1467 ],
1468 ),
1469 ],
1470 ),
1471 ),
1472
1473 // Part C
1474 pw.SizedBox(height: 15),
1475 _buildSectionHeader(
1476 'Part - C : Warehouse Facility Information', headerBlue),
1477 pw.Container(
1478 decoration: pw.BoxDecoration(
1479 border: pw.Border.all(),
1480 ),
1481 child: pw.Column(
1482 children: [
1483 pw.Container(
1484 width: double.infinity,
1485 padding: const pw.EdgeInsets.all(8),
1486 decoration: pw.BoxDecoration(
1487 border: pw.Border(bottom: pw.BorderSide()),
1488 ),
1489 child: pw.Text('12. Discrepancy Indication Space',
1490 style: pw.TextStyle(fontSize: 9)),
1491 ),
1492 pw.Container(
1493 padding: const pw.EdgeInsets.all(8),
1494 child: pw.Column(
1495 crossAxisAlignment: pw.CrossAxisAlignment.start,
1496 children: [
1497 pw.Row(
1498 children: [
1499 pw.Expanded(
1500 child: pw.Text(
1501 '13. Facility Owner/Operator: certification of material covered by this manifest except as noted in item',
1502 style: pw.TextStyle(fontSize: 9),
1503 ),
1504 ),
1505 pw.SizedBox(width: 10),
1506 pw.Text('Date:', style: pw.TextStyle(fontSize: 9)),
1507 ],
1508 ),
1509 pw.SizedBox(height: 20),
1510 pw.Row(
1511 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
1512 children: [
1513 pw.Column(
1514 crossAxisAlignment: pw.CrossAxisAlignment.start,
1515 children: [
1516 pw.Text('Receiver Name',
1517 style: pw.TextStyle(fontSize: 9)),
1518 ],
1519 ),
1520 pw.Column(
1521 crossAxisAlignment: pw.CrossAxisAlignment.start,
1522 children: [
1523 pw.Text('Signature',
1524 style: pw.TextStyle(fontSize: 9)),
1525 ],
1526 ),
1527 ],
1528 ),
1529 ],
1530 ),
1531 ),
1532 ],
1533 ),
1534 ),
1535
1536 // Footer
1537 pw.Spacer(),
1538 pw.Align(
1539 alignment: pw.Alignment.bottomRight,
1540 child: pw.Text(
1541 'POWERED BY\nAidra Connect',
1542 style: pw.TextStyle(fontSize: 8, color: PdfColors.grey),
1543 textAlign: pw.TextAlign.right,
1544 ),
1545 ),
1546 ],
1547 ),
1548 ),
1549 );
1550
1551 final output = await getTemporaryDirectory();
1552 final file = File('${output.path}/E-Manifest_$collectionName.pdf');
1553 await file.writeAsBytes(await pdf.save());
1554
1555 OpenFilex.open(file.path);
1556}
1557
1558pw.Widget _buildSectionHeader(String title, PdfColor color) {
1559 return pw.Container(
1560 width: double.infinity,
1561 color: color,
1562 padding: const pw.EdgeInsets.symmetric(vertical: 4, horizontal: 10),
1563 margin: const pw.EdgeInsets.only(bottom: 5),
1564 child: pw.Text(
1565 title,
1566 style: pw.TextStyle(
1567 fontSize: 11,
1568 fontWeight: pw.FontWeight.bold,
1569 ),
1570 ),
1571 );
1572}
1573
1574pw.Widget _buildShippingTable({required MainifestEntity? data}) {
1575 return pw.Table(
1576 border: pw.TableBorder.all(),
1577 columnWidths: {
1578 0: pw.FlexColumnWidth(2),
1579 1: pw.FlexColumnWidth(1),
1580 2: pw.FlexColumnWidth(1),
1581 3: pw.FlexColumnWidth(1),
1582 4: pw.FlexColumnWidth(1),
1583 },
1584 children: [
1585 // Header row
1586 pw.TableRow(
1587 decoration: pw.BoxDecoration(color: PdfColors.blue50),
1588 children: [
1589 pw.Padding(
1590 padding: const pw.EdgeInsets.all(5),
1591 child: pw.Text(
1592 '5.(Shipping Name, Hazard Class, and PIN)',
1593 style: pw.TextStyle(fontSize: 9),
1594 ),
1595 ),
1596 pw.Column(
1597 children: [
1598 pw.Container(
1599 alignment: pw.Alignment.center,
1600 padding: const pw.EdgeInsets.all(5),
1601 decoration: pw.BoxDecoration(
1602 border: pw.Border(bottom: pw.BorderSide()),
1603 ),
1604 child: pw.Text(
1605 '6.Containers',
1606 style: pw.TextStyle(fontSize: 9),
1607 ),
1608 ),
1609 pw.Row(
1610 children: [
1611 pw.Expanded(
1612 child: pw.Container(
1613 alignment: pw.Alignment.center,
1614 padding: const pw.EdgeInsets.all(5),
1615 decoration: pw.BoxDecoration(
1616 border: pw.Border(right: pw.BorderSide()),
1617 ),
1618 child: pw.Text('No.', style: pw.TextStyle(fontSize: 9)),
1619 ),
1620 ),
1621 pw.Expanded(
1622 child: pw.Container(
1623 alignment: pw.Alignment.center,
1624 padding: const pw.EdgeInsets.all(5),
1625 child: pw.Text('Type', style: pw.TextStyle(fontSize: 9)),
1626 ),
1627 ),
1628 ],
1629 ),
1630 ],
1631 ),
1632 pw.Container(
1633 alignment: pw.Alignment.center,
1634 padding: const pw.EdgeInsets.all(5),
1635 child: pw.Text('7.Total Qty', style: pw.TextStyle(fontSize: 9)),
1636 ),
1637 pw.Container(
1638 alignment: pw.Alignment.center,
1639 padding: const pw.EdgeInsets.all(5),
1640 child: pw.Text('8.Unit Wt/Vol', style: pw.TextStyle(fontSize: 9)),
1641 ),
1642 pw.Container(
1643 alignment: pw.Alignment.center,
1644 padding: const pw.EdgeInsets.all(5),
1645 child: pw.Text('9.WPS No.', style: pw.TextStyle(fontSize: 9)),
1646 ),
1647 ],
1648 ),
1649 // Data row
1650 pw.TableRow(
1651 children: [
1652 pw.Padding(
1653 padding: const pw.EdgeInsets.all(5),
1654 child: pw.Text(extractName(data?.productName),
1655 style: pw.TextStyle(fontSize: 9)),
1656 ),
1657 pw.Row(
1658 children: [
1659 pw.Expanded(
1660 child: pw.Container(
1661 alignment: pw.Alignment.center,
1662 padding: const pw.EdgeInsets.all(5),
1663 decoration: pw.BoxDecoration(
1664 border: pw.Border(right: pw.BorderSide()),
1665 ),
1666 child: pw.Text('${data?.containerNumber ?? ""}',
1667 style: pw.TextStyle(fontSize: 9)),
1668 ),
1669 ),
1670 pw.Expanded(
1671 child: pw.Container(
1672 alignment: pw.Alignment.center,
1673 padding: const pw.EdgeInsets.all(5),
1674 child: pw.Text('${data?.containerType ?? ""}',
1675 style: pw.TextStyle(fontSize: 9)),
1676 ),
1677 ),
1678 ],
1679 ),
1680 pw.Container(
1681 alignment: pw.Alignment.center,
1682 padding: const pw.EdgeInsets.all(5),
1683 child: pw.Text(
1684 '${NumberConversionService.convertAndFormatWeight(data?.totalQuantity)}',
1685 style: pw.TextStyle(fontSize: 9)),
1686 ),
1687 pw.Container(
1688 alignment: pw.Alignment.center,
1689 padding: const pw.EdgeInsets.all(5),
1690 child: pw.Text('Kg', style: pw.TextStyle(fontSize: 9)),
1691 ),
1692 pw.Container(
1693 alignment: pw.Alignment.center,
1694 padding: const pw.EdgeInsets.all(5),
1695 child: pw.Text('', style: pw.TextStyle(fontSize: 9)),
1696 ),
1697 ],
1698 ),
1699 // Add empty row for potential additional items
1700 pw.TableRow(
1701 children: [
1702 pw.Container(height: 25),
1703 pw.Row(
1704 children: [
1705 pw.Expanded(
1706 child: pw.Container(
1707 height: 25,
1708 decoration: pw.BoxDecoration(
1709 border: pw.Border(right: pw.BorderSide()),
1710 ),
1711 ),
1712 ),
1713 pw.Expanded(
1714 child: pw.Container(height: 25),
1715 ),
1716 ],
1717 ),
1718 pw.Container(height: 25),
1719 pw.Container(height: 25),
1720 pw.Container(height: 25),
1721 ],
1722 ),
1723 ],
1724 );
1725}
1726
1727String extractName(String? productName) {
1728 if (productName == null || productName.isEmpty) {
1729 return '';
1730 }
1731
1732 try {
1733 final Map<String, dynamic> decoded = jsonDecode(productName);
1734 return decoded['en_US'] ?? '';
1735 } catch (e) {
1736 return productName;
1737 }
1738}
1739
1740Future<MainifestEntity?>? fetchData({required String collectionName}) async {
1741 try {
1742 final apiClient = sl<ApiClient>();
1743 final response = await apiClient.get(
1744 '',
1745 {},
1746 false,
1747 'https://dev-api.aidra.tech/document/ManifestDocument/$collectionName',
1748 );
1749 if (response == {}) {
1750 return null;
1751 }
1752 log(response.toString());
1753 return MainifestEntity.fromJson(response);
1754 } catch (e) {
1755 print(e);
1756 return null;
1757 }
1758}
1759
1760class MainifestEntity {
1761 final DateTime? collectionDate;
1762 final CollectionVoucher? collectionVoucher;
1763 final Company? company;
1764 final String? containerNumber;
1765 final String? containerType;
1766 final Partner? driver;
1767 final String? generatorId;
1768 final int? id;
1769 final Partner? partner;
1770 final String? productName;
1771 final String? status;
1772 final int? totalQuantity;
1773 final String? uom;
1774 final String? vehiclePlate;
1775
1776 MainifestEntity({
1777 this.collectionDate,
1778 this.collectionVoucher,
1779 this.company,
1780 this.containerNumber,
1781 this.containerType,
1782 this.driver,
1783 this.generatorId,
1784 this.id,
1785 this.partner,
1786 this.productName,
1787 this.status,
1788 this.totalQuantity,
1789 this.uom,
1790 this.vehiclePlate,
1791 });
1792
1793 factory MainifestEntity.fromJson(Map<String, dynamic> json) {
1794 return MainifestEntity(
1795 collectionDate: json['collectionDate'] != null
1796 ? DateTime.parse(json['collectionDate'])
1797 : null,
1798 collectionVoucher: json['collectionVoucher'] != null
1799 ? CollectionVoucher.fromJson(json['collectionVoucher'])
1800 : null,
1801 company:
1802 json['company'] != null ? Company.fromJson(json['company']) : null,
1803 containerNumber: json['containerNumber'],
1804 containerType: json['containerType'],
1805 driver: json['driver'] != null ? Partner.fromJson(json['driver']) : null,
1806 generatorId: json['generatorId'],
1807 id: json['id'],
1808 partner:
1809 json['partner'] != null ? Partner.fromJson(json['partner']) : null,
1810 productName: json['productName'],
1811 status: json['status'],
1812 totalQuantity: json['totalQuantity'],
1813 uom: json['uom'],
1814 vehiclePlate: json['vehiclePlate'],
1815 );
1816 }
1817
1818 Map<String, dynamic> toJson() {
1819 final Map<String, dynamic> data = <String, dynamic>{};
1820 if (collectionDate != null) {
1821 data['collectionDate'] = collectionDate!.toIso8601String();
1822 }
1823 if (collectionVoucher != null) {
1824 data['collectionVoucher'] = collectionVoucher!.toJson();
1825 }
1826 if (company != null) {
1827 data['company'] = company!.toJson();
1828 }
1829 data['containerNumber'] = containerNumber;
1830 data['containerType'] = containerType;
1831 if (driver != null) {
1832 data['driver'] = driver!.toJson();
1833 }
1834 data['generatorId'] = generatorId;
1835 data['id'] = id;
1836 if (partner != null) {
1837 data['partner'] = partner!.toJson();
1838 }
1839 data['productName'] = productName;
1840 data['status'] = status;
1841 data['totalQuantity'] = totalQuantity;
1842 data['uom'] = uom;
1843 data['vehiclePlate'] = vehiclePlate;
1844 return data;
1845 }
1846}
1847
1848class CollectionVoucher {
1849 final String? billStatus;
1850 final String? collectionConfirmRef;
1851 final String? collectionOrderRef;
1852 final DateTime? confirmationDate;
1853 final double? cvAmountTotal;
1854 final int? id;
1855 final String? name;
1856 final String? paymentBillRef;
1857 final String? receiptStatus;
1858 final String? status;
1859
1860 CollectionVoucher({
1861 this.billStatus,
1862 this.collectionConfirmRef,
1863 this.collectionOrderRef,
1864 this.confirmationDate,
1865 this.cvAmountTotal,
1866 this.id,
1867 this.name,
1868 this.paymentBillRef,
1869 this.receiptStatus,
1870 this.status,
1871 });
1872
1873 factory CollectionVoucher.fromJson(Map<String, dynamic> json) {
1874 return CollectionVoucher(
1875 billStatus: json['billStatus'],
1876 collectionConfirmRef: json['collectionConfirmRef'],
1877 collectionOrderRef: json['collectionOrderRef'],
1878 confirmationDate: json['confirmationDate'] != null
1879 ? DateTime.parse(json['confirmationDate'])
1880 : null,
1881 cvAmountTotal: json['cvAmountTotal']?.toDouble(),
1882 id: json['id'],
1883 name: json['name'],
1884 paymentBillRef: json['paymentBillRef'],
1885 receiptStatus: json['receiptStatus'],
1886 status: json['status'],
1887 );
1888 }
1889
1890 Map<String, dynamic> toJson() {
1891 final Map<String, dynamic> data = <String, dynamic>{};
1892 data['billStatus'] = billStatus;
1893 data['collectionConfirmRef'] = collectionConfirmRef;
1894 data['collectionOrderRef'] = collectionOrderRef;
1895 if (confirmationDate != null) {
1896 data['confirmationDate'] = confirmationDate!.toIso8601String();
1897 }
1898 data['cvAmountTotal'] = cvAmountTotal;
1899 data['id'] = id;
1900 data['name'] = name;
1901 data['paymentBillRef'] = paymentBillRef;
1902 data['receiptStatus'] = receiptStatus;
1903 data['status'] = status;
1904 return data;
1905 }
1906}
1907
1908class Company {
1909 final int? id;
1910 final String? name;
1911 final Partner? partner;
1912
1913 Company({
1914 this.id,
1915 this.name,
1916 this.partner,
1917 });
1918
1919 factory Company.fromJson(Map<String, dynamic> json) {
1920 return Company(
1921 id: json['id'],
1922 name: json['name'],
1923 partner:
1924 json['partner'] != null ? Partner.fromJson(json['partner']) : null,
1925 );
1926 }
1927
1928 Map<String, dynamic> toJson() {
1929 final Map<String, dynamic> data = <String, dynamic>{};
1930 data['id'] = id;
1931 data['name'] = name;
1932 if (partner != null) {
1933 data['partner'] = partner!.toJson();
1934 }
1935 return data;
1936 }
1937}
1938
1939class Partner {
1940 final String? contactName;
1941 final int? id;
1942 final String? internalCode;
1943 final bool? isCompany;
1944 final double? monthlyCapacity;
1945 final String? name;
1946 final int? parentId;
1947 final String? partnerLatitude;
1948 final String? partnerLongitude;
1949 final String? phone;
1950 final SalesPerson? salesPerson;
1951 final String? street;
1952 final double? tokenTotalValue;
1953
1954 Partner({
1955 this.contactName,
1956 this.id,
1957 this.internalCode,
1958 this.isCompany,
1959 this.monthlyCapacity,
1960 this.name,
1961 this.parentId,
1962 this.partnerLatitude,
1963 this.partnerLongitude,
1964 this.phone,
1965 this.salesPerson,
1966 this.street,
1967 this.tokenTotalValue,
1968 });
1969
1970 factory Partner.fromJson(Map<String, dynamic> json) {
1971 return Partner(
1972 contactName: json['contactName'],
1973 id: json['id'],
1974 internalCode: json['internalCode'],
1975 isCompany: json['isCompany'],
1976 monthlyCapacity: json['monthlyCapacity']?.toDouble(),
1977 name: json['name'],
1978 parentId: json['parentId'],
1979 partnerLatitude: json['partnerLatitude'],
1980 partnerLongitude: json['partnerLongitude'],
1981 phone: json['phone'],
1982 salesPerson: json['salesPerson'] != null
1983 ? SalesPerson.fromJson(json['salesPerson'])
1984 : null,
1985 street: json['street'],
1986 tokenTotalValue: json['tokenTotalValue']?.toDouble(),
1987 );
1988 }
1989
1990 Map<String, dynamic> toJson() {
1991 final Map<String, dynamic> data = <String, dynamic>{};
1992 data['contactName'] = contactName;
1993 data['id'] = id;
1994 data['internalCode'] = internalCode;
1995 data['isCompany'] = isCompany;
1996 data['monthlyCapacity'] = monthlyCapacity;
1997 data['name'] = name;
1998 data['parentId'] = parentId;
1999 data['partnerLatitude'] = partnerLatitude;
2000 data['partnerLongitude'] = partnerLongitude;
2001 data['phone'] = phone;
2002 if (salesPerson != null) {
2003 data['salesPerson'] = salesPerson!.toJson();
2004 }
2005 data['street'] = street;
2006 data['tokenTotalValue'] = tokenTotalValue;
2007 return data;
2008 }
2009}
2010
2011class SalesPerson {
2012 final Company? company;
2013 final int? id;
2014 final PartnerId? partnerId;
2015
2016 SalesPerson({
2017 this.company,
2018 this.id,
2019 this.partnerId,
2020 });
2021
2022 factory SalesPerson.fromJson(Map<String, dynamic> json) {
2023 return SalesPerson(
2024 company:
2025 json['company'] != null ? Company.fromJson(json['company']) : null,
2026 id: json['id'],
2027 partnerId: json['partnerId'] != null
2028 ? PartnerId.fromJson(json['partnerId'])
2029 : null,
2030 );
2031 }
2032
2033 Map<String, dynamic> toJson() {
2034 final Map<String, dynamic> data = <String, dynamic>{};
2035 if (company != null) {
2036 data['company'] = company!.toJson();
2037 }
2038 data['id'] = id;
2039 if (partnerId != null) {
2040 data['partnerId'] = partnerId!.toJson();
2041 }
2042 return data;
2043 }
2044}
2045
2046class PartnerId {
2047 final int? id;
2048 final bool? isCompany;
2049 final double? monthlyCapacity;
2050 final String? name;
2051 final String? partnerLatitude;
2052 final String? partnerLongitude;
2053 final double? tokenTotalValue;
2054
2055 PartnerId({
2056 this.id,
2057 this.isCompany,
2058 this.monthlyCapacity,
2059 this.name,
2060 this.partnerLatitude,
2061 this.partnerLongitude,
2062 this.tokenTotalValue,
2063 });
2064
2065 factory PartnerId.fromJson(Map<String, dynamic> json) {
2066 return PartnerId(
2067 id: json['id'],
2068 isCompany: json['isCompany'],
2069 monthlyCapacity: json['monthlyCapacity']?.toDouble(),
2070 name: json['name'],
2071 partnerLatitude: json['partnerLatitude'],
2072 partnerLongitude: json['partnerLongitude'],
2073 tokenTotalValue: json['tokenTotalValue']?.toDouble(),
2074 );
2075 }
2076
2077 Map<String, dynamic> toJson() {
2078 final Map<String, dynamic> data = <String, dynamic>{};
2079 data['id'] = id;
2080 data['isCompany'] = isCompany;
2081 data['monthlyCapacity'] = monthlyCapacity;
2082 data['name'] = name;
2083 data['partnerLatitude'] = partnerLatitude;
2084 data['partnerLongitude'] = partnerLongitude;
2085 data['tokenTotalValue'] = tokenTotalValue;
2086 return data;
2087 }
2088}
static const String tajmieLogo
Definition assets.dart:35
factory CurrencyModel fromJson(Map< String, dynamic > json)
final num partnerId
class CurrencyEntity id
class ResCountryStateEntity company
final String name
final Widget child
final EdgeInsets padding
final Color backgroundColor
final Color color
Definition failures.dart:1
final String message
Definition failures.dart:0
Future generateManifest({ required BuildContext context, required String collectionName, }) async
Future< CollectionVoucherDocumentModel?> fetchData({required String collectionName}) async
override Widget build(BuildContext context)
final sl
Map< String, dynamic > toJson()
final String title