Aidra Connect 10.0.2+16
Aidra Connect Mobile Application
Loading...
Searching...
No Matches
transaction_card_details.dart
Go to the documentation of this file.
1import 'package:connect/core/localization/app_localizations.dart';
2import 'package:connect/features/collections/presentation/screens/transaction_history_screen/views/competed_transactions_view/views/transactions_summary_view/widgets/generate_mainifest_pdf.dart';
3import 'package:connect/features/collections/presentation/screens/transaction_history_screen/views/competed_transactions_view/views/transactions_summary_view/widgets/generate_voucher.dart';
4import 'package:flutter/services.dart';
5import '../../../../../../../../../../core/constants/assets.dart';
6import '../../../../../../../../../../core/utils/number_conversion.dart';
7import '/core/ui/widgets/custom_card.dart';
8import '/features/collections/domain/entities/collection_entity.dart';
9import 'package:flutter/material.dart';
10import 'package:flutter_screenutil/flutter_screenutil.dart';
11import 'package:flutter_svg/svg.dart';
12import 'package:hugeicons/hugeicons.dart';
13import 'package:intl/intl.dart';
14
15import 'dart:io';
16import 'package:path_provider/path_provider.dart';
17import 'package:pdf/pdf.dart';
18import 'package:pdf/widgets.dart' as pw;
19import 'package:open_filex/open_filex.dart';
20
21import 'package:percent_indicator/circular_percent_indicator.dart';
22
23class TransactionCardDetails extends StatelessWidget {
25 super.key,
26 required this.collection,
27 });
28
30
31 @override
32 Widget build(BuildContext context) {
33 return SafeArea(
34 child: Container(
35 padding: EdgeInsets.only(top: 2.sp),
36 decoration: BoxDecoration(
37 color: Theme.of(context).colorScheme.primary,
38 borderRadius: BorderRadius.circular(20),
39 ),
41 padding: EdgeInsets.symmetric(horizontal: 15.sp, vertical: 15.sp),
42 child: SingleChildScrollView(
43 child: Column(
44 mainAxisSize: MainAxisSize.min,
45 crossAxisAlignment: CrossAxisAlignment.start,
46 children: [
47 Container(
48 width: MediaQuery.of(context).size.width,
49 padding:
50 EdgeInsets.symmetric(vertical: 16.sp, horizontal: 25.sp),
51 decoration: BoxDecoration(
52 borderRadius: BorderRadius.circular(200.sp),
53 gradient: LinearGradient(
54 colors: [
55 Theme.of(context).colorScheme.surface.withOpacity(0.11),
56 Theme.of(context).colorScheme.primary.withOpacity(0.11),
57 ],
58 ),
59 ),
60 child: Row(
61 mainAxisAlignment: MainAxisAlignment.spaceBetween,
62 children: [
63 SizedBox(),
64 SvgPicture.asset(
65 'assets/svgs/logo_aidra.svg',
66 height: 18.sp,
67 colorFilter: ColorFilter.mode(
68 Theme.of(context).colorScheme.primary,
69 BlendMode.srcIn),
70 ),
71 ],
72 ),
73 ),
74 // SizedBox(height: 15.sp),
75 // Divider(height: 0.0),
76 SizedBox(height: 20.sp),
77 Wrap(
78 spacing: 40.sp,
79 runSpacing: 20.sp,
80 children: [
82 size: MainAxisSize.max,
83 context: context,
84 icon: HugeIcons.strokeRoundedBinaryCode,
85 label: AppLocalizations.of(context)
86 .translate('CR Reference'),
87 info: collection.name,
88 ),
90 context: context,
91 icon: HugeIcons.strokeRoundedCalendar01,
92 label:
93 AppLocalizations.of(context).translate('Order Date'),
94 info: collection.dateOrder != null
95 ? DateFormat('yyyy-MM-dd')
96 .format(collection.dateOrder!)
97 : AppLocalizations.of(context)
98 .translate('No date available'),
99 ),
101 context: context,
102 icon: HugeIcons.strokeRoundedWeightScale01,
103 label: AppLocalizations.of(context).translate('Quantity'),
105 collection.orderLines?.first.productQty,
106 ),
107 // info:
108 // '${NumberFormat.compact().format(collection.orderLines?.first.productQty)} ${extractKg(collection.orderLines?.first.productUom?.name)}',
109 ),
110 ],
111 ),
112 SizedBox(height: 15.sp),
114 context: context,
115 icon: HugeIcons.strokeRoundedEqualSignCircle,
116 label: AppLocalizations.of(context).translate('Instructions'),
117 info: collection.instruction,
118 ),
119 SizedBox(height: 15.sp),
120 Divider(height: 0.0),
121 SizedBox(height: 5.sp),
122 Padding(
123 padding: EdgeInsets.symmetric(horizontal: 15.sp),
124 child: Row(
125 mainAxisAlignment: MainAxisAlignment.spaceBetween,
126 children: [
127 Column(
128 children: [
129 Icon(
130 HugeIcons.strokeRoundedCoins01,
131 color: Theme.of(context).colorScheme.primary,
132 ),
133 SizedBox(height: 13.sp),
134 Text(
135 NumberFormat.currency(
136 symbol: collection.currency?.symbol ?? '',
137 ).format(
138 collection.orderLines?.first.priceTotal ?? 0),
139 textAlign: TextAlign.center,
140 ),
141 SizedBox(height: 5.sp),
142 Text(
143 AppLocalizations.of(context)
144 .translate('You have Earned'),
145 textAlign: TextAlign.center,
146 style:
147 Theme.of(context).textTheme.bodySmall?.copyWith(
148 fontSize: 10.sp,
149 color: Theme.of(context).hintColor,
150 ),
151 ),
152 ],
153 ),
155 label: AppLocalizations.of(context)
156 .translate('Collected Vs Declared'),
157 context: context,
158 received: collection.orderLines?.first.qtyReceived ?? 0,
159 qty: collection.orderLines?.first.productQty ?? 0,
160 ),
161 ],
162 ),
163 ),
164 SizedBox(height: 5.sp),
165 Divider(height: 0.0),
166 SizedBox(height: 15.sp),
167
168 SizedBox(
169 width: MediaQuery.of(context).size.width,
170 child: ElevatedButton(
171 style: ElevatedButton.styleFrom(
172 backgroundColor: Colors.transparent,
173 foregroundColor: Theme.of(context).colorScheme.primary,
174 padding: EdgeInsets.symmetric(
175 horizontal: 15.sp,
176 vertical: 16.sp,
177 ),
178 shape: RoundedRectangleBorder(
179 borderRadius: BorderRadius.circular(200),
180 side: BorderSide(
181 color: Theme.of(context).colorScheme.primary,
182 width: 0.5,
183 ),
184 ),
185 ),
186 child: Row(
187 mainAxisAlignment: MainAxisAlignment.center,
188 children: [
189 Icon(HugeIcons.strokeRoundedDownload05),
190 SizedBox(width: 5.sp),
191 Text(
192 AppLocalizations.of(context)
193 .translate('Download Voucher'),
194 style: Theme.of(context)
195 .textTheme
196 .bodySmall
197 ?.copyWith(
198 color: Theme.of(context).colorScheme.primary,
199 ),
200 ),
201 ],
202 ),
203 onPressed: () {
204 generateCollectionVoucher(collection.name ?? '', context);
205 },
206 ),
207 ),
208 // SizedBox(height: 12.sp),
209 // SizedBox(
210 // width: MediaQuery.of(context).size.width,
211 // child: ElevatedButton(
212 // style: ElevatedButton.styleFrom(
213 // backgroundColor: Colors.transparent,
214 // foregroundColor: Theme.of(context).colorScheme.primary,
215 // padding: EdgeInsets.symmetric(
216 // horizontal: 15.sp,
217 // vertical: 16.sp,
218 // ),
219 // shape: RoundedRectangleBorder(
220 // borderRadius: BorderRadius.circular(200),
221 // side: BorderSide(
222 // color: Theme.of(context).colorScheme.primary,
223 // width: 0.5,
224 // ),
225 // ),
226 // ),
227 // child: Row(
228 // mainAxisAlignment: MainAxisAlignment.center,
229 // children: [
230 // Icon(HugeIcons.strokeRoundedDownload05),
231 // SizedBox(width: 5.sp),
232 // Text(
233 // 'Download E-Manifest',
234 // style: Theme.of(context)
235 // .textTheme
236 // .bodySmall
237 // ?.copyWith(
238 // color: Theme.of(context).colorScheme.primary,
239 // ),
240 // ),
241 // ],
242 // ),
243 // onPressed: () {
244 // generateManifest(
245 // context: context,
246 // collectionName: collection.name ?? '',
247 // );
248 // },
249 // ),
250 // ),
251 ],
252 ),
253 ),
254 ),
255 ),
256 );
257 }
258
260 required BuildContext context,
261 IconData? icon,
262 required String label,
263 required String? info,
264 MainAxisSize? size,
265 }) {
266 return Padding(
267 padding: EdgeInsets.symmetric(horizontal: 7.sp),
268 child: Row(
269 mainAxisSize: size ?? MainAxisSize.min,
270 children: [
271 icon == null
272 ? const SizedBox()
273 : Container(
274 decoration: BoxDecoration(
275 color:
276 Theme.of(context).colorScheme.primary.withOpacity(0.11),
277 borderRadius: BorderRadius.circular(10),
278 ),
279 padding: EdgeInsets.all(9.sp),
280 child: Icon(
281 icon,
282 color: Theme.of(context).colorScheme.primary,
283 size: 18.sp,
284 ),
285 ),
286 SizedBox(width: 15.sp),
287 Column(
288 mainAxisSize: MainAxisSize.min,
289 crossAxisAlignment: CrossAxisAlignment.start,
290 children: [
291 Opacity(
292 opacity: 0.7,
293 child: Text(
294 label,
295 style: Theme.of(context).textTheme.bodySmall,
296 ),
297 ),
298 SizedBox(height: 3.sp),
299 Flexible(
300 child: Text(
301 info ?? AppLocalizations.of(context).translate('Not Found'),
302 style: Theme.of(context).textTheme.bodySmall,
303 ),
304 ),
305 ],
306 ),
307 ],
308 ),
309 );
310 }
311
313 required String label,
314 required BuildContext context,
315 required num received,
316 required num qty,
317 }) {
318 // Calculate percentage based on received and qty, capped at 100%.
319 double percentageValue = (qty > 0) ? (received / qty) : 0.0;
320 percentageValue = percentageValue > 1.0 ? 1.0 : percentageValue;
321
322 return Container(
323 padding: EdgeInsets.all(10.sp),
324 decoration: BoxDecoration(
325 borderRadius: BorderRadius.circular(10),
326 ),
327 child: Column(
328 crossAxisAlignment: CrossAxisAlignment.center,
329 children: [
330 CircularPercentIndicator(
331 radius: 25.sp,
332 lineWidth: 4,
333 percent: percentageValue,
334 center: Text(
335 '${(percentageValue * 100).toStringAsFixed(0)}%',
336 style: Theme.of(context).textTheme.bodySmall?.copyWith(
337 fontSize: 10.sp,
338 ),
339 ),
340 progressColor: Theme.of(context).colorScheme.primary,
342 Theme.of(context).colorScheme.primary.withOpacity(0.11),
343 ),
344 SizedBox(height: 10.sp),
345 Text(
346 label,
347 textAlign: TextAlign.center,
348 style: Theme.of(context).textTheme.bodySmall?.copyWith(
349 fontSize: 10.sp,
350 color: Theme.of(context).hintColor,
351 ),
352 ),
353 ],
354 ),
355 );
356 }
357
358 Future<void> generatePDF({
360 }) async {
361 final pdf = pw.Document();
362
363 final qrCode = pw.BarcodeWidget(
364 barcode: pw.Barcode.qrCode(),
365 data: collection.name ?? '',
366 width: 80,
367 height: 80,
368 );
369
370 final directorSignature = pw.Column(
371 children: [
372 pw.Text(
373 'Driver / Collector : Ali Iftikar',
374 ),
375 pw.Container(
376 width: 100,
377 height: 100,
378 child: pw.Center(
379 child: pw.Image(
380 pw.MemoryImage(
381 (await rootBundle.load(Assets.collectorSign))
382 .buffer
383 .asUint8List(),
384 ),
385 fit: pw.BoxFit.contain,
386 ),
387 ),
388 ),
389 ],
390 );
391 final collectorSignature = pw.Column(
392 children: [
393 pw.Text(
394 'Collection Point : Shah waqar',
395 ),
396 pw.Container(
397 width: 100,
398 height: 100,
399 child: pw.Center(
400 child: pw.Image(
401 pw.MemoryImage(
402 (await rootBundle.load(Assets.directorSign))
403 .buffer
404 .asUint8List(),
405 ),
406 fit: pw.BoxFit.contain,
407 ),
408 ),
409 ),
410 ],
411 );
412
413 pdf.addPage(
414 pw.Page(
415 build: (context) {
416 return pw.Column(
417 crossAxisAlignment: pw.CrossAxisAlignment.center,
418 children: [
419 pw.Text(
420 'Collection Voucher',
421 ),
422 pw.SizedBox(height: 8),
423 pw.Text(
424 'Document Number : ${collection.name}',
425 style: pw.TextStyle(
426 fontSize: 24, fontWeight: pw.FontWeight.normal),
427 ),
428 pw.SizedBox(height: 30),
429 pw.Column(
430 crossAxisAlignment: pw.CrossAxisAlignment.start,
431 children: [
432 pw.Text(
433 'Name: Buffalo Wings & Rings - DIFC',
434 style: pw.TextStyle(
435 fontSize: 20, fontWeight: pw.FontWeight.normal),
436 ),
437 pw.SizedBox(height: 8),
438 pw.Text(
439 'Address: Liberty House - Level C - Al Sukouk Street - DIFC Dubai, United Arab Emirates',
440 style: pw.TextStyle(
441 fontSize: 20, fontWeight: pw.FontWeight.normal),
442 ),
443 ],
444 ),
445 pw.SizedBox(height: 30),
446 pw.Table(
447 border: pw.TableBorder.all(),
448 children: [
449 pw.TableRow(
450 children: [
451 pw.Container(
452 padding: const pw.EdgeInsets.all(8),
453 child: pw.Text(
454 'Collection Date',
455 ),
456 ),
457 pw.Container(
458 padding: const pw.EdgeInsets.all(8),
459 child: pw.Text('9/12/2024'),
460 ),
461 pw.Container(
462 padding: const pw.EdgeInsets.all(8),
463 child: pw.Text(
464 'Payment Bill Ref',
465 ),
466 ),
467 pw.Container(
468 padding: const pw.EdgeInsets.all(8),
469 child: pw.Text('BILL/202411/27/0006'),
470 ),
471 ],
472 ),
473 pw.TableRow(
474 children: [
475 pw.Container(
476 padding: const pw.EdgeInsets.all(8),
477 child: pw.Text(
478 'Collection Order Ref',
479 ),
480 ),
481 pw.Container(
482 padding: const pw.EdgeInsets.all(8),
483 child: pw.Text('${collection.name}/INV2024'),
484 ),
485 pw.Container(
486 padding: const pw.EdgeInsets.all(8),
487 child: pw.Text(
488 'Payment Method',
489 ),
490 ),
491 pw.Container(
492 padding: const pw.EdgeInsets.all(8),
493 child: pw.Text('CASH'),
494 ),
495 ],
496 ),
497 pw.TableRow(
498 children: [
499 pw.Container(
500 padding: const pw.EdgeInsets.all(8),
501 child: pw.Text(
502 'Collection Confirmation Ref',
503 ),
504 ),
505 pw.Container(
506 padding: const pw.EdgeInsets.all(8),
507 child: pw.Text('WH/IN00061'),
508 ),
509 pw.Container(
510 padding: const pw.EdgeInsets.all(8),
511 child: pw.Text(
512 'Bill Status',
513 ),
514 ),
515 pw.Container(
516 padding: const pw.EdgeInsets.all(8),
517 child: pw.Text('POSTED'),
518 ),
519 ],
520 ),
521 ],
522 ),
523 pw.SizedBox(height: 30),
524 // ignore: deprecated_member_use
525
526 pw.Table.fromTextArray(
527 context: context,
528 headers: [
529 'Product',
530 'Quantity Received',
531 'Quantity Billed',
532 'Unit Price'
533 ],
534 data: List.generate(1, (index) {
535 return [
536 '[UCO] Used cooking oil',
537 '${collection.orderLines?.first.productQty} L',
538 '${collection.orderLines?.first.productQty ?? 0 - 10} Kg',
539 '2.2',
540 ];
541 }),
542 cellAlignment: pw.Alignment.centerLeft,
543 ),
544
545 pw.Container(
546 padding: pw.EdgeInsets.all(5.sp),
547 decoration: pw.BoxDecoration(
548 border: pw.Border(
549 left: pw.BorderSide(color: PdfColor(0, 0, 0), width: 1),
550 right: pw.BorderSide(color: PdfColor(0, 0, 0), width: 1),
551 bottom: pw.BorderSide(color: PdfColor(0, 0, 0), width: 1),
552 top: pw.BorderSide.none,
553 ),
554 ),
555 child: pw.Row(
556 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
557 children: [
558 pw.SizedBox(),
559 pw.Text(
560 'Payment Amount: ${NumberFormat.compact().format((collection.orderLines?.first.productQty ?? 0 - 10) * 2.2)}',
561 ),
562 ],
563 ),
564 ),
565
566 pw.SizedBox(height: 30),
567 pw.Row(
568 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
569 children: [directorSignature, collectorSignature],
570 ),
571 pw.SizedBox(height: 30),
572 pw.Row(
573 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
574 crossAxisAlignment: pw.CrossAxisAlignment.end,
575 children: [
576 pw.Text(
577 'STRICTLY CONFIDENTIAL',
578 ),
579 pw.Row(
580 mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
581 children: [
582 qrCode,
583 pw.SizedBox(width: 10),
584 ],
585 ),
586 ],
587 ),
588 ],
589 );
590 },
591 ),
592 );
593
594 final output = await getTemporaryDirectory();
595 final file =
596 File('${output.path}/collection_voucher_with_table_and_payment.pdf');
597 await file.writeAsBytes(await pdf.save());
598
599 OpenFilex.open(file.path);
600 }
601}
class CalenderTransactionsSummaryVeiw extends StatefulWidget collection
String translate(String key)
static AppLocalizations of(BuildContext context)
static const String collectorSign
Definition assets.dart:43
static const String directorSign
Definition assets.dart:44
static String convertAndFormatWeight(num? kg)
const TransactionCardDetails({ super.key, required this.collection, })
final IconData icon
final VoidCallback onPressed
Widget _buildPercentageInfoLabel({ required String label, required BuildContext context, required num received, required num qty, })
const CustomCard({ super.key, required this.child, this.padding, this.bgColor, })
_buildInfoLabel({ required BuildContext context, IconData? icon, required String label, required String? info, MainAxisSize? size, })
final Widget child
override Widget build(BuildContext context)
final CollectionEntity collection
final String label
Future< void > generatePDF({ required CollectionEntity collection, }) async
final Widget child
final EdgeInsets padding
final Color backgroundColor
final Color progressColor
final String label
final Color color
Definition failures.dart:1
override Widget build(BuildContext context)