void struck

This commit is contained in:
efrilm 2025-11-10 13:06:06 +07:00
parent af182b6f5a
commit c5673a147c
8 changed files with 381 additions and 35 deletions

View File

@ -64,6 +64,22 @@ class PrintStruckBloc extends Bloc<PrintStruckEvent, PrintStruckState> {
order: e.order, order: e.order,
); );
emit(
state.copyWith(
isPrinting: false,
failureOrPrintStruck: optionOf(failureOrSuccess),
),
);
},
voided: (e) async {
Either<PrinterFailure, Unit> failureOrSuccess;
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
failureOrSuccess = await _printerRepository.printStruckVoid(
order: e.order,
);
emit( emit(
state.copyWith( state.copyWith(
isPrinting: false, isPrinting: false,

View File

@ -23,18 +23,21 @@ mixin _$PrintStruckEvent {
required TResult Function(Order order) order, required TResult Function(Order order) order,
required TResult Function(Order order) cashier, required TResult Function(Order order) cashier,
required TResult Function(Order order) payment, required TResult Function(Order order) payment,
required TResult Function(Order order) voided,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function(Order order)? order, TResult? Function(Order order)? order,
TResult? Function(Order order)? cashier, TResult? Function(Order order)? cashier,
TResult? Function(Order order)? payment, TResult? Function(Order order)? payment,
TResult? Function(Order order)? voided,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function(Order order)? order, TResult Function(Order order)? order,
TResult Function(Order order)? cashier, TResult Function(Order order)? cashier,
TResult Function(Order order)? payment, TResult Function(Order order)? payment,
TResult Function(Order order)? voided,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@ -42,18 +45,21 @@ mixin _$PrintStruckEvent {
required TResult Function(_Order value) order, required TResult Function(_Order value) order,
required TResult Function(_Cashier value) cashier, required TResult Function(_Cashier value) cashier,
required TResult Function(_Payment value) payment, required TResult Function(_Payment value) payment,
required TResult Function(_Voided value) voided,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({ TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Order value)? order, TResult? Function(_Order value)? order,
TResult? Function(_Cashier value)? cashier, TResult? Function(_Cashier value)? cashier,
TResult? Function(_Payment value)? payment, TResult? Function(_Payment value)? payment,
TResult? Function(_Voided value)? voided,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(_Order value)? order, TResult Function(_Order value)? order,
TResult Function(_Cashier value)? cashier, TResult Function(_Cashier value)? cashier,
TResult Function(_Payment value)? payment, TResult Function(_Payment value)? payment,
TResult Function(_Voided value)? voided,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@ -191,6 +197,7 @@ class _$OrderImpl implements _Order {
required TResult Function(Order order) order, required TResult Function(Order order) order,
required TResult Function(Order order) cashier, required TResult Function(Order order) cashier,
required TResult Function(Order order) payment, required TResult Function(Order order) payment,
required TResult Function(Order order) voided,
}) { }) {
return order(this.order); return order(this.order);
} }
@ -201,6 +208,7 @@ class _$OrderImpl implements _Order {
TResult? Function(Order order)? order, TResult? Function(Order order)? order,
TResult? Function(Order order)? cashier, TResult? Function(Order order)? cashier,
TResult? Function(Order order)? payment, TResult? Function(Order order)? payment,
TResult? Function(Order order)? voided,
}) { }) {
return order?.call(this.order); return order?.call(this.order);
} }
@ -211,6 +219,7 @@ class _$OrderImpl implements _Order {
TResult Function(Order order)? order, TResult Function(Order order)? order,
TResult Function(Order order)? cashier, TResult Function(Order order)? cashier,
TResult Function(Order order)? payment, TResult Function(Order order)? payment,
TResult Function(Order order)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (order != null) { if (order != null) {
@ -225,6 +234,7 @@ class _$OrderImpl implements _Order {
required TResult Function(_Order value) order, required TResult Function(_Order value) order,
required TResult Function(_Cashier value) cashier, required TResult Function(_Cashier value) cashier,
required TResult Function(_Payment value) payment, required TResult Function(_Payment value) payment,
required TResult Function(_Voided value) voided,
}) { }) {
return order(this); return order(this);
} }
@ -235,6 +245,7 @@ class _$OrderImpl implements _Order {
TResult? Function(_Order value)? order, TResult? Function(_Order value)? order,
TResult? Function(_Cashier value)? cashier, TResult? Function(_Cashier value)? cashier,
TResult? Function(_Payment value)? payment, TResult? Function(_Payment value)? payment,
TResult? Function(_Voided value)? voided,
}) { }) {
return order?.call(this); return order?.call(this);
} }
@ -245,6 +256,7 @@ class _$OrderImpl implements _Order {
TResult Function(_Order value)? order, TResult Function(_Order value)? order,
TResult Function(_Cashier value)? cashier, TResult Function(_Cashier value)? cashier,
TResult Function(_Payment value)? payment, TResult Function(_Payment value)? payment,
TResult Function(_Voided value)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (order != null) { if (order != null) {
@ -346,6 +358,7 @@ class _$CashierImpl implements _Cashier {
required TResult Function(Order order) order, required TResult Function(Order order) order,
required TResult Function(Order order) cashier, required TResult Function(Order order) cashier,
required TResult Function(Order order) payment, required TResult Function(Order order) payment,
required TResult Function(Order order) voided,
}) { }) {
return cashier(this.order); return cashier(this.order);
} }
@ -356,6 +369,7 @@ class _$CashierImpl implements _Cashier {
TResult? Function(Order order)? order, TResult? Function(Order order)? order,
TResult? Function(Order order)? cashier, TResult? Function(Order order)? cashier,
TResult? Function(Order order)? payment, TResult? Function(Order order)? payment,
TResult? Function(Order order)? voided,
}) { }) {
return cashier?.call(this.order); return cashier?.call(this.order);
} }
@ -366,6 +380,7 @@ class _$CashierImpl implements _Cashier {
TResult Function(Order order)? order, TResult Function(Order order)? order,
TResult Function(Order order)? cashier, TResult Function(Order order)? cashier,
TResult Function(Order order)? payment, TResult Function(Order order)? payment,
TResult Function(Order order)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (cashier != null) { if (cashier != null) {
@ -380,6 +395,7 @@ class _$CashierImpl implements _Cashier {
required TResult Function(_Order value) order, required TResult Function(_Order value) order,
required TResult Function(_Cashier value) cashier, required TResult Function(_Cashier value) cashier,
required TResult Function(_Payment value) payment, required TResult Function(_Payment value) payment,
required TResult Function(_Voided value) voided,
}) { }) {
return cashier(this); return cashier(this);
} }
@ -390,6 +406,7 @@ class _$CashierImpl implements _Cashier {
TResult? Function(_Order value)? order, TResult? Function(_Order value)? order,
TResult? Function(_Cashier value)? cashier, TResult? Function(_Cashier value)? cashier,
TResult? Function(_Payment value)? payment, TResult? Function(_Payment value)? payment,
TResult? Function(_Voided value)? voided,
}) { }) {
return cashier?.call(this); return cashier?.call(this);
} }
@ -400,6 +417,7 @@ class _$CashierImpl implements _Cashier {
TResult Function(_Order value)? order, TResult Function(_Order value)? order,
TResult Function(_Cashier value)? cashier, TResult Function(_Cashier value)? cashier,
TResult Function(_Payment value)? payment, TResult Function(_Payment value)? payment,
TResult Function(_Voided value)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (cashier != null) { if (cashier != null) {
@ -501,6 +519,7 @@ class _$PaymentImpl implements _Payment {
required TResult Function(Order order) order, required TResult Function(Order order) order,
required TResult Function(Order order) cashier, required TResult Function(Order order) cashier,
required TResult Function(Order order) payment, required TResult Function(Order order) payment,
required TResult Function(Order order) voided,
}) { }) {
return payment(this.order); return payment(this.order);
} }
@ -511,6 +530,7 @@ class _$PaymentImpl implements _Payment {
TResult? Function(Order order)? order, TResult? Function(Order order)? order,
TResult? Function(Order order)? cashier, TResult? Function(Order order)? cashier,
TResult? Function(Order order)? payment, TResult? Function(Order order)? payment,
TResult? Function(Order order)? voided,
}) { }) {
return payment?.call(this.order); return payment?.call(this.order);
} }
@ -521,6 +541,7 @@ class _$PaymentImpl implements _Payment {
TResult Function(Order order)? order, TResult Function(Order order)? order,
TResult Function(Order order)? cashier, TResult Function(Order order)? cashier,
TResult Function(Order order)? payment, TResult Function(Order order)? payment,
TResult Function(Order order)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (payment != null) { if (payment != null) {
@ -535,6 +556,7 @@ class _$PaymentImpl implements _Payment {
required TResult Function(_Order value) order, required TResult Function(_Order value) order,
required TResult Function(_Cashier value) cashier, required TResult Function(_Cashier value) cashier,
required TResult Function(_Payment value) payment, required TResult Function(_Payment value) payment,
required TResult Function(_Voided value) voided,
}) { }) {
return payment(this); return payment(this);
} }
@ -545,6 +567,7 @@ class _$PaymentImpl implements _Payment {
TResult? Function(_Order value)? order, TResult? Function(_Order value)? order,
TResult? Function(_Cashier value)? cashier, TResult? Function(_Cashier value)? cashier,
TResult? Function(_Payment value)? payment, TResult? Function(_Payment value)? payment,
TResult? Function(_Voided value)? voided,
}) { }) {
return payment?.call(this); return payment?.call(this);
} }
@ -555,6 +578,7 @@ class _$PaymentImpl implements _Payment {
TResult Function(_Order value)? order, TResult Function(_Order value)? order,
TResult Function(_Cashier value)? cashier, TResult Function(_Cashier value)? cashier,
TResult Function(_Payment value)? payment, TResult Function(_Payment value)? payment,
TResult Function(_Voided value)? voided,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (payment != null) { if (payment != null) {
@ -578,6 +602,167 @@ abstract class _Payment implements PrintStruckEvent {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc
abstract class _$$VoidedImplCopyWith<$Res>
implements $PrintStruckEventCopyWith<$Res> {
factory _$$VoidedImplCopyWith(
_$VoidedImpl value,
$Res Function(_$VoidedImpl) then,
) = __$$VoidedImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({Order order});
@override
$OrderCopyWith<$Res> get order;
}
/// @nodoc
class __$$VoidedImplCopyWithImpl<$Res>
extends _$PrintStruckEventCopyWithImpl<$Res, _$VoidedImpl>
implements _$$VoidedImplCopyWith<$Res> {
__$$VoidedImplCopyWithImpl(
_$VoidedImpl _value,
$Res Function(_$VoidedImpl) _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(
_$VoidedImpl(
null == order
? _value.order
: order // ignore: cast_nullable_to_non_nullable
as Order,
),
);
}
}
/// @nodoc
class _$VoidedImpl implements _Voided {
const _$VoidedImpl(this.order);
@override
final Order order;
@override
String toString() {
return 'PrintStruckEvent.voided(order: $order)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$VoidedImpl &&
(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')
_$$VoidedImplCopyWith<_$VoidedImpl> get copyWith =>
__$$VoidedImplCopyWithImpl<_$VoidedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(Order order) order,
required TResult Function(Order order) cashier,
required TResult Function(Order order) payment,
required TResult Function(Order order) voided,
}) {
return voided(this.order);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(Order order)? order,
TResult? Function(Order order)? cashier,
TResult? Function(Order order)? payment,
TResult? Function(Order order)? voided,
}) {
return voided?.call(this.order);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(Order order)? order,
TResult Function(Order order)? cashier,
TResult Function(Order order)? payment,
TResult Function(Order order)? voided,
required TResult orElse(),
}) {
if (voided != null) {
return voided(this.order);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Order value) order,
required TResult Function(_Cashier value) cashier,
required TResult Function(_Payment value) payment,
required TResult Function(_Voided value) voided,
}) {
return voided(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Order value)? order,
TResult? Function(_Cashier value)? cashier,
TResult? Function(_Payment value)? payment,
TResult? Function(_Voided value)? voided,
}) {
return voided?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Order value)? order,
TResult Function(_Cashier value)? cashier,
TResult Function(_Payment value)? payment,
TResult Function(_Voided value)? voided,
required TResult orElse(),
}) {
if (voided != null) {
return voided(this);
}
return orElse();
}
}
abstract class _Voided implements PrintStruckEvent {
const factory _Voided(final Order order) = _$VoidedImpl;
@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)
_$$VoidedImplCopyWith<_$VoidedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc /// @nodoc
mixin _$PrintStruckState { mixin _$PrintStruckState {
Option<Either<PrinterFailure, Unit>> get failureOrPrintStruck => Option<Either<PrinterFailure, Unit>> get failureOrPrintStruck =>

View File

@ -5,4 +5,5 @@ class PrintStruckEvent with _$PrintStruckEvent {
const factory PrintStruckEvent.order(Order order) = _Order; const factory PrintStruckEvent.order(Order order) = _Order;
const factory PrintStruckEvent.cashier(Order order) = _Cashier; const factory PrintStruckEvent.cashier(Order order) = _Cashier;
const factory PrintStruckEvent.payment(Order order) = _Payment; const factory PrintStruckEvent.payment(Order order) = _Payment;
const factory PrintStruckEvent.voided(Order order) = _Voided;
} }

View File

@ -25,4 +25,5 @@ abstract class IPrinterRepository {
Future<Either<PrinterFailure, Unit>> printStruckPayment({ Future<Either<PrinterFailure, Unit>> printStruckPayment({
required Order order, required Order order,
}); });
Future<Either<PrinterFailure, Unit>> printStruckVoid({required Order order});
} }

