apskel-pos-flutter/lib/presentation/table/pages/payment_table_page.dart
2025-08-03 00:47:49 +07:00

1271 lines
64 KiB
Dart

// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:enaklo_pos/core/extensions/int_ext.dart';
import 'package:enaklo_pos/core/extensions/string_ext.dart';
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/table_model.dart';
import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/get_table_status/get_table_status_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/order/order_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/payment_methods/payment_methods_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/status_table/status_table_bloc.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:enaklo_pos/presentation/home/models/order_type.dart';
import 'package:enaklo_pos/presentation/home/widgets/order_menu.dart';
import 'package:enaklo_pos/presentation/home/widgets/success_payment_dialog.dart';
import 'package:enaklo_pos/presentation/home/widgets/order_type_selector.dart';
import 'package:enaklo_pos/presentation/table/models/draft_order_model.dart';
import 'package:enaklo_pos/data/models/response/payment_methods_response_model.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import '../../../core/components/buttons.dart';
import '../../../core/components/spaces.dart';
import '../../../core/constants/colors.dart';
class PaymentTablePage extends StatefulWidget {
final DraftOrderModel? draftOrder;
final TableModel? table;
const PaymentTablePage({
super.key,
this.draftOrder,
this.table,
});
@override
State<PaymentTablePage> createState() => _PaymentTablePageState();
}
class _PaymentTablePageState extends State<PaymentTablePage> {
final totalPriceController = TextEditingController();
final customerController = TextEditingController();
PaymentMethod? selectedPaymentMethod;
int totalPriceFinal = 0;
int discountAmountFinal = 0;
// Helper method to handle post-payment cleanup
Future<void> _handlePostPaymentCleanup() async {
if (widget.table != null && widget.draftOrder?.id != null) {
// Update table status to available
final newTable = TableModel(
id: widget.table!.id,
tableName: widget.table!.tableName,
status: 'available',
orderId: 0,
paymentAmount: 0,
startTime: DateTime.now().toIso8601String(),
position: widget.table!.position,
);
// Update table status
await ProductLocalDatasource.instance.updateStatusTable(newTable);
// Remove draft order
await ProductLocalDatasource.instance
.removeDraftOrderById(widget.draftOrder!.id!);
// Refresh table status
context.read<GetTableStatusBloc>().add(
GetTableStatusEvent.getTablesStatus('all'),
);
log("Table ${widget.table!.tableName} freed up and draft order removed");
}
// Safely navigate back - pop multiple times to get to table management
// Pop the success dialog first, then the payment page
if (Navigator.of(context).canPop()) {
Navigator.of(context).pop(); // Pop success dialog
if (Navigator.of(context).canPop()) {
Navigator.of(context).pop(); // Pop payment page
}
}
}
@override
void initState() {
context
.read<GetTableStatusBloc>()
.add(GetTableStatusEvent.getTablesStatus('available'));
context
.read<PaymentMethodsBloc>()
.add(PaymentMethodsEvent.fetchPaymentMethods());
super.initState();
// Set a default payment method in case API fails
selectedPaymentMethod = PaymentMethod(
id: "4b1c0d21-c98a-4fc0-a2f9-8d90a0c9d905",
organizationId: "3e8b1793-d18b-40c4-a03d-0c6480b630c7",
name: "CASH",
type: "cash",
isActive: true,
createdAt: DateTime.tryParse('2025-07-18T03:43:13.857048+07:00'),
updatedAt: DateTime.tryParse('2025-07-18T03:43:13.857048+07:00'),
);
}
@override
void dispose() {
totalPriceController.dispose();
customerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Hero(
tag: 'table_payment_screen',
child: Scaffold(
appBar: AppBar(
title: Text('Payment - Table ${widget.table?.tableName}'),
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
},
),
actions: [
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Kembali'),
content: const Text(
'Apakah Anda yakin ingin kembali? Order akan tetap tersimpan.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(); // Close dialog
},
child: const Text('Tidak'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(); // Close dialog
Navigator.of(context)
.pop(); // Go back to previous page
},
child: const Text('Ya'),
),
],
);
},
);
},
child: const Text(
'Kembali',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
],
),
body: Row(
children: [
// LEFT CONTENT
Expanded(
flex: 2,
child: Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Konfirmasi',
style: TextStyle(
color: AppColors.primary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
Text(
'Orders Table ${widget.table?.tableName}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
const SpaceHeight(8.0),
const Divider(),
const SpaceHeight(24.0),
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Item',
style: TextStyle(
color: AppColors.primary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
SizedBox(
width: 160,
),
SizedBox(
width: 50.0,
child: Text(
'Qty',
style: TextStyle(
color: AppColors.primary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(
child: Text(
'Price',
style: TextStyle(
color: AppColors.primary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
],
),
const SpaceHeight(8),
const Divider(),
const SpaceHeight(8),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () => const Center(
child: Text('No Items'),
),
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
if (products.isEmpty) {
return const Center(
child: Text('No Items'),
);
}
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) =>
OrderMenu(data: products[index]),
separatorBuilder: (context, index) =>
const SpaceHeight(16.0),
itemCount: products.length,
);
},
);
},
),
const SpaceHeight(16.0),
const SpaceHeight(8.0),
const Divider(),
const SpaceHeight(8.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Sub total',
style: TextStyle(color: AppColors.grey),
),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final price = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products.fold(
0,
(previousValue, element) =>
previousValue +
(element.product.price! *
element.quantity),
));
return Text(
price.currencyFormatRp,
style: const TextStyle(
color: AppColors.primary,
fontWeight: FontWeight.w600,
),
);
},
),
],
),
const SpaceHeight(16.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Diskon',
style: TextStyle(color: AppColors.grey),
),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final discount = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
log("discountAmount: $discountAmount");
return discountAmount;
});
discountAmountFinal = discount.toInt();
return Text(
discount.toInt().currencyFormatRp,
style: TextStyle(
color: AppColors.primary,
fontWeight: FontWeight.w600,
),
);
},
),
],
),
const SpaceHeight(16.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Pajak PB1',
style: TextStyle(color: AppColors.grey),
),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final tax = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
tax,
);
final price = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products.fold(
0,
(previousValue, element) =>
previousValue +
(element.product.price! *
element.quantity),
),
);
final discount = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
return discountAmount;
});
final subTotal = price - discount;
final finalTax = subTotal * (tax / 100);
return Text(
'$tax % (${finalTax.toInt().currencyFormatRp})',
style: const TextStyle(
color: AppColors.primary,
fontWeight: FontWeight.w600,
),
);
},
),
],
),
const SpaceHeight(16.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Biaya Layanan',
style: TextStyle(color: AppColors.grey),
),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
tax,
);
final price = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products.fold(
0,
(previousValue, element) =>
previousValue +
(element.product.price! *
element.quantity),
),
);
final discount = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
return discountAmount;
});
final serviceCharge = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
serviceCharge,
);
final subTotal = price - discount;
final finalServiceCharge =
subTotal * (serviceCharge / 100);
return Text(
'$serviceCharge % (${finalServiceCharge.toInt().currencyFormatRp}) ',
style: const TextStyle(
color: AppColors.primary,
fontWeight: FontWeight.w600,
),
);
},
),
],
),
const SpaceHeight(16.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total',
style: TextStyle(
color: AppColors.grey,
fontWeight: FontWeight.bold,
fontSize: 16),
),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final price = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products.fold(
0,
(previousValue, element) =>
previousValue +
(element.product.price! *
element.quantity),
),
);
final discount = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
return discountAmount;
});
final serviceCharge = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
serviceCharge,
);
final tax = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
tax,
);
final subTotal = price - discount;
final finalTax = subTotal * (tax / 100);
final service =
subTotal * (serviceCharge / 100);
final total = subTotal + finalTax + service;
totalPriceFinal = total.ceil();
totalPriceController.text =
total.ceil().toString();
return Text(
total.ceil().currencyFormatRp,
style: const TextStyle(
color: AppColors.primary,
fontWeight: FontWeight.w600,
fontSize: 16,
),
);
},
),
],
),
// const SpaceHeight(20.0),
// Button.filled(
// onPressed: () {},
// label: 'Lanjutkan Pembayaran',
// ),
],
),
),
),
),
// RIGHT CONTENT
Expanded(
flex: 3,
child: Align(
alignment: Alignment.topCenter,
child: Stack(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Pembayaran',
style: TextStyle(
color: AppColors.primary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(16.0),
const Divider(),
const SpaceHeight(8.0),
const Text(
'Customer',
style: TextStyle(
color: AppColors.primary,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SpaceHeight(12.0),
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () {
return SizedBox.shrink();
},
loaded: (items,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
customerController.text = draftName;
return TextFormField(
readOnly: true,
controller: customerController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(8.0),
),
hintText: 'Nama Customer',
),
);
},
);
},
),
const SpaceHeight(8.0),
const Divider(),
const SpaceHeight(8.0),
const OrderTypeSelector(),
const SpaceHeight(8.0),
const Divider(),
const SpaceHeight(8.0),
const Text(
'Metode Bayar',
style: TextStyle(
color: AppColors.primary,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
const SpaceHeight(12.0),
BlocBuilder<PaymentMethodsBloc,
PaymentMethodsState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () => const Center(
child: CircularProgressIndicator(),
),
loading: () => const Center(
child: Column(
children: [
CircularProgressIndicator(),
SizedBox(height: 8.0),
Text('Loading payment methods...'),
],
),
),
error: (message) => Column(
children: [
Center(
child: Text(
'Error loading payment methods: $message'),
),
const SpaceHeight(16.0),
Button.filled(
onPressed: () {
context
.read<PaymentMethodsBloc>()
.add(PaymentMethodsEvent
.fetchPaymentMethods());
},
label: 'Retry',
),
],
),
loaded: (paymentMethods) {
log("Loaded ${paymentMethods.length} payment methods");
paymentMethods.forEach((method) {
log("Payment method: ${method.name} (ID: ${method.id})");
});
if (paymentMethods.isEmpty) {
return Column(
children: [
const Center(
child: Text(
'No payment methods available'),
),
const SpaceHeight(16.0),
Button.filled(
onPressed: () {
context
.read<PaymentMethodsBloc>()
.add(PaymentMethodsEvent
.fetchPaymentMethods());
},
label: 'Retry',
),
],
);
}
// Set default selected payment method if none selected or if current selection is not in the list
if (selectedPaymentMethod == null ||
!paymentMethods.any((method) =>
method.id ==
selectedPaymentMethod?.id)) {
selectedPaymentMethod =
paymentMethods.first;
}
return Wrap(
spacing: 12.0,
runSpacing: 8.0,
children: paymentMethods.map((method) {
final isSelected =
selectedPaymentMethod?.id ==
method.id;
return Container(
constraints: const BoxConstraints(
minWidth: 120.0,
),
decoration: isSelected
? BoxDecoration(
border: Border.all(
color: AppColors.primary,
width: 2.0,
),
borderRadius:
BorderRadius.circular(
8.0),
)
: null,
child: isSelected
? Button.filled(
width: double.infinity,
height: 50.0,
onPressed: () {
setState(() {
selectedPaymentMethod =
method;
});
},
label: method.name
?.isNotEmpty ==
true
? method.name!
: 'Unknown',
)
: Button.outlined(
width: double.infinity,
height: 50.0,
onPressed: () {
setState(() {
selectedPaymentMethod =
method;
});
},
label: method.name
?.isNotEmpty ==
true
? method.name!
: 'Unknown',
),
);
}).toList(),
);
},
);
},
),
const SpaceHeight(8.0),
const Divider(),
const SpaceHeight(8.0),
const Text(
'Total Bayar',
style: TextStyle(
color: AppColors.primary,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SpaceHeight(12.0),
TextFormField(
controller: totalPriceController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
hintText: 'Total harga',
),
),
const SpaceHeight(45.0),
Row(
children: [
Button.filled(
width: 150.0,
onPressed: () {},
label: 'UANG PAS',
),
const SpaceWidth(20.0),
Button.filled(
width: 150.0,
onPressed: () {},
label: 'Rp 250.000',
),
const SpaceWidth(20.0),
Button.filled(
width: 150.0,
onPressed: () {},
label: 'Rp 300.000',
),
],
),
const SpaceHeight(100.0),
]),
),
Align(
alignment: Alignment.bottomCenter,
child: ColoredBox(
color: AppColors.white,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24.0, vertical: 16.0),
child: Row(
children: [
Flexible(
child: Button.outlined(
onPressed: () => context.pop(),
label: 'Kembali',
),
),
const SpaceWidth(8.0),
Flexible(
child: Button.outlined(
onPressed: () {
// Show void confirmation dialog
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Row(
children: [
Icon(Icons.warning,
color: AppColors.red),
SizedBox(width: 8),
Text('Batalkan Pesanan?'),
],
),
content: Text(
'Apakah anda yakin ingin membatalkan pesanan untuk meja ${widget.table?.tableName ?? "ini"}?\n\nPesanan akan dihapus secara permanen.'),
actions: [
TextButton(
onPressed: () =>
Navigator.pop(context),
child: Text('Tidak',
style: TextStyle(
color:
AppColors.primary)),
),
BlocListener<StatusTableBloc,
StatusTableState>(
listener: (context, state) {
state.maybeWhen(
orElse: () {},
success: () {
Navigator.pop(
context); // Close void dialog
Navigator.pop(
context); // Close payment page
ScaffoldMessenger.of(
context)
.showSnackBar(
const SnackBar(
content: Text(
'Pesanan berhasil dibatalkan'),
backgroundColor:
AppColors.primary,
),
);
},
);
},
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
AppColors.red,
),
onPressed: () {
// Void the order
if (widget.table != null) {
final newTable = TableModel(
id: widget.table!.id,
tableName: widget
.table!.tableName,
status: 'available',
orderId: 0,
paymentAmount: 0,
startTime: DateTime.now()
.toIso8601String(),
position: widget
.table!.position,
);
context
.read<StatusTableBloc>()
.add(
StatusTableEvent
.statusTabel(
newTable),
);
}
// Remove draft order from local storage
if (widget.draftOrder?.id !=
null) {
ProductLocalDatasource
.instance
.removeDraftOrderById(
widget.draftOrder!
.id!);
}
log("Voided order from payment page");
},
child: const Text(
"Ya, Batalkan",
style: TextStyle(
color: Colors.white),
),
),
),
],
),
);
},
label: 'Batalkan',
),
),
const SpaceWidth(8.0),
BlocListener<OrderBloc, OrderState>(
listener: (context, state) {
final newTable = TableModel(
id: widget.table!.id,
tableName: widget.table!.tableName,
status: 'available',
orderId: 0,
paymentAmount: 0,
startTime:
DateTime.now().toIso8601String(),
position: widget.table!.position,
);
context.read<StatusTableBloc>().add(
StatusTableEvent.statusTabel(
newTable,
),
);
ProductLocalDatasource.instance
.removeDraftOrderById(
widget.draftOrder!.id!);
},
child:
BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final discount = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) {
if (discountModel == null) {
return 0;
}
return discountModel.value!
.replaceAll('.00', '')
.toIntegerFromText;
});
final price = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products.fold(
0,
(previousValue, element) =>
previousValue +
(element.product.price! *
element.quantity),
),
);
final tax = state.maybeWhen(
orElse: () => 0,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
tax,
);
final subTotal =
price - (discount / 100 * price);
final totalDiscount =
discount / 100 * price;
final finalTax = subTotal * (tax / 100);
List<ProductQuantity> items =
state.maybeWhen(
orElse: () => [],
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
products,
);
final totalQty = items.fold(
0,
(previousValue, element) =>
previousValue + element.quantity,
);
final orderType = state.maybeWhen(
orElse: () => OrderType.dineIn,
loaded: (products,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType) =>
orderType,
);
return Flexible(
child: Button.filled(
onPressed: () async {
if (selectedPaymentMethod == null) {
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
'Please select a payment method'),
backgroundColor: Colors.red,
),
);
return;
}
final paymentMethodName =
selectedPaymentMethod?.name
?.toLowerCase() ??
'';
log("Selected payment method: ${selectedPaymentMethod?.name} (normalized: $paymentMethodName)");
if (paymentMethodName == 'cash' ||
paymentMethodName == 'tunai' ||
paymentMethodName ==
'uang tunai' ||
paymentMethodName ==
'cash payment') {
context.read<OrderBloc>().add(
OrderEvent.order(
items,
discount,
discountAmountFinal,
finalTax.toInt(),
0,
totalPriceController.text
.toIntegerFromText,
customerController.text,
widget.table?.id ?? 0,
'completed',
'paid',
selectedPaymentMethod
?.name ??
'Cash',
totalPriceFinal,
orderType));
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) =>
SuccessPaymentDialog(
isTablePaymentPage: true,
data: items,
totalQty: totalQty,
totalPrice:
totalPriceFinal.toInt(),
totalTax: finalTax.toInt(),
totalDiscount:
totalDiscount.toInt(),
subTotal: subTotal.toInt(),
normalPrice: price,
totalService: 0,
draftName:
customerController.text,
),
);
await _handlePostPaymentCleanup();
} else {
log("Processing non-cash payment: ${selectedPaymentMethod?.name}");
context.read<OrderBloc>().add(
OrderEvent.order(
items,
discount,
discountAmountFinal,
finalTax.toInt(),
0,
totalPriceController.text
.toIntegerFromText,
customerController.text,
widget.table?.id ?? 0,
'completed',
'paid',
selectedPaymentMethod
?.name ??
'Unknown Payment Method',
totalPriceFinal,
orderType));
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) =>
SuccessPaymentDialog(
isTablePaymentPage: true,
data: items,
totalQty: totalQty,
totalPrice:
totalPriceFinal.toInt(),
totalTax: finalTax.toInt(),
totalDiscount:
totalDiscount.toInt(),
subTotal: subTotal.toInt(),
normalPrice: price,
totalService: 0,
draftName:
customerController.text,
),
);
// Handle post-payment cleanup
await _handlePostPaymentCleanup();
}
},
label: 'Bayar',
),
);
},
),
),
],
),
),
),
),
],
),
),
),
],
),
),
),
);
}
}