2025-07-30 22:38:44 +07:00
|
|
|
// 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:intl/intl.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/dataoutputs/print_dataoutputs.dart';
|
|
|
|
|
import 'package:enaklo_pos/data/datasources/product_local_datasource.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/core/utils/printer_service.dart';
|
|
|
|
|
import 'package:enaklo_pos/data/datasources/settings_local_datasource.dart';
|
|
|
|
|
|
|
|
|
|
import '../../../core/assets/assets.gen.dart';
|
|
|
|
|
import '../../../core/components/buttons.dart';
|
|
|
|
|
import '../../../core/components/spaces.dart';
|
|
|
|
|
import '../../table/blocs/get_table/get_table_bloc.dart';
|
|
|
|
|
import '../bloc/checkout/checkout_bloc.dart';
|
|
|
|
|
import '../bloc/order/order_bloc.dart';
|
|
|
|
|
|
|
|
|
|
class SuccessPaymentDialog extends StatefulWidget {
|
|
|
|
|
const SuccessPaymentDialog({
|
|
|
|
|
Key? key,
|
|
|
|
|
required this.data,
|
|
|
|
|
required this.totalQty,
|
|
|
|
|
required this.totalPrice,
|
|
|
|
|
required this.totalTax,
|
|
|
|
|
required this.totalDiscount,
|
|
|
|
|
required this.subTotal,
|
|
|
|
|
required this.normalPrice,
|
|
|
|
|
required this.totalService,
|
|
|
|
|
required this.draftName,
|
|
|
|
|
this.isTablePaymentPage = false,
|
|
|
|
|
}) : super(key: key);
|
|
|
|
|
final List<ProductQuantity> data;
|
|
|
|
|
final int totalQty;
|
|
|
|
|
final int totalPrice;
|
|
|
|
|
final int totalTax;
|
|
|
|
|
final int totalDiscount;
|
|
|
|
|
final int subTotal;
|
|
|
|
|
final int normalPrice;
|
|
|
|
|
final int totalService;
|
|
|
|
|
final String draftName;
|
|
|
|
|
final bool? isTablePaymentPage;
|
|
|
|
|
@override
|
|
|
|
|
State<SuccessPaymentDialog> createState() => _SuccessPaymentDialogState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _SuccessPaymentDialogState extends State<SuccessPaymentDialog> {
|
|
|
|
|
// List<ProductQuantity> data = [];
|
|
|
|
|
// int totalQty = 0;
|
|
|
|
|
// int totalPrice = 0;
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return AlertDialog(
|
|
|
|
|
content: SingleChildScrollView(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Center(child: Assets.icons.success.svg()),
|
|
|
|
|
const SpaceHeight(16.0),
|
|
|
|
|
const Center(
|
|
|
|
|
child: Text(
|
|
|
|
|
'Pembayaran telah sukses dilakukan',
|
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 20,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(20.0),
|
|
|
|
|
const Text('METODE BAYAR'),
|
|
|
|
|
const SpaceHeight(5.0),
|
|
|
|
|
BlocBuilder<OrderBloc, OrderState>(
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final paymentMethod = state.maybeWhen(
|
|
|
|
|
orElse: () => 'Cash',
|
|
|
|
|
loaded: (model, orderId) => model.paymentMethod,
|
|
|
|
|
);
|
|
|
|
|
return Text(
|
|
|
|
|
paymentMethod,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(10.0),
|
|
|
|
|
const Divider(),
|
|
|
|
|
const SpaceHeight(8.0),
|
|
|
|
|
const Text('TOTAL TAGIHAN'),
|
|
|
|
|
const SpaceHeight(5.0),
|
|
|
|
|
BlocBuilder<OrderBloc, OrderState>(
|
|
|
|
|
builder: (context, state) {
|
2025-08-06 18:12:27 +07:00
|
|
|
state.maybeWhen(
|
2025-07-30 22:38:44 +07:00
|
|
|
orElse: () => 0,
|
|
|
|
|
loaded: (model, orderId) => model.total,
|
|
|
|
|
);
|
|
|
|
|
return Text(
|
|
|
|
|
widget.totalPrice.currencyFormatRp,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(10.0),
|
|
|
|
|
const Divider(),
|
|
|
|
|
const SpaceHeight(8.0),
|
|
|
|
|
const Text('NOMINAL BAYAR'),
|
|
|
|
|
const SpaceHeight(5.0),
|
|
|
|
|
BlocBuilder<OrderBloc, OrderState>(
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final paymentAmount = state.maybeWhen(
|
|
|
|
|
orElse: () => 0,
|
|
|
|
|
loaded: (model, orderId) => model.paymentAmount,
|
|
|
|
|
);
|
|
|
|
|
return Text(
|
|
|
|
|
paymentAmount.ceil().currencyFormatRp,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
const Divider(),
|
|
|
|
|
const SpaceHeight(8.0),
|
|
|
|
|
const Text('KEMBALIAN'),
|
|
|
|
|
const SpaceHeight(5.0),
|
|
|
|
|
BlocBuilder<OrderBloc, OrderState>(
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final paymentAmount = state.maybeWhen(
|
|
|
|
|
orElse: () => 0,
|
|
|
|
|
loaded: (model, orderId) => model.paymentAmount,
|
|
|
|
|
);
|
|
|
|
|
final total = state.maybeWhen(
|
|
|
|
|
orElse: () => 0,
|
|
|
|
|
loaded: (model, orderId) => model.total,
|
|
|
|
|
);
|
|
|
|
|
final diff = paymentAmount - total;
|
|
|
|
|
log("DIFF: $diff paymentAmount: $paymentAmount total: $total");
|
|
|
|
|
return Text(
|
|
|
|
|
diff.ceil().currencyFormatRp,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(10.0),
|
|
|
|
|
const Divider(),
|
|
|
|
|
const SpaceHeight(8.0),
|
|
|
|
|
const Text('WAKTU PEMBAYARAN'),
|
|
|
|
|
const SpaceHeight(5.0),
|
|
|
|
|
Text(
|
|
|
|
|
DateFormat('dd MMMM yyyy, HH:mm').format(DateTime.now()),
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SpaceHeight(20.0),
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Flexible(
|
|
|
|
|
child: Button.outlined(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
// For table payment page, just close the dialog
|
|
|
|
|
// The cleanup and navigation is handled by the payment page
|
|
|
|
|
if (widget.isTablePaymentPage == true) {
|
|
|
|
|
Navigator.of(context).pop(); // Close dialog only
|
|
|
|
|
} else {
|
|
|
|
|
// For regular payment flow, reset and go to root
|
|
|
|
|
context
|
|
|
|
|
.read<CheckoutBloc>()
|
2025-09-01 22:12:56 +07:00
|
|
|
.add(const CheckoutEvent.started([]));
|
2025-07-30 22:38:44 +07:00
|
|
|
context
|
|
|
|
|
.read<GetTableBloc>()
|
|
|
|
|
.add(const GetTableEvent.getTables());
|
|
|
|
|
context.popToRoot();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
label: 'Kembali',
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SpaceWidth(8.0),
|
|
|
|
|
Flexible(
|
|
|
|
|
child: BlocBuilder<OrderBloc, OrderState>(
|
|
|
|
|
builder: (context, state) {
|
|
|
|
|
final paymentAmount = state.maybeWhen(
|
|
|
|
|
orElse: () => 0,
|
|
|
|
|
loaded: (model, orderId) => model.paymentAmount,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
final kembalian = paymentAmount - widget.totalPrice;
|
2025-08-06 18:12:27 +07:00
|
|
|
return BlocBuilder<CheckoutBloc, CheckoutState>(
|
2025-07-30 22:38:44 +07:00
|
|
|
builder: (context, checkoutState) {
|
|
|
|
|
final orderType = checkoutState.maybeWhen(
|
|
|
|
|
orElse: () => OrderType.dineIn,
|
2025-08-06 18:47:20 +07:00
|
|
|
loaded: (
|
|
|
|
|
items,
|
|
|
|
|
discountModel,
|
|
|
|
|
discount,
|
|
|
|
|
discountAmount,
|
|
|
|
|
tax,
|
|
|
|
|
serviceCharge,
|
|
|
|
|
totalQuantity,
|
|
|
|
|
totalPrice,
|
|
|
|
|
draftName,
|
|
|
|
|
orderType,
|
|
|
|
|
deliveryType,
|
|
|
|
|
) =>
|
2025-08-06 18:12:27 +07:00
|
|
|
orderType,
|
2025-07-30 22:38:44 +07:00
|
|
|
);
|
2025-08-06 18:12:27 +07:00
|
|
|
|
2025-07-30 22:38:44 +07:00
|
|
|
return Button.filled(
|
|
|
|
|
onPressed: () async {
|
2025-08-06 18:12:27 +07:00
|
|
|
final receiptPrinter =
|
|
|
|
|
await ProductLocalDatasource.instance
|
|
|
|
|
.getPrinterByCode('receipt');
|
|
|
|
|
final kitchenPrinter =
|
|
|
|
|
await ProductLocalDatasource.instance
|
|
|
|
|
.getPrinterByCode('kitchen');
|
|
|
|
|
final barPrinter = await ProductLocalDatasource
|
|
|
|
|
.instance
|
|
|
|
|
.getPrinterByCode('bar');
|
|
|
|
|
|
|
|
|
|
// Receipt Printer
|
|
|
|
|
if (receiptPrinter != null) {
|
|
|
|
|
try {
|
|
|
|
|
final settingsLocalDatasource =
|
|
|
|
|
SettingsLocalDatasource();
|
|
|
|
|
final taxModel =
|
|
|
|
|
await settingsLocalDatasource.getTax();
|
|
|
|
|
final serviceChargeValue =
|
|
|
|
|
await settingsLocalDatasource
|
|
|
|
|
.getServiceCharge();
|
|
|
|
|
|
|
|
|
|
// Get the actual payment method from OrderBloc
|
|
|
|
|
final paymentMethod = state.maybeWhen(
|
|
|
|
|
orElse: () => 'Cash',
|
|
|
|
|
loaded: (model, orderId) =>
|
|
|
|
|
model.paymentMethod,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
final printValue = await PrintDataoutputs
|
|
|
|
|
.instance
|
|
|
|
|
.printOrderV3(
|
|
|
|
|
widget.data,
|
|
|
|
|
widget.totalQty,
|
|
|
|
|
widget.totalPrice,
|
|
|
|
|
paymentMethod,
|
|
|
|
|
paymentAmount,
|
|
|
|
|
kembalian,
|
|
|
|
|
widget.subTotal,
|
|
|
|
|
widget.totalDiscount,
|
|
|
|
|
widget.totalTax,
|
|
|
|
|
widget.totalService,
|
|
|
|
|
'kasir',
|
|
|
|
|
widget.draftName,
|
|
|
|
|
receiptPrinter.paper.toIntegerFromText,
|
|
|
|
|
taxPercentage: taxModel.value,
|
|
|
|
|
serviceChargePercentage: serviceChargeValue,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await PrinterService().printWithPrinter(
|
|
|
|
|
receiptPrinter, printValue, context);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log("Error printing receipt: $e");
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
SnackBar(
|
|
|
|
|
content:
|
|
|
|
|
Text('Error printing receipt: $e')),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Kitchen Printer
|
|
|
|
|
if (kitchenPrinter != null &&
|
|
|
|
|
widget.isTablePaymentPage == false) {
|
|
|
|
|
try {
|
|
|
|
|
final printValue = await PrintDataoutputs
|
|
|
|
|
.instance
|
|
|
|
|
.printKitchen(
|
|
|
|
|
widget.data,
|
|
|
|
|
'',
|
|
|
|
|
widget.draftName,
|
|
|
|
|
'kasir',
|
|
|
|
|
kitchenPrinter.paper.toIntegerFromText,
|
|
|
|
|
orderType.value,
|
|
|
|
|
);
|
2025-07-30 22:38:44 +07:00
|
|
|
|
2025-08-06 18:12:27 +07:00
|
|
|
await PrinterService().printWithPrinter(
|
|
|
|
|
kitchenPrinter, printValue, context);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log("Error printing kitchen order: $e");
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
SnackBar(
|
|
|
|
|
content: Text(
|
|
|
|
|
'Error printing kitchen order: $e')),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-30 22:38:44 +07:00
|
|
|
|
2025-08-06 18:12:27 +07:00
|
|
|
// Bar printer
|
|
|
|
|
if (barPrinter != null &&
|
|
|
|
|
widget.isTablePaymentPage == false) {
|
|
|
|
|
try {
|
|
|
|
|
final printValue =
|
|
|
|
|
await PrintDataoutputs.instance.printBar(
|
|
|
|
|
widget.data,
|
|
|
|
|
'',
|
|
|
|
|
widget.draftName,
|
|
|
|
|
'kasir',
|
|
|
|
|
barPrinter.paper.toIntegerFromText,
|
|
|
|
|
orderType.value,
|
|
|
|
|
);
|
2025-07-30 22:38:44 +07:00
|
|
|
|
2025-08-06 18:12:27 +07:00
|
|
|
await PrinterService().printWithPrinter(
|
|
|
|
|
barPrinter, printValue, context);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
log("Error printing bar order: $e");
|
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
SnackBar(
|
|
|
|
|
content: Text(
|
|
|
|
|
'Error printing bar order: $e')),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-30 22:38:44 +07:00
|
|
|
},
|
|
|
|
|
label: 'Print',
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|