View File

@ -489,6 +489,15 @@ class PrinterRepository implements IPrinterRepository {
return _printCashier(order: order, outlet: outlet, cashieName: user.name); return _printCashier(order: order, outlet: outlet, cashieName: user.name);
} }
@override
Future<Either<PrinterFailure, Unit>> printStruckVoid({
required Order order,
}) async {
final outlet = await _outletLocalDatasource.currentOutlet();
final user = await _authLocalDataProvider.currentUser();
return _printVoid(order: order, outlet: outlet, cashieName: user.name);
}
@override @override
Future<Either<PrinterFailure, Unit>> printStruckPayment({ Future<Either<PrinterFailure, Unit>> printStruckPayment({
required Order order, required Order order,
@ -766,4 +775,52 @@ class PrinterRepository implements IPrinterRepository {
); );
} }
} }
Future<Either<PrinterFailure, Unit>> _printVoid({
required Order order,
required Outlet outlet,
required String cashieName,
}) async {
log('Starting to print void', name: _logName);
final voidPrinter = await _localDataProvider.findPrinterByCode('receipt');
if (voidPrinter.hasData) {
try {
final printer = voidPrinter.data!.toDomain();
final printValue = await PrintUi().printVoid(
order: order,
outlet: outlet,
cashierName: cashieName,
);
await printStruct(printer, printValue);
log('Finished printed void', name: _logName);
return right(unit);
} catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
'Print Struck Void Error: $e',
stackTrace,
reason:
'Print struck void error / Printer not setting in printer page',
information: ['Order ID: ${order.id}'],
);
log("Error printing void", name: _logName, error: e);
return left(
const PrinterFailure.dynamicErrorMessage('Error printing void order'),
);
}
} else {
FirebaseCrashlytics.instance.recordError(
'Void printer not found',
null,
reason: 'Void printer not found / Printer not setting in printer page',
information: ['Order ID: ${order.id}'],
);
return left(
const PrinterFailure.dynamicErrorMessage('Void printer not found'),
);
}
}
} }

