// 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/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/data/models/response/table_model.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/save_order_dialog.dart'; import 'package:enaklo_pos/data/models/response/payment_methods_response_model.dart'; import 'package:enaklo_pos/data/datasources/product_local_datasource.dart'; import 'package:enaklo_pos/presentation/table/models/draft_order_item.dart'; import '../../../core/components/buttons.dart'; import '../../../core/components/spaces.dart'; import '../../../core/constants/colors.dart'; import '../bloc/checkout/checkout_bloc.dart'; import '../widgets/order_menu.dart'; import '../widgets/success_payment_dialog.dart'; import '../widgets/order_type_selector.dart'; class ConfirmPaymentPage extends StatefulWidget { final bool isTable; final TableModel? table; const ConfirmPaymentPage({ super.key, required this.isTable, this.table, }); @override State createState() => _ConfirmPaymentPageState(); } class _ConfirmPaymentPageState extends State { final totalPriceController = TextEditingController(); final customerController = TextEditingController(); bool isPayNow = true; bool isAddToOrder = false; PaymentMethod? selectedPaymentMethod; TableModel? selectTable; int discountAmount = 0; int priceValue = 0; int uangPas = 0; int uangPas2 = 0; int uangPas3 = 0; // int discountAmountValue = 0; int totalPriceFinal = 0; // int taxFinal = 0; // int serviceChargeFinal = 0; @override void initState() { // Fetch available tables by default context .read() .add(GetTableStatusEvent.getTablesStatus('available')); context .read() .add(PaymentMethodsEvent.fetchPaymentMethods()); // Set a default payment method in case API fails selectedPaymentMethod = PaymentMethod( id: 1, name: 'Cash', description: 'Cash payment', isActive: true, sortOrder: 1, ); // if (selectTable == null && widget.table != null) { // selectTable = tables.firstWhere( // (t) => t.id == widget.table!.id, // orElse: () => null, // ); // } if (widget.table != null) { // selectTable = TableModel( // tableNumber: widget.table!.tableNumber, // startTime: widget.table!.startTime, // status: widget.table!.status, // orderId: widget.table!.orderId, // paymentAmount: widget.table!.paymentAmount, // position: widget.table!.position, // ); } super.initState(); } @override void dispose() { totalPriceController.dispose(); customerController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SafeArea( child: Hero( tag: 'payment_confirmation_screen', child: Scaffold( backgroundColor: AppColors.white, body: Row( children: [ Expanded( flex: 2, child: Align( alignment: Alignment.topCenter, child: SingleChildScrollView( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Konfirmasi', style: TextStyle( color: AppColors.primary, fontSize: 20, fontWeight: FontWeight.w600, ), ), Text( widget.isTable ? 'Orders Table ${widget.table?.tableName}' : 'Orders #1', 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( 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(12.0), itemCount: products.length, ); }, ); }, ), const SpaceHeight(8.0), const Divider(), const SpaceHeight(4.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Sub total', style: TextStyle(color: AppColors.grey), ), BlocBuilder( 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(4.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Diskon', style: TextStyle(color: AppColors.grey), ), BlocBuilder( 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 subTotal = 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 finalDiscount = discount / 100 * subTotal; discountAmount = finalDiscount.toInt(); return Text( '$discount % (${finalDiscount.toInt().currencyFormatRp})', style: TextStyle( color: AppColors.primary, fontWeight: FontWeight.w600, ), ); }, ), ], ), const SpaceHeight(4.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Pajak PB1', style: TextStyle(color: AppColors.grey), ), BlocBuilder( 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) { if (discountModel == null) { return 0; } return discountModel.value! .replaceAll('.00', '') .toIntegerFromText; }); final subTotal = price - (discount / 100 * price); final finalTax = subTotal * (tax / 100); // final finalDiscount = discount / 100 * subTotal; // discountAmountValue = finalDiscount.toInt(); // taxFinal = finalTax.toInt(); return Text( '$tax % (${finalTax.toInt().currencyFormatRp})', style: const TextStyle( color: AppColors.primary, fontWeight: FontWeight.w600, ), ); }, ), ], ), const SpaceHeight(4.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Biaya Layanan', style: TextStyle(color: AppColors.grey), ), BlocBuilder( builder: (context, state) { final serviceCharge = state.maybeWhen( orElse: () => 0, loaded: (products, discountModel, discount, discountAmount, tax, serviceCharge, totalQuantity, totalPrice, draftName, orderType) => serviceCharge, ); 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 nominalServiceCharge = (serviceCharge / 100) * (price - discountAmount); // serviceChargeFinal = // nominalServiceCharge.toInt(); return Text( '$serviceCharge % (${nominalServiceCharge.toInt().currencyFormatRp})', style: const TextStyle( color: AppColors.primary, fontWeight: FontWeight.w600, ), ); }, ), ], ), const SpaceHeight(10.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Total', style: TextStyle( color: AppColors.grey, fontWeight: FontWeight.bold, fontSize: 16), ), BlocBuilder( 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) { if (discountModel == null) { return 0; } return discountModel.value! .replaceAll('.00', '') .toIntegerFromText; }); final tax = state.maybeWhen( orElse: () => 0, loaded: (products, discountModel, discount, discountAmount, tax, serviceCharge, totalQuantity, totalPrice, draftName, orderType) => tax, ); final serviceCharge = state.maybeWhen( orElse: () => 0, loaded: (products, discountModel, discount, discountAmount, tax, serviceCharge, totalQuantity, totalPrice, draftName, orderType) => serviceCharge, ); final subTotal = price - (discount / 100 * price); final finalTax = subTotal * (tax / 100); final service = (serviceCharge / 100) * subTotal; final total = subTotal + finalTax + service; priceValue = total.toInt(); totalPriceController.text = total.ceil().currencyFormatRpV2; uangPas = total.ceil(); uangPas2 = uangPas ~/ 50000 * 50000 + 50000; uangPas3 = uangPas ~/ 50000 * 50000 + 100000; totalPriceFinal = total.ceil(); // log("totalPriceFinal: $totalPriceFinal"); return Text( total.ceil().currencyFormatRp, style: const TextStyle( color: AppColors.primary, fontWeight: FontWeight.w600, fontSize: 16, ), ); }, ), ], ), ], ), ), ), ), Expanded( flex: 3, child: Align( alignment: Alignment.topCenter, child: ListView( children: [ SingleChildScrollView( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.isTable != true) ...[ const Text( 'Pembayaran', style: TextStyle( color: AppColors.primary, fontSize: 20, fontWeight: FontWeight.w600, ), ), const SpaceHeight(16.0), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ isPayNow && !isAddToOrder ? Button.filled( height: 52.0, width: 200.0, onPressed: () { isPayNow = true; isAddToOrder = false; setState(() {}); }, label: 'Bayar Sekarang', ) : Button.outlined( width: 200.0, height: 52.0, onPressed: () { isPayNow = true; isAddToOrder = false; setState(() {}); }, label: 'Bayar Sekarang'), SpaceWidth(8), !isPayNow && !isAddToOrder ? Button.filled( width: 200.0, height: 52.0, onPressed: () async { print( "🔘 Bayar Nanti button pressed (filled)"); print( "🔘 Fetching available tables for Bayar Nanti"); isPayNow = false; isAddToOrder = false; // Debug: Check all tables first final allTables = await ProductLocalDatasource .instance .getAllTable(); print( "🔘 All tables in database: ${allTables.length}"); allTables.forEach((table) { print( "🔘 Table: ${table.tableName} - Status: ${table.status} - ID: ${table.id}"); }); // Fetch available tables for Bayar Nanti context .read() .add( GetTableStatusEvent .getTablesStatus( 'available'), ); setState(() {}); }, label: 'Bayar Nanti', ) : Button.outlined( width: 200.0, height: 52.0, onPressed: () async { print( "🔘 Bayar Nanti button pressed (outlined)"); print( "🔘 Fetching available tables for Bayar Nanti"); isPayNow = false; isAddToOrder = false; // Debug: Check all tables first final allTables = await ProductLocalDatasource .instance .getAllTable(); print( "🔘 All tables in database: ${allTables.length}"); allTables.forEach((table) { print( "🔘 Table: ${table.tableName} - Status: ${table.status} - ID: ${table.id}"); }); // Fetch available tables for Bayar Nanti context .read() .add( GetTableStatusEvent .getTablesStatus( 'available'), ); setState(() {}); }, label: 'Bayar Nanti'), SpaceWidth(8), isAddToOrder ? Button.filled( width: 200.0, height: 52.0, onPressed: () { isPayNow = false; isAddToOrder = true; setState(() {}); }, label: 'Tambah ke Pesanan', ) : Button.outlined( width: 200.0, height: 52.0, onPressed: () { print( "🔘 Tambah button pressed (outlined)"); print( "🔘 Fetching occupied tables for Tambah ke Pesanan"); isPayNow = false; isAddToOrder = true; // Fetch occupied tables for Tambah ke Pesanan context .read() .add( GetTableStatusEvent .getTablesStatus( 'occupied'), ); setState(() {}); }, label: 'Tambah ke Pesanan', ), ], ), ), ], const SpaceHeight(8.0), if (!isPayNow && !isAddToOrder) ...[ const Divider(), const SpaceHeight(8.0), const Text( 'Pilih Meja', style: TextStyle( color: AppColors.primary, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SpaceHeight(12.0), BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const CircularProgressIndicator(), success: (tables) { print( "🔘 Tables fetched: ${tables.length} tables"); print( "🔘 Table statuses: ${tables.map((t) => '${t.tableName}: ${t.status}').join(', ')}"); print( "🔘 Current mode: ${!isPayNow && !isAddToOrder ? 'Pay Later' : isAddToOrder ? 'Add to Order' : 'Pay Now'}"); // No need to filter since we're fetching the correct tables directly final availableTables = tables; if (selectTable == null && availableTables.isNotEmpty) { selectTable = availableTables.first; } if (availableTables.isEmpty) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.orange[50], borderRadius: BorderRadius.circular(16), border: Border.all( color: Colors.orange, width: 1, ), ), child: const Text( 'Tidak ada meja yang tersedia. Silakan pilih opsi lain.', style: TextStyle(color: Colors.orange), ), ); } return Container( padding: const EdgeInsets.symmetric( horizontal: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all( color: Theme.of(context).primaryColor, width: 2, ), ), child: DropdownButtonHideUnderline( child: DropdownButton( isExpanded: true, value: selectTable, onChanged: (TableModel? newValue) { setState(() { selectTable = newValue; }); }, items: availableTables .map< DropdownMenuItem>( (TableModel value) => DropdownMenuItem< TableModel>( value: value, child: Text(value.tableName), ), ) .toList(), ), ), ); }, ); }), ], const SpaceHeight(8.0), if (isAddToOrder) ...[ const Divider(), const SpaceHeight(8.0), const Text( 'Pilih Meja yang Sudah Ada Pesanan', style: TextStyle( color: AppColors.primary, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SpaceHeight(12.0), BlocBuilder( builder: (context, state) { return state.maybeWhen( orElse: () => const CircularProgressIndicator(), success: (tables) { print( "🔘 Add to Order - Tables fetched: ${tables.length} tables"); print( "🔘 Add to Order - Table statuses: ${tables.map((t) => '${t.tableName}: ${t.status}').join(', ')}"); // No need to filter since we're fetching occupied tables directly final occupiedTables = tables; if (selectTable == null && occupiedTables.isNotEmpty) { selectTable = occupiedTables.first; } return Container( padding: const EdgeInsets.symmetric( horizontal: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all( color: Theme.of(context).primaryColor, width: 2, ), ), child: DropdownButtonHideUnderline( child: DropdownButton( isExpanded: true, value: selectTable, onChanged: (TableModel? newValue) { setState(() { selectTable = newValue; }); }, items: occupiedTables .map< DropdownMenuItem>( (TableModel value) => DropdownMenuItem< TableModel>( value: value, child: Text( '${value.tableName} (Occupied)'), ), ) .toList(), ), ), ); }, ); }), ], if (!isAddToOrder) ...[ const SpaceHeight(8.0), const Divider(), const SpaceHeight(8.0), const Text( 'Customer', style: TextStyle( color: AppColors.primary, fontSize: 16, fontWeight: FontWeight.w500, ), ), const SpaceHeight(12.0), TextFormField( controller: customerController, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), hintText: 'Nama Customer', ), textCapitalization: TextCapitalization.words, ), ], const SpaceHeight(8.0), const Divider(), const SpaceHeight(8.0), const OrderTypeSelector(), const SpaceHeight(8.0), if (isPayNow) ...[ 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( 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() .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() .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: Tooltip( message: method.description ?? 'No description available', 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), BlocBuilder( builder: (context, state) { return TextFormField( controller: totalPriceController, keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), hintText: 'Total harga', ), onChanged: (value) { priceValue = value.toIntegerFromText; final int newValue = value.toIntegerFromText; totalPriceController.text = newValue.currencyFormatRp; totalPriceController.selection = TextSelection.fromPosition( TextPosition( offset: totalPriceController .text.length)); }, ); }, ), const SpaceHeight(20.0), BlocBuilder( builder: (context, state) { return Row( children: [ Button.filled( width: 150.0, onPressed: () { totalPriceController.text = uangPas .toString() .currencyFormatRpV2; priceValue = uangPas; }, label: 'UANG PAS', ), const SpaceWidth(20.0), Button.filled( width: 150.0, onPressed: () { totalPriceController.text = uangPas2 .toString() .currencyFormatRpV2; priceValue = uangPas2; }, label: uangPas2 .toString() .currencyFormatRpV2, ), const SpaceWidth(20.0), Button.filled( width: 150.0, onPressed: () { totalPriceController.text = uangPas3 .toString() .currencyFormatRpV2; priceValue = uangPas3; }, label: uangPas3 .toString() .currencyFormatRpV2, ), ], ); }, ), ] ], ), ), 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), BlocListener( listener: (context, state) { state.maybeWhen( orElse: () {}, savedDraftOrder: (orderDraftId) { log("PRICEVALUE: ${priceValue}"); final newTabel = TableModel( id: widget.isTable ? widget.table!.id : selectTable?.id, tableName: widget.isTable ? widget.table!.tableName : selectTable?.tableName ?? '0', status: 'occupied', paymentAmount: priceValue, orderId: orderDraftId, startTime: DateTime.now() .toIso8601String(), position: widget.isTable ? widget.table!.position : selectTable!.position); log('new tabel: ${newTabel.toMap()}'); context .read() .add(StatusTableEvent.statusTabel( newTabel, )); }); }, child: BlocBuilder( 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 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 orderType = state.maybeWhen( orElse: () => OrderType.dineIn, loaded: (products, discountModel, discount, discountAmount, tax, serviceCharge, totalQuantity, totalPrice, draftName, orderType) => orderType, ); final subTotal = price - (discount / 100 * price); final totalDiscount = discount / 100 * price; final finalTax = subTotal * (tax / 100); final totalServiceCharge = (serviceCharge / 100) * price; List 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, ); return Flexible( child: Button.filled( onPressed: () async { print("🔘 Payment button pressed"); print("🔘 isPayNow: $isPayNow"); print( "🔘 isAddToOrder: $isAddToOrder"); print( "🔘 selectedPaymentMethod: ${selectedPaymentMethod?.name}"); if (selectedPaymentMethod == null) { ScaffoldMessenger.of(context) .showSnackBar( const SnackBar( content: Text( 'Please select a payment method'), backgroundColor: Colors.red, ), ); return; } if (widget.isTable) { log("discountAmountValue: $totalDiscount"); context.read().add( CheckoutEvent .saveDraftOrder( widget.isTable == true ? widget.table!.id! : selectTable!.id!, customerController.text, totalDiscount.toInt(), ), ); await showDialog( context: context, barrierDismissible: false, builder: (context) => SaveOrderDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, table: widget.table!, draftName: customerController.text, ), ); } else if (isPayNow) { log("🔘 Entering Pay Now flow"); // context.read().add( // OrderEvent.addPaymentMethod( // items, // totalPrice, // finalTax, // discount != null // ? discount.value // .replaceAll( // '.00', '') // .toIntegerFromText // : 0, // finalDiscountAmount, // finalService, // subTotal, // totalPriceController.text // .toIntegerFromText, // auth?.user.name ?? '-', // totalQuantity, // auth?.user.id ?? 1, // isCash // ? 'Cash' // : 'QR Pay')); final paymentMethodName = selectedPaymentMethod?.name ?.toLowerCase() ?? ''; log("Selected payment method: ${selectedPaymentMethod?.name} (normalized: $paymentMethodName)"); if (paymentMethodName == 'cash' || paymentMethodName == 'tunai' || paymentMethodName == 'uang tunai' || paymentMethodName == 'cash payment') { log("🔘 Payment method is cash, proceeding with OrderBloc call"); log("discountAmountValue: $totalDiscount"); log("💳 About to call OrderBloc for cash payment"); log("💳 OrderBloc instance: ${context.read()}"); log("💳 About to dispatch OrderEvent.order for cash payment"); context.read().add( OrderEvent.order( items, discount, totalDiscount.toInt(), finalTax.toInt(), 0, totalPriceController .text .toIntegerFromText, customerController.text, 0, 'completed', 'paid', selectedPaymentMethod ?.name ?? 'Cash', totalPriceFinal, orderType)); log("💳 OrderEvent.order dispatched for cash payment"); await showDialog( context: context, barrierDismissible: false, builder: (context) => SuccessPaymentDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, totalService: totalServiceCharge .toInt(), draftName: customerController.text, ), ); } else { // Process non-cash payment directly without QRIS dialog log("Processing non-cash payment: ${selectedPaymentMethod?.name}"); log("💳 About to call OrderBloc for non-cash payment"); log("💳 OrderBloc instance: ${context.read()}"); context.read().add( OrderEvent.order( items, discount, totalDiscount.toInt(), finalTax.toInt(), 0, totalPriceController .text .toIntegerFromText, customerController.text, 0, 'completed', 'paid', selectedPaymentMethod ?.name ?? 'Unknown Payment Method', totalPriceFinal, orderType)); await showDialog( context: context, barrierDismissible: false, builder: (context) => SuccessPaymentDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, totalService: totalServiceCharge .toInt(), draftName: customerController.text, ), ); } } else if (isAddToOrder) { // Tambahkan ke pesanan meja yang sudah ada if (selectTable != null) { // Ambil draft order yang sudah ada final existingDraftOrder = await ProductLocalDatasource .instance .getDraftOrderById( selectTable ?.orderId ?? 0); if (existingDraftOrder != null) { // Convert items ke DraftOrderItem final newDraftItems = items .map((item) => DraftOrderItem( product: item.product, quantity: item.quantity, )) .toList(); // Gabungkan dengan pesanan yang sudah ada final updatedItems = [ ...existingDraftOrder .orders, ...newDraftItems ]; final updatedDraftOrder = existingDraftOrder .copyWith( orders: updatedItems, totalQuantity: updatedItems.fold( 0, (sum, item) => sum + item.quantity), subTotal: updatedItems.fold< int>( 0, (sum, item) => sum + (item.product .price ?? 0) * item.quantity), ); // Update draft order await ProductLocalDatasource .instance .updateDraftOrder( updatedDraftOrder); // Tampilkan dialog sukses await showDialog( context: context, barrierDismissible: false, builder: (context) => SaveOrderDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, table: selectTable!, draftName: customerController .text, ), ); } else { // Jika tidak ada draft order, buat baru context .read() .add( CheckoutEvent .saveDraftOrder( selectTable!.id!, customerController .text, totalDiscount.toInt(), ), ); await showDialog( context: context, barrierDismissible: false, builder: (context) => SaveOrderDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, table: selectTable!, draftName: customerController .text, ), ); } } else { ScaffoldMessenger.of(context) .showSnackBar( const SnackBar( content: Text( 'Pilih meja terlebih dahulu'), backgroundColor: Colors.red, ), ); } } else { context.read().add( CheckoutEvent .saveDraftOrder( widget.isTable == true ? widget.table!.id! : selectTable!.id!, customerController.text, totalDiscount.toInt(), ), ); await showDialog( context: context, barrierDismissible: false, builder: (context) => SaveOrderDialog( data: items, totalQty: totalQty, totalPrice: totalPriceFinal, totalTax: finalTax.toInt(), totalDiscount: totalDiscount.toInt(), subTotal: subTotal.toInt(), normalPrice: price, table: selectTable!, draftName: customerController.text, ), ); } }, label: isPayNow ? 'Bayar' : isAddToOrder ? 'Simpan' : 'Simpan Order', ), ); }, ), ), ], ), ), ), ), ], ), ), ), ], ), ), ), ); } }