From af182b6f5acf8dc5b4fbd908d03a3999ebfa7a11 Mon Sep 17 00:00:00 2001 From: efrilm Date: Fri, 7 Nov 2025 17:08:57 +0700 Subject: [PATCH] print payment --- .../print_struck/print_struck_bloc.dart | 20 +- .../print_struck_bloc.freezed.dart | 267 +++++++++++++++--- .../print_struck/print_struck_event.dart | 3 +- .../repositories/i_printer_repository.dart | 5 +- .../repositories/printer_repository.dart | 11 +- .../order/widgets/order_right_panel.dart | 5 +- .../payment_success/payment_success_page.dart | 87 +++--- .../widgets/payment_success_left_panel.dart | 21 +- 8 files changed, 314 insertions(+), 105 deletions(-) diff --git a/lib/application/printer/print_struck/print_struck_bloc.dart b/lib/application/printer/print_struck/print_struck_bloc.dart index 31ac3fb..111aa31 100644 --- a/lib/application/printer/print_struck/print_struck_bloc.dart +++ b/lib/application/printer/print_struck/print_struck_bloc.dart @@ -39,12 +39,28 @@ class PrintStruckBloc extends Bloc { ), ); }, - receipt: (e) async { + cashier: (e) async { Either failureOrSuccess; emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none())); - failureOrSuccess = await _printerRepository.printStruckReceipt( + failureOrSuccess = await _printerRepository.printStruckCashier( + order: e.order, + ); + + emit( + state.copyWith( + isPrinting: false, + failureOrPrintStruck: optionOf(failureOrSuccess), + ), + ); + }, + payment: (e) async { + Either failureOrSuccess; + + emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none())); + + failureOrSuccess = await _printerRepository.printStruckPayment( order: e.order, ); diff --git a/lib/application/printer/print_struck/print_struck_bloc.freezed.dart b/lib/application/printer/print_struck/print_struck_bloc.freezed.dart index 7c44fbc..d0ee0ff 100644 --- a/lib/application/printer/print_struck/print_struck_bloc.freezed.dart +++ b/lib/application/printer/print_struck/print_struck_bloc.freezed.dart @@ -21,33 +21,39 @@ mixin _$PrintStruckEvent { @optionalTypeArgs TResult when({ required TResult Function(Order order) order, - required TResult Function(Order order) receipt, + required TResult Function(Order order) cashier, + required TResult Function(Order order) payment, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function(Order order)? order, - TResult? Function(Order order)? receipt, + TResult? Function(Order order)? cashier, + TResult? Function(Order order)? payment, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function(Order order)? order, - TResult Function(Order order)? receipt, + TResult Function(Order order)? cashier, + TResult Function(Order order)? payment, required TResult orElse(), }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(_Order value) order, - required TResult Function(_Receipt value) receipt, + required TResult Function(_Cashier value) cashier, + required TResult Function(_Payment value) payment, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Order value)? order, - TResult? Function(_Receipt value)? receipt, + TResult? Function(_Cashier value)? cashier, + TResult? Function(_Payment value)? payment, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(_Order value)? order, - TResult Function(_Receipt value)? receipt, + TResult Function(_Cashier value)? cashier, + TResult Function(_Payment value)? payment, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -183,7 +189,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult when({ required TResult Function(Order order) order, - required TResult Function(Order order) receipt, + required TResult Function(Order order) cashier, + required TResult Function(Order order) payment, }) { return order(this.order); } @@ -192,7 +199,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult? whenOrNull({ TResult? Function(Order order)? order, - TResult? Function(Order order)? receipt, + TResult? Function(Order order)? cashier, + TResult? Function(Order order)? payment, }) { return order?.call(this.order); } @@ -201,7 +209,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult maybeWhen({ TResult Function(Order order)? order, - TResult Function(Order order)? receipt, + TResult Function(Order order)? cashier, + TResult Function(Order order)? payment, required TResult orElse(), }) { if (order != null) { @@ -214,7 +223,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult map({ required TResult Function(_Order value) order, - required TResult Function(_Receipt value) receipt, + required TResult Function(_Cashier value) cashier, + required TResult Function(_Payment value) payment, }) { return order(this); } @@ -223,7 +233,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Order value)? order, - TResult? Function(_Receipt value)? receipt, + TResult? Function(_Cashier value)? cashier, + TResult? Function(_Payment value)? payment, }) { return order?.call(this); } @@ -232,7 +243,8 @@ class _$OrderImpl implements _Order { @optionalTypeArgs TResult maybeMap({ TResult Function(_Order value)? order, - TResult Function(_Receipt value)? receipt, + TResult Function(_Cashier value)? cashier, + TResult Function(_Payment value)? payment, required TResult orElse(), }) { if (order != null) { @@ -257,12 +269,12 @@ abstract class _Order implements PrintStruckEvent { } /// @nodoc -abstract class _$$ReceiptImplCopyWith<$Res> +abstract class _$$CashierImplCopyWith<$Res> implements $PrintStruckEventCopyWith<$Res> { - factory _$$ReceiptImplCopyWith( - _$ReceiptImpl value, - $Res Function(_$ReceiptImpl) then, - ) = __$$ReceiptImplCopyWithImpl<$Res>; + factory _$$CashierImplCopyWith( + _$CashierImpl value, + $Res Function(_$CashierImpl) then, + ) = __$$CashierImplCopyWithImpl<$Res>; @override @useResult $Res call({Order order}); @@ -272,12 +284,12 @@ abstract class _$$ReceiptImplCopyWith<$Res> } /// @nodoc -class __$$ReceiptImplCopyWithImpl<$Res> - extends _$PrintStruckEventCopyWithImpl<$Res, _$ReceiptImpl> - implements _$$ReceiptImplCopyWith<$Res> { - __$$ReceiptImplCopyWithImpl( - _$ReceiptImpl _value, - $Res Function(_$ReceiptImpl) _then, +class __$$CashierImplCopyWithImpl<$Res> + extends _$PrintStruckEventCopyWithImpl<$Res, _$CashierImpl> + implements _$$CashierImplCopyWith<$Res> { + __$$CashierImplCopyWithImpl( + _$CashierImpl _value, + $Res Function(_$CashierImpl) _then, ) : super(_value, _then); /// Create a copy of PrintStruckEvent @@ -286,7 +298,7 @@ class __$$ReceiptImplCopyWithImpl<$Res> @override $Res call({Object? order = null}) { return _then( - _$ReceiptImpl( + _$CashierImpl( null == order ? _value.order : order // ignore: cast_nullable_to_non_nullable @@ -298,22 +310,22 @@ class __$$ReceiptImplCopyWithImpl<$Res> /// @nodoc -class _$ReceiptImpl implements _Receipt { - const _$ReceiptImpl(this.order); +class _$CashierImpl implements _Cashier { + const _$CashierImpl(this.order); @override final Order order; @override String toString() { - return 'PrintStruckEvent.receipt(order: $order)'; + return 'PrintStruckEvent.cashier(order: $order)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$ReceiptImpl && + other is _$CashierImpl && (identical(other.order, order) || other.order == order)); } @@ -325,36 +337,39 @@ class _$ReceiptImpl implements _Receipt { @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$ReceiptImplCopyWith<_$ReceiptImpl> get copyWith => - __$$ReceiptImplCopyWithImpl<_$ReceiptImpl>(this, _$identity); + _$$CashierImplCopyWith<_$CashierImpl> get copyWith => + __$$CashierImplCopyWithImpl<_$CashierImpl>(this, _$identity); @override @optionalTypeArgs TResult when({ required TResult Function(Order order) order, - required TResult Function(Order order) receipt, + required TResult Function(Order order) cashier, + required TResult Function(Order order) payment, }) { - return receipt(this.order); + return cashier(this.order); } @override @optionalTypeArgs TResult? whenOrNull({ TResult? Function(Order order)? order, - TResult? Function(Order order)? receipt, + TResult? Function(Order order)? cashier, + TResult? Function(Order order)? payment, }) { - return receipt?.call(this.order); + return cashier?.call(this.order); } @override @optionalTypeArgs TResult maybeWhen({ TResult Function(Order order)? order, - TResult Function(Order order)? receipt, + TResult Function(Order order)? cashier, + TResult Function(Order order)? payment, required TResult orElse(), }) { - if (receipt != null) { - return receipt(this.order); + if (cashier != null) { + return cashier(this.order); } return orElse(); } @@ -363,36 +378,39 @@ class _$ReceiptImpl implements _Receipt { @optionalTypeArgs TResult map({ required TResult Function(_Order value) order, - required TResult Function(_Receipt value) receipt, + required TResult Function(_Cashier value) cashier, + required TResult Function(_Payment value) payment, }) { - return receipt(this); + return cashier(this); } @override @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Order value)? order, - TResult? Function(_Receipt value)? receipt, + TResult? Function(_Cashier value)? cashier, + TResult? Function(_Payment value)? payment, }) { - return receipt?.call(this); + return cashier?.call(this); } @override @optionalTypeArgs TResult maybeMap({ TResult Function(_Order value)? order, - TResult Function(_Receipt value)? receipt, + TResult Function(_Cashier value)? cashier, + TResult Function(_Payment value)? payment, required TResult orElse(), }) { - if (receipt != null) { - return receipt(this); + if (cashier != null) { + return cashier(this); } return orElse(); } } -abstract class _Receipt implements PrintStruckEvent { - const factory _Receipt(final Order order) = _$ReceiptImpl; +abstract class _Cashier implements PrintStruckEvent { + const factory _Cashier(final Order order) = _$CashierImpl; @override Order get order; @@ -401,7 +419,162 @@ abstract class _Receipt implements PrintStruckEvent { /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$ReceiptImplCopyWith<_$ReceiptImpl> get copyWith => + _$$CashierImplCopyWith<_$CashierImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$PaymentImplCopyWith<$Res> + implements $PrintStruckEventCopyWith<$Res> { + factory _$$PaymentImplCopyWith( + _$PaymentImpl value, + $Res Function(_$PaymentImpl) then, + ) = __$$PaymentImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({Order order}); + + @override + $OrderCopyWith<$Res> get order; +} + +/// @nodoc +class __$$PaymentImplCopyWithImpl<$Res> + extends _$PrintStruckEventCopyWithImpl<$Res, _$PaymentImpl> + implements _$$PaymentImplCopyWith<$Res> { + __$$PaymentImplCopyWithImpl( + _$PaymentImpl _value, + $Res Function(_$PaymentImpl) _then, + ) : super(_value, _then); + + /// Create a copy of PrintStruckEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? order = null}) { + return _then( + _$PaymentImpl( + null == order + ? _value.order + : order // ignore: cast_nullable_to_non_nullable + as Order, + ), + ); + } +} + +/// @nodoc + +class _$PaymentImpl implements _Payment { + const _$PaymentImpl(this.order); + + @override + final Order order; + + @override + String toString() { + return 'PrintStruckEvent.payment(order: $order)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PaymentImpl && + (identical(other.order, order) || other.order == order)); + } + + @override + int get hashCode => Object.hash(runtimeType, order); + + /// Create a copy of PrintStruckEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PaymentImplCopyWith<_$PaymentImpl> get copyWith => + __$$PaymentImplCopyWithImpl<_$PaymentImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(Order order) order, + required TResult Function(Order order) cashier, + required TResult Function(Order order) payment, + }) { + return payment(this.order); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(Order order)? order, + TResult? Function(Order order)? cashier, + TResult? Function(Order order)? payment, + }) { + return payment?.call(this.order); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Order order)? order, + TResult Function(Order order)? cashier, + TResult Function(Order order)? payment, + required TResult orElse(), + }) { + if (payment != null) { + return payment(this.order); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Order value) order, + required TResult Function(_Cashier value) cashier, + required TResult Function(_Payment value) payment, + }) { + return payment(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Order value)? order, + TResult? Function(_Cashier value)? cashier, + TResult? Function(_Payment value)? payment, + }) { + return payment?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Order value)? order, + TResult Function(_Cashier value)? cashier, + TResult Function(_Payment value)? payment, + required TResult orElse(), + }) { + if (payment != null) { + return payment(this); + } + return orElse(); + } +} + +abstract class _Payment implements PrintStruckEvent { + const factory _Payment(final Order order) = _$PaymentImpl; + + @override + Order get order; + + /// Create a copy of PrintStruckEvent + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PaymentImplCopyWith<_$PaymentImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/application/printer/print_struck/print_struck_event.dart b/lib/application/printer/print_struck/print_struck_event.dart index 05df7a1..a9747bb 100644 --- a/lib/application/printer/print_struck/print_struck_event.dart +++ b/lib/application/printer/print_struck/print_struck_event.dart @@ -3,5 +3,6 @@ part of 'print_struck_bloc.dart'; @freezed class PrintStruckEvent with _$PrintStruckEvent { const factory PrintStruckEvent.order(Order order) = _Order; - const factory PrintStruckEvent.receipt(Order order) = _Receipt; + const factory PrintStruckEvent.cashier(Order order) = _Cashier; + const factory PrintStruckEvent.payment(Order order) = _Payment; } diff --git a/lib/domain/printer/repositories/i_printer_repository.dart b/lib/domain/printer/repositories/i_printer_repository.dart index 0494303..99d66b1 100644 --- a/lib/domain/printer/repositories/i_printer_repository.dart +++ b/lib/domain/printer/repositories/i_printer_repository.dart @@ -19,7 +19,10 @@ abstract class IPrinterRepository { Future> printStruckSaveOrder({ required Order order, }); - Future> printStruckReceipt({ + Future> printStruckCashier({ + required Order order, + }); + Future> printStruckPayment({ required Order order, }); } diff --git a/lib/infrastructure/printer/repositories/printer_repository.dart b/lib/infrastructure/printer/repositories/printer_repository.dart index 2d3e759..8ea4815 100644 --- a/lib/infrastructure/printer/repositories/printer_repository.dart +++ b/lib/infrastructure/printer/repositories/printer_repository.dart @@ -481,7 +481,7 @@ class PrinterRepository implements IPrinterRepository { } @override - Future> printStruckReceipt({ + Future> printStruckCashier({ required Order order, }) async { final outlet = await _outletLocalDatasource.currentOutlet(); @@ -489,6 +489,15 @@ class PrinterRepository implements IPrinterRepository { return _printCashier(order: order, outlet: outlet, cashieName: user.name); } + @override + Future> printStruckPayment({ + required Order order, + }) async { + final outlet = await _outletLocalDatasource.currentOutlet(); + final user = await _authLocalDataProvider.currentUser(); + return _printReceipt(order: order, outlet: outlet, cashieName: user.name); + } + Future> _printReceipt({ required Order order, required Outlet outlet, diff --git a/lib/presentation/pages/order/widgets/order_right_panel.dart b/lib/presentation/pages/order/widgets/order_right_panel.dart index bad5cf9..7104989 100644 --- a/lib/presentation/pages/order/widgets/order_right_panel.dart +++ b/lib/presentation/pages/order/widgets/order_right_panel.dart @@ -61,9 +61,12 @@ class OrderRightPanel extends StatelessWidget { AppElevatedButton.outlined( onPressed: () { if (state.selectedOrder?.status == 'completed') { + context.read().add( + PrintStruckEvent.payment(state.selectedOrder!), + ); } else { context.read().add( - PrintStruckEvent.receipt(state.selectedOrder!), + PrintStruckEvent.cashier(state.selectedOrder!), ); } }, diff --git a/lib/presentation/pages/payment/pages/payment_success/payment_success_page.dart b/lib/presentation/pages/payment/pages/payment_success/payment_success_page.dart index b09fe85..9ed3c22 100644 --- a/lib/presentation/pages/payment/pages/payment_success/payment_success_page.dart +++ b/lib/presentation/pages/payment/pages/payment_success/payment_success_page.dart @@ -3,10 +3,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../../application/order/order_loader/order_loader_bloc.dart'; +import '../../../../../application/printer/print_struck/print_struck_bloc.dart'; import '../../../../../common/theme/theme.dart'; import '../../../../../injection.dart'; import '../../../../components/error/order_loader_error_state_widget.dart'; import '../../../../components/loader/loader_with_text.dart'; +import '../../../../components/toast/flushbar.dart'; import 'widgets/payment_success_left_panel.dart'; import 'widgets/payment_success_right_panel.dart'; @@ -17,45 +19,58 @@ class PaymentSuccessPage extends StatelessWidget implements AutoRouteWrapper { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColor.background, - body: SafeArea( - child: BlocBuilder( - builder: (context, state) { - if (state.isFetchingById) { - return const Center(child: LoaderWithText()); - } - return state.failureOptionGetById.fold( - () => Container( - padding: const EdgeInsets.all(24.0), - child: Row( - children: [ - // Left Panel - Success Message & Order Info - Expanded( - flex: 35, - child: PaymentSuccessLeftPanel(order: state.order), - ), + return BlocListener( + listenWhen: (previous, current) => + previous.failureOrPrintStruck != current.failureOrPrintStruck, + listener: (context, state) { + state.failureOrPrintStruck.fold(() {}, (either) { + either.fold((f) => AppFlushbar.showPrinterFailureToast(context, f), ( + success, + ) { + AppFlushbar.showSuccess(context, "Struck berhasil dicetak"); + }); + }); + }, + child: Scaffold( + backgroundColor: AppColor.background, + body: SafeArea( + child: BlocBuilder( + builder: (context, state) { + if (state.isFetchingById) { + return const Center(child: LoaderWithText()); + } + return state.failureOptionGetById.fold( + () => Container( + padding: const EdgeInsets.all(24.0), + child: Row( + children: [ + // Left Panel - Success Message & Order Info + Expanded( + flex: 35, + child: PaymentSuccessLeftPanel(order: state.order), + ), - const SizedBox(width: 16), + const SizedBox(width: 16), - // Right Panel - Order Details - Expanded( - flex: 65, - child: PaymentSuccessRightPanel(order: state.order), - ), - ], + // Right Panel - Order Details + Expanded( + flex: 65, + child: PaymentSuccessRightPanel(order: state.order), + ), + ], + ), ), - ), - (f) => OrderLoaderErrorStateWidget( - failure: f, - onRefresh: () { - context.read().add( - OrderLoaderEvent.getById(orderId), - ); - }, - ), - ); - }, + (f) => OrderLoaderErrorStateWidget( + failure: f, + onRefresh: () { + context.read().add( + OrderLoaderEvent.getById(orderId), + ); + }, + ), + ); + }, + ), ), ), ); diff --git a/lib/presentation/pages/payment/pages/payment_success/widgets/payment_success_left_panel.dart b/lib/presentation/pages/payment/pages/payment_success/widgets/payment_success_left_panel.dart index 4963a77..32de37e 100644 --- a/lib/presentation/pages/payment/pages/payment_success/widgets/payment_success_left_panel.dart +++ b/lib/presentation/pages/payment/pages/payment_success/widgets/payment_success_left_panel.dart @@ -1,6 +1,8 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../../../application/printer/print_struck/print_struck_bloc.dart'; import '../../../../../../common/extension/extension.dart'; import '../../../../../../common/theme/theme.dart'; import '../../../../../../domain/order/order.dart'; @@ -160,22 +162,9 @@ class PaymentSuccessLeftPanel extends StatelessWidget { Expanded( child: AppElevatedButton.filled( onPressed: () { - // onPrintRecipt( - // context, - // order: widget.order, - // paymentMethod: widget.paymentMethod, - // nominalBayar: widget.paymentMethod == "Cash" - // ? widget.nominalBayar - // : widget.order.totalAmount ?? 0, - // kembalian: widget.nominalBayar - - // (widget.order.totalAmount ?? 0), - // productQuantity: widget.productQuantity, - // ); - // onPrint( - // context, - // productQuantity: widget.productQuantity, - // order: widget.order, - // ); + context.read().add( + PrintStruckEvent.payment(order), + ); }, label: 'Cetak Struk', icon: Icon(Icons.print_rounded, color: AppColor.white),