View File

@ -348,4 +348,70 @@ class PrintUi {
return bytes; return bytes;
} }
Future<List<int>> printVoid({
required Order order,
required Outlet outlet,
required String cashierName,
int paper = 58,
}) async {
List<int> bytes = [];
final profile = await CapabilityProfile.load();
final generator = Generator(
paper == 58 ? PaperSize.mm58 : PaperSize.mm80,
profile,
);
final builder = ReceiptComponentBuilder(
generator: generator,
paperSize: 58,
);
bytes += generator.reset();
bytes += builder.header(
outletName: outlet.name,
address: outlet.address,
phoneNumber: outlet.phoneNumber,
);
bytes += builder.dateTime(DateTime.now());
bytes += builder.orderInfo(
orderNumber: order.orderNumber,
customerName: order.metadata['customer_name'] ?? 'John Doe',
cashierName: cashierName,
paymentMethod: order.payments.isEmpty
? null
: order.payments.last.paymentMethodName,
tableNumber: order.tableNumber,
);
bytes += builder.orderType('Void');
bytes += builder.emptyLines(1);
for (final item in order.orderItems) {
bytes += builder.orderItem(
productName: item.productName,
quantity: item.quantity,
unitPrice: item.unitPrice.currencyFormatRpV2,
totalPrice: item.totalPrice.currencyFormatRpV2,
variantName: item.productVariantName,
notes: item.notes,
);
}
bytes += builder.summary(
totalItems: order.orderItems.length,
subtotal: order.subtotal.currencyFormatRpV2,
discount: order.discountAmount.currencyFormatRpV2,
total: order.totalAmount.currencyFormatRpV2,
paid: order.totalPaid.currencyFormatRpV2,
);
bytes += builder.footer(message: 'Kasir');
return bytes;
}
} }

View File

@ -2,9 +2,11 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/printer/print_struck/print_struck_bloc.dart';
import '../../../../../application/void/void_form/void_form_bloc.dart'; import '../../../../../application/void/void_form/void_form_bloc.dart';
import '../../../../../common/theme/theme.dart'; import '../../../../../common/theme/theme.dart';
import '../../../../components/spaces/space.dart'; import '../../../../components/spaces/space.dart';
import '../../../../components/toast/flushbar.dart';
import 'widgets/void_success_left_panel.dart'; import 'widgets/void_success_left_panel.dart';
import 'widgets/void_success_right_panel.dart'; import 'widgets/void_success_right_panel.dart';
@ -14,26 +16,44 @@ class VoidSuccessPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return BlocListener<PrintStruckBloc, PrintStruckState>(
backgroundColor: AppColor.background, listenWhen: (previous, current) =>
body: BlocBuilder<VoidFormBloc, VoidFormState>( previous.failureOrPrintStruck != current.failureOrPrintStruck,
builder: (context, state) { listener: (context, state) {
return SafeArea( state.failureOrPrintStruck.fold(
child: Padding( () {},
padding: const EdgeInsets.all(24.0), (either) => either.fold(
child: Row( (f) => AppFlushbar.showPrinterFailureToast(context, f),
children: [ (success) {
Expanded(flex: 35, child: VoidSuccessLeftPanel(state: state)), AppFlushbar.showSuccess(context, "Struck berhasil dicetak");
SpaceWidth(16), },
Expanded( ),
flex: 65, );
child: VoidSuccessRightPanel(state: state), },
), child: Scaffold(
], backgroundColor: AppColor.background,
body: BlocBuilder<VoidFormBloc, VoidFormState>(
builder: (context, state) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
children: [
Expanded(
flex: 35,
child: VoidSuccessLeftPanel(state: state),
),
SpaceWidth(16),
Expanded(
flex: 65,
child: VoidSuccessRightPanel(state: state),
),
],
),
), ),
), );
); },
}, ),
), ),
); );
} }

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../application/printer/print_struck/print_struck_bloc.dart';
import '../../../../../../application/void/void_form/void_form_bloc.dart'; import '../../../../../../application/void/void_form/void_form_bloc.dart';
import '../../../../../../common/extension/extension.dart'; import '../../../../../../common/extension/extension.dart';
import '../../../../../../common/theme/theme.dart'; import '../../../../../../common/theme/theme.dart';
@ -149,22 +150,21 @@ class VoidSuccessLeftPanel extends StatelessWidget {
Expanded( Expanded(
child: AppElevatedButton.filled( child: AppElevatedButton.filled(
onPressed: () { onPressed: () {
// onPrintRecipt( context.read<PrintStruckBloc>().add(
// context, PrintStruckEvent.voided(
// order: widget.order, state.order.copyWith(
// paymentMethod: widget.paymentMethod, orderItems: state.voidType.isAll
// nominalBayar: widget.paymentMethod == "Cash" ? state.order.orderItems
// ? widget.nominalBayar : state.voidItems,
// : widget.order.totalAmount ?? 0, subtotal: state.voidType.isAll
// kembalian: widget.nominalBayar - ? state.order.totalAmount
// (widget.order.totalAmount ?? 0), : state.totalPriceVoid,
// productQuantity: widget.productQuantity, totalAmount: state.voidType.isAll
// ); ? state.order.totalAmount
// onPrint( : state.totalPriceVoid,
// context, ),
// productQuantity: widget.productQuantity, ),
// order: widget.order, );
// );
}, },
label: 'Cetak Struk', label: 'Cetak Struk',
icon: Icon(Icons.print_rounded, color: AppColor.white), icon: Icon(Icons.print_rounded, color: AppColor.white),