Compare commits

...
26 Commits
Author SHA1 Message Date
efrilm 3022d8de9f null safety 2025-09-19 19:12:35 +07:00
efrilm 6acfbdc4ca print on sales 2025-09-19 18:49:55 +07:00
efrilm 7b12793618 print 2025-09-19 18:23:55 +07:00
efrilm a6ac12c36a tracking print 2025-09-19 13:52:29 +07:00
efrilm e1e702bd76 fix null 2025-09-19 13:31:17 +07:00
efrilm fabb77d2b9 fix home error 2025-09-19 13:18:11 +07:00
efrilm f18a70b312 fix force close at home 2025-09-19 13:01:28 +07:00
efrilm 78914d7140 update 2025-09-18 21:47:34 +07:00
efrilm 937b98e45b update 2025-09-18 21:36:32 +07:00
efrilm c1be16845e update 2025-09-18 21:22:40 +07:00
efrilm dcb929cde5 printer setting null safety 2025-09-17 22:43:46 +07:00
efrilm 8aa326c513 printer setting null safety 2025-09-17 22:35:00 +07:00
efrilm bd02f389e5 table number null safety 2025-09-17 22:22:55 +07:00
efrilm 5534aad0d4 fix: product 2025-09-03 12:15:43 +07:00
efrilm 6599e6fe7c fear: rev 2 2025-09-02 19:49:01 +07:00
efrilm 3624f75bea feat: print void 2025-09-01 22:36:26 +07:00
efrilm 0d91d43866 fix: print split bill 2025-09-01 22:25:15 +07:00
efrilm dcd739e4a4 fix: checkout items 2025-09-01 22:12:56 +07:00
efrilm 631ac4bc46 feat: update 2025-08-15 17:08:17 +07:00
efrilm 7007f39766 feat: category report 2025-08-15 17:07:29 +07:00
efrilm 79585b253d feat: update 2025-08-15 16:49:24 +07:00
efrilm cc8012354f feat: date range picker 2025-08-15 16:09:25 +07:00
efrilm 2c75fcf582 feat: inventory report pdf 2025-08-15 01:36:50 +07:00
efrilm 34c0ad5411 feat: inventory report 2025-08-15 01:12:04 +07:00
efrilm f37814fec8 feat: report transaction 2025-08-14 21:19:34 +07:00
efrilm 0c375de6e4 fix: report profit loss 2025-08-14 17:32:16 +07:00
72 changed files with 8730 additions and 2395 deletions
+5 -1
View File
@@ -2,6 +2,8 @@ plugins {
id "com.android.application" id "com.android.application"
id "kotlin-android" id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin" id "dev.flutter.flutter-gradle-plugin"
id "com.google.gms.google-services"
id "com.google.firebase.crashlytics"
} }
def localProperties = new Properties() def localProperties = new Properties()
@@ -45,7 +47,7 @@ android {
applicationId "com.appscale.pos" applicationId "com.appscale.pos"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 21 minSdkVersion 23
targetSdkVersion 35 targetSdkVersion 35
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
@@ -69,4 +71,6 @@ dependencies {
//multiDex //multiDex
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation platform('com.google.firebase:firebase-bom:34.2.0')
implementation 'com.google.firebase:firebase-crashlytics'
} }
+29
View File
@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "1094037575589",
"project_id": "apskel-pos",
"storage_bucket": "apskel-pos.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1094037575589:android:5157684038a971a3d3fa4c",
"android_client_info": {
"package_name": "com.appscale.pos"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAle1ZcO4Z7wtNJUHkHEVkuBHr6mHcvPvI"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}
+2
View File
@@ -7,6 +7,8 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.4.3'
classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.6'
} }
} }
+2 -1
View File
@@ -70,7 +70,8 @@ class _CustomDatePickerState extends State<CustomDatePicker> {
), ),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: Padding( suffixIcon: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 16),
child: Assets.icons.calendar.svg(), child: Assets.icons.calendar.svg(),
), ),
prefix: widget.prefix, prefix: widget.prefix,
+409
View File
@@ -0,0 +1,409 @@
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
class DateRangePickerModal {
static Future<DateRangePickerSelectionChangedArgs?> show({
required BuildContext context,
String title = 'Pilih Rentang Tanggal',
DateTime? initialStartDate,
DateTime? initialEndDate,
DateTime? minDate,
DateTime? maxDate,
String confirmText = 'Pilih',
String cancelText = 'Batal',
Color primaryColor = Colors.blue,
Function(DateTime? startDate, DateTime? endDate)? onChanged,
}) async {
return await showDialog<DateRangePickerSelectionChangedArgs?>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) => _DateRangePickerDialog(
title: title,
initialStartDate: initialStartDate,
initialEndDate: initialEndDate,
minDate: minDate,
maxDate: maxDate,
confirmText: confirmText,
cancelText: cancelText,
primaryColor: primaryColor,
onChanged: onChanged,
),
);
}
}
class _DateRangePickerDialog extends StatefulWidget {
final String title;
final DateTime? initialStartDate;
final DateTime? initialEndDate;
final DateTime? minDate;
final DateTime? maxDate;
final String confirmText;
final String cancelText;
final Color primaryColor;
final Function(DateTime? startDate, DateTime? endDate)? onChanged;
const _DateRangePickerDialog({
required this.title,
this.initialStartDate,
this.initialEndDate,
this.minDate,
this.maxDate,
required this.confirmText,
required this.cancelText,
required this.primaryColor,
this.onChanged,
});
@override
State<_DateRangePickerDialog> createState() => _DateRangePickerDialogState();
}
class _DateRangePickerDialogState extends State<_DateRangePickerDialog>
with TickerProviderStateMixin {
DateRangePickerSelectionChangedArgs? _selectionChangedArgs;
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
late Animation<double> _fadeAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_scaleAnimation = Tween<double>(
begin: 0.8,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.elasticOut,
));
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _onSelectionChanged(DateRangePickerSelectionChangedArgs args) {
setState(() {
_selectionChangedArgs = args;
});
// Note: onChanged callback is now called only when confirm button is pressed
// This allows users to see real-time selection without triggering callbacks
}
String _getSelectionText() {
if (_selectionChangedArgs?.value is PickerDateRange) {
final PickerDateRange range = _selectionChangedArgs!.value;
if (range.startDate != null && range.endDate != null) {
return '${_formatDate(range.startDate!)} - ${_formatDate(range.endDate!)}';
} else if (range.startDate != null) {
return _formatDate(range.startDate!);
}
}
return 'Belum ada tanggal dipilih';
}
String _formatDate(DateTime date) {
final months = [
'Jan',
'Feb',
'Mar',
'Apr',
'Mei',
'Jun',
'Jul',
'Agu',
'Sep',
'Okt',
'Nov',
'Des'
];
return '${date.day} ${months[date.month - 1]} ${date.year}';
}
bool get _isValidSelection {
if (_selectionChangedArgs?.value is PickerDateRange) {
final PickerDateRange range = _selectionChangedArgs!.value;
return range.startDate != null && range.endDate != null;
}
return false;
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return FadeTransition(
opacity: _fadeAnimation,
child: ScaleTransition(
scale: _scaleAnimation,
child: Dialog(
backgroundColor: Colors.transparent,
elevation: 0,
insetPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
child: Container(
width: MediaQuery.of(context).size.width,
constraints: BoxConstraints(
maxWidth: 400,
maxHeight: MediaQuery.of(context).size.height * 0.85,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
widget.primaryColor,
widget.primaryColor.withOpacity(0.8),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Row(
children: [
Icon(
Icons.calendar_today_rounded,
color: Colors.white,
size: 24,
),
const SizedBox(width: 12),
Expanded(
child: Text(
widget.title,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
// Scrollable Content
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
// Selection Info
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: widget.primaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: widget.primaryColor.withOpacity(0.2),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Tanggal Terpilih:',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: widget.primaryColor,
),
),
const SizedBox(height: 4),
Text(
_getSelectionText(),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
],
),
),
// Date Picker
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16),
child: Container(
height: 320,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey.withOpacity(0.2),
),
),
child: SfDateRangePicker(
onSelectionChanged: _onSelectionChanged,
selectionMode:
DateRangePickerSelectionMode.range,
initialSelectedRange:
(widget.initialStartDate != null &&
widget.initialEndDate != null)
? PickerDateRange(
widget.initialStartDate,
widget.initialEndDate,
)
: null,
minDate: widget.minDate,
maxDate: widget.maxDate,
startRangeSelectionColor: widget.primaryColor,
endRangeSelectionColor: widget.primaryColor,
rangeSelectionColor:
widget.primaryColor.withOpacity(0.2),
todayHighlightColor: widget.primaryColor,
headerStyle: DateRangePickerHeaderStyle(
backgroundColor: Colors.transparent,
textAlign: TextAlign.center,
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
monthViewSettings:
DateRangePickerMonthViewSettings(
viewHeaderStyle:
DateRangePickerViewHeaderStyle(
backgroundColor:
Colors.grey.withOpacity(0.1),
textStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: widget.primaryColor,
),
),
),
selectionTextStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14,
),
rangeTextStyle: TextStyle(
color: widget.primaryColor,
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
),
),
],
),
),
),
// Action Buttons
Padding(
padding: const EdgeInsets.all(20),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.of(context).pop(),
style: OutlinedButton.styleFrom(
padding:
const EdgeInsets.symmetric(vertical: 14),
side: BorderSide(color: Colors.grey.shade400),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text(
widget.cancelText,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.grey,
),
),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _isValidSelection
? () {
// Call onChanged when confirm button is pressed
if (widget.onChanged != null &&
_selectionChangedArgs?.value
is PickerDateRange) {
final PickerDateRange range =
_selectionChangedArgs!.value;
widget.onChanged!(
range.startDate, range.endDate);
}
Navigator.of(context)
.pop(_selectionChangedArgs);
}
: null,
style: ElevatedButton.styleFrom(
backgroundColor: widget.primaryColor,
padding:
const EdgeInsets.symmetric(vertical: 14),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
disabledBackgroundColor: Colors.grey.shade300,
),
child: Text(
widget.confirmText,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: _isValidSelection
? Colors.white
: Colors.grey.shade600,
),
),
),
),
],
),
),
],
),
),
),
),
);
},
);
}
}
+1 -1
View File
@@ -2,6 +2,6 @@ class Variables {
static const String appName = 'POS Kasir Resto App'; static const String appName = 'POS Kasir Resto App';
static const String apiVersion = 'v1'; static const String apiVersion = 'v1';
// static const String baseUrl = 'http://192.168.1.202:8000'; // static const String baseUrl = 'http://192.168.1.202:8000';
static const String baseUrl = 'https://enaklo-pos-be.altru.id'; static const String baseUrl = 'https://api-pos.apskel.id';
static const int defaultLimit = 10; static const int defaultLimit = 10;
} }
+232 -24
View File
@@ -12,6 +12,7 @@ import 'package:enaklo_pos/data/datasources/settings_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart';
import 'package:enaklo_pos/data/type/bussines_type.dart'; import 'package:enaklo_pos/data/type/bussines_type.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart'; import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:barcode/barcode.dart'; import 'package:barcode/barcode.dart';
import 'package:image/image.dart' as img; import 'package:image/image.dart' as img;
@@ -22,6 +23,9 @@ Future<void> onPrint(
required Order order, required Order order,
}) async { }) async {
final outlet = await OutletLocalDatasource().get(); final outlet = await OutletLocalDatasource().get();
final settings = await SettingsLocalDatasource().getTax();
final authData = await AuthLocalDataSource().getAuthData();
if (outlet.businessType == BusinessType.restaurant) { if (outlet.businessType == BusinessType.restaurant) {
final checkerPrinter = final checkerPrinter =
await ProductLocalDatasource.instance.getPrinterByCode('checker'); await ProductLocalDatasource.instance.getPrinterByCode('checker');
@@ -29,8 +33,53 @@ Future<void> onPrint(
await ProductLocalDatasource.instance.getPrinterByCode('kitchen'); await ProductLocalDatasource.instance.getPrinterByCode('kitchen');
final barPrinter = final barPrinter =
await ProductLocalDatasource.instance.getPrinterByCode('bar'); await ProductLocalDatasource.instance.getPrinterByCode('bar');
final receiptPrinter =
await ProductLocalDatasource.instance.getPrinterByCode('receipt');
final authData = await AuthLocalDataSource().getAuthData(); if (receiptPrinter != null) {
try {
final printValue = await PrintDataoutputs.instance.printOrderV4(
order,
authData.user?.name ?? "",
'',
0,
0,
settings.value,
receiptPrinter.paper.toIntegerFromText,
order.orderType ?? "",
outlet,
productQuantity);
await PrinterService()
.printWithPrinter(receiptPrinter, printValue, context);
} catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Print receipt failed',
information: [
'Order ID: ${order.id}',
'Printer: ${receiptPrinter.name}',
],
);
log("Error printing receipt order: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing receipt order: $e')),
);
}
} else {
FirebaseCrashlytics.instance.recordError(
'Receipt printer not found',
null,
reason:
'Receipt printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer receipt')),
);
}
// Checker printer // Checker printer
if (checkerPrinter != null) { if (checkerPrinter != null) {
@@ -40,63 +89,144 @@ Future<void> onPrint(
order.tableNumber ?? "", order.tableNumber ?? "",
order.orderNumber ?? "", order.orderNumber ?? "",
authData.user?.name ?? "", authData.user?.name ?? "",
order.metadata?['customer_name'] ?? "",
checkerPrinter.paper.toIntegerFromText, checkerPrinter.paper.toIntegerFromText,
order.orderType ?? "", order.orderType ?? "",
); );
await PrinterService() if (productQuantity.isNotEmpty) {
// ignore: use_build_context_synchronously await PrinterService()
.printWithPrinter(checkerPrinter, printValue, context); // ignore: use_build_context_synchronously
} catch (e) { .printWithPrinter(checkerPrinter, printValue, context);
}
} catch (e, stackTrace) {
log("Error printing checker: $e"); log("Error printing checker: $e");
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing checker ${checkerPrinter.name}',
information: [
'Printer: checker',
'data: ${checkerPrinter.toMap()}',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing checker: $e')), SnackBar(content: Text('Error printing checker: $e')),
); );
} }
} else {
FirebaseCrashlytics.instance.recordError(
'Checker printer not found',
null,
reason:
'Checker printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer checker')),
);
} }
// Kitchen printer // Kitchen printer
if (kitchenPrinter != null) { if (kitchenPrinter != null) {
try { try {
final productByPrinter = productQuantity
.where((item) => item.product.printerType == 'kitchen')
.toList();
final printValue = await PrintDataoutputs.instance.printKitchen( final printValue = await PrintDataoutputs.instance.printKitchen(
productQuantity, productByPrinter,
order.tableNumber!, order.tableNumber ?? "",
order.orderNumber ?? "", order.orderNumber ?? "",
authData.user?.name ?? "", authData.user?.name ?? "",
order.metadata?['customer_name'] ?? "",
kitchenPrinter.paper.toIntegerFromText, kitchenPrinter.paper.toIntegerFromText,
order.orderType ?? "", order.orderType ?? "",
); );
await PrinterService() if (productByPrinter.isNotEmpty) {
.printWithPrinter(kitchenPrinter, printValue, context); await PrinterService()
} catch (e) { .printWithPrinter(kitchenPrinter, printValue, context);
}
} catch (e, stackTrace) {
log("Error printing kitchen order: $e"); log("Error printing kitchen order: $e");
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing kitchen ${kitchenPrinter.name}',
information: [
'Printer: kitchen',
'data: ${kitchenPrinter.toMap()}',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing kitchen order: $e')), SnackBar(content: Text('Error printing kitchen order: $e')),
); );
} }
} else {
FirebaseCrashlytics.instance.recordError(
'Kitchen printer not found',
null,
reason:
'Kitchen printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer kitchen')),
);
} }
// Bar printer // Bar printer
if (barPrinter != null) { if (barPrinter != null) {
try { try {
final productByPrinter = productQuantity
.where((item) => item.product.printerType == 'bar')
.toList();
final printValue = await PrintDataoutputs.instance.printBar( final printValue = await PrintDataoutputs.instance.printBar(
productQuantity, productByPrinter,
order.tableNumber ?? "", order.tableNumber ?? "",
order.orderNumber ?? "", order.orderNumber ?? "",
authData.user?.name ?? "", authData.user?.name ?? "",
order.metadata?['customer_name'] ?? "",
barPrinter.paper.toIntegerFromText, barPrinter.paper.toIntegerFromText,
order.orderType ?? "", order.orderType ?? "",
); );
await PrinterService() if (productByPrinter.isNotEmpty) {
.printWithPrinter(barPrinter, printValue, context); await PrinterService()
} catch (e) { .printWithPrinter(barPrinter, printValue, context);
}
} catch (e, stackTrace) {
log("Error printing bar order: $e"); log("Error printing bar order: $e");
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing bar ${barPrinter.name}',
information: [
'Printer: bar',
'data: ${barPrinter.toMap()}',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing bar order: $e')), SnackBar(content: Text('Error printing bar order: $e')),
); );
} }
} else {
FirebaseCrashlytics.instance.recordError(
'Bar printer not found',
null,
reason: 'Bar printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer bar')),
);
} }
} }
@@ -117,12 +247,34 @@ Future<void> onPrint(
await PrinterService() await PrinterService()
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
.printWithPrinter(ticketPrinter, printValue, context); .printWithPrinter(ticketPrinter, printValue, context);
} catch (e) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing ticket ${ticketPrinter.name}',
information: [
'Printer: ticket',
'data: ${ticketPrinter.toMap()}',
],
);
log("Error printing ticket: $e"); log("Error printing ticket: $e");
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing ticket: $e')), SnackBar(content: Text('Error printing ticket: $e')),
); );
} }
} else {
FirebaseCrashlytics.instance.recordError(
'Ticket printer not found',
null,
reason:
'Ticket printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer ticket')),
);
} }
} }
} }
@@ -133,6 +285,7 @@ Future<void> onPrintRecipt(
required String paymentMethod, required String paymentMethod,
required int nominalBayar, required int nominalBayar,
required int kembalian, required int kembalian,
required List<ProductQuantity> productQuantity,
}) async { }) async {
final receiptPrinter = final receiptPrinter =
await ProductLocalDatasource.instance.getPrinterByCode('receipt'); await ProductLocalDatasource.instance.getPrinterByCode('receipt');
@@ -143,16 +296,71 @@ Future<void> onPrintRecipt(
if (receiptPrinter != null) { if (receiptPrinter != null) {
try { try {
final printValue = await PrintDataoutputs.instance.printOrderV4( final printValue = await PrintDataoutputs.instance.printOrderV4(
order, order,
authData.user?.name ?? "", authData.user?.name ?? "",
paymentMethod, paymentMethod,
nominalBayar, nominalBayar,
kembalian, kembalian,
settings.value, settings.value,
receiptPrinter.paper.toIntegerFromText, receiptPrinter.paper.toIntegerFromText,
order.orderType ?? "", order.orderType ?? "",
outlet, outlet,
productQuantity);
await PrinterService()
.printWithPrinter(receiptPrinter, printValue, context);
} catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Print receipt failed',
information: [
'Order ID: ${order.id}',
'Payment Method: $paymentMethod',
'Printer: ${receiptPrinter.name}',
],
); );
log("Error printing receipt order: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing receipt order: $e')),
);
}
} else {
FirebaseCrashlytics.instance.recordError(
'Kitchen printer not found',
null,
reason: 'Kitchen printer not found / Printer not setting in printer page',
information: [
'Order ID: ${order.id}',
],
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Anda belum menghubungkan printer kitchen')),
);
}
}
Future<void> onPrinVoidRecipt(
context, {
required Order order,
required List<OrderItem> productItemVoid,
required int totalVoid,
}) async {
final receiptPrinter =
await ProductLocalDatasource.instance.getPrinterByCode('receipt');
final authData = await AuthLocalDataSource().getAuthData();
final settings = await SettingsLocalDatasource().getTax();
final outlet = await OutletLocalDatasource().get();
if (receiptPrinter != null) {
try {
final printValue = await PrintDataoutputs.instance.printVoidOrder(
order,
authData.user?.name ?? "",
settings.value,
receiptPrinter.paper.toIntegerFromText,
totalVoid,
outlet,
productItemVoid);
await PrinterService() await PrinterService()
.printWithPrinter(receiptPrinter, printValue, context); .printWithPrinter(receiptPrinter, printValue, context);
} catch (e) { } catch (e) {
+2 -2
View File
@@ -7,8 +7,8 @@ import 'package:shared_preferences/shared_preferences.dart';
class DioClient { class DioClient {
static final Dio _dio = Dio(BaseOptions( static final Dio _dio = Dio(BaseOptions(
connectTimeout: const Duration(seconds: 10), connectTimeout: const Duration(minutes: 1),
receiveTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(minutes: 1),
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
}, },
+568
View File
@@ -0,0 +1,568 @@
import 'dart:io';
import 'package:enaklo_pos/core/utils/helper_pdf_service.dart';
import 'package:enaklo_pos/data/datasources/outlet_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/inventory_analytic_response_model.dart';
import 'package:flutter/services.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
class InventoryReport {
static final primaryColor = PdfColor.fromHex("36175e");
static Future<File> previewPdf({
required String searchDateFormatted,
required InventoryAnalyticData? inventory,
}) async {
final pdf = pw.Document();
final ByteData dataImage = await rootBundle.load('assets/logo/logo.png');
final Uint8List bytes = dataImage.buffer.asUint8List();
final outlet = await OutletLocalDatasource().get();
final image = pw.MemoryImage(bytes);
pdf.addPage(
pw.MultiPage(
pageFormat: PdfPageFormat.a4,
margin: pw.EdgeInsets.zero,
build: (pw.Context context) {
return [
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
// Bagian kiri - Logo dan Info Perusahaan
pw.Row(
crossAxisAlignment: pw.CrossAxisAlignment.center,
children: [
// Icon/Logo placeholder (bisa diganti dengan gambar logo)
pw.Container(
width: 40,
height: 40,
child: pw.Image(image),
),
pw.SizedBox(width: 15),
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text(
'Apskel',
style: pw.TextStyle(
fontSize: 28,
fontWeight: pw.FontWeight.bold,
color: primaryColor,
),
),
pw.SizedBox(height: 4),
pw.Text(
outlet.name ?? "",
style: pw.TextStyle(
fontSize: 16,
color: PdfColors.grey700,
),
),
pw.SizedBox(height: 2),
pw.Text(
outlet.address ?? "",
style: pw.TextStyle(
fontSize: 12,
color: PdfColors.grey600,
),
),
],
),
],
),
// Bagian kanan - Info Laporan
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.end,
children: [
pw.Text(
'Laporan Transaksi',
style: pw.TextStyle(
fontSize: 24,
fontWeight: pw.FontWeight.bold,
color: PdfColors.grey800,
),
),
pw.SizedBox(height: 8),
pw.Text(
searchDateFormatted,
style: pw.TextStyle(
fontSize: 14,
color: PdfColors.grey600,
),
),
pw.SizedBox(height: 4),
pw.Text(
'Laporan',
style: pw.TextStyle(
fontSize: 12,
color: PdfColors.grey500,
),
),
],
),
],
),
),
pw.Container(
width: double.infinity,
height: 3,
color: primaryColor,
),
// Summary
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('1. Ringkasan'),
pw.SizedBox(height: 30),
pw.Row(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Expanded(
flex: 1,
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSummaryItem(
'Total Item',
(inventory?.summary.totalProducts ?? 0)
.toString(),
),
_buildSummaryItem(
'Total Item Masuk',
(inventory?.products.fold<num>(
0,
(sum, item) =>
sum + (item.totalIn)) ??
0)
.toString(),
),
_buildSummaryItem(
'Total Item Keluar',
(inventory?.products.fold<num>(0,
(sum, item) => sum + (item.totalOut)))
.toString(),
),
],
),
),
pw.SizedBox(width: 20),
pw.Expanded(
flex: 1,
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSummaryItem(
'Total Ingredient',
(inventory?.summary.totalIngredients ?? 0)
.toString(),
),
_buildSummaryItem(
'Total Ingredient Masuk',
(inventory?.ingredients.fold<num>(
0,
(sum, item) =>
sum + (item.totalIn)) ??
0)
.toString(),
),
_buildSummaryItem(
'Total Ingredient Keluar',
(inventory?.ingredients.fold<num>(
0,
(sum, item) =>
sum + (item.totalOut)) ??
0)
.toString(),
),
],
),
),
],
),
],
),
),
// Summary Item
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
children: [
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('2. Item'),
pw.SizedBox(height: 30),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // Stock
3: pw.FlexColumnWidth(2), // Masuk
4: pw.FlexColumnWidth(2), // Keluar
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Kategori'),
_buildHeaderCell('Stock'),
_buildHeaderCell('Masuk'),
_buildHeaderCell('Keluar'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // Stock
3: pw.FlexColumnWidth(2), // Masuk
4: pw.FlexColumnWidth(2), // Keluar
},
children: inventory?.products
.map((item) => _buildProductDataRow(
item,
inventory.products.indexOf(item) %
2 ==
0,
))
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // Stock
3: pw.FlexColumnWidth(2), // Masuk
4: pw.FlexColumnWidth(2), // Keluar
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(''),
_buildTotalCell(
(inventory?.products.fold<num>(
0,
(sum, item) =>
sum + (item.quantity)) ??
0)
.toString(),
),
_buildTotalCell(
(inventory?.products.fold<num>(
0,
(sum, item) =>
sum + (item.totalIn)) ??
0)
.toString(),
),
_buildTotalCell(
(inventory?.products.fold<num>(
0,
(sum, item) =>
sum + (item.totalOut)) ??
0)
.toString(),
),
],
),
],
),
),
],
),
],
),
),
// Summary Ingredient
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
children: [
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('3. Ingredient'),
pw.SizedBox(height: 30),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Name
1: pw.FlexColumnWidth(1), // Stock
2: pw.FlexColumnWidth(2), // Masuk
3: pw.FlexColumnWidth(2), // Keluar
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Stock'),
_buildHeaderCell('Masuk'),
_buildHeaderCell('Keluar'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Name
1: pw.FlexColumnWidth(1), // Stock
2: pw.FlexColumnWidth(2), // Masuk
3: pw.FlexColumnWidth(2), // Keluar
},
children: inventory?.ingredients
.map((item) => _buildIngredientsDataRow(
item,
inventory.ingredients.indexOf(item) %
2 ==
0,
))
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Name
1: pw.FlexColumnWidth(1), // Stock
2: pw.FlexColumnWidth(2), // Masuk
3: pw.FlexColumnWidth(2), // Keluar
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(
(inventory?.ingredients.fold<num>(
0,
(sum, item) =>
sum + (item.quantity)) ??
0)
.toString(),
),
_buildTotalCell(
(inventory?.ingredients.fold<num>(
0,
(sum, item) =>
sum + (item.totalIn)) ??
0)
.toString(),
),
_buildTotalCell(
(inventory?.ingredients.fold<num>(
0,
(sum, item) =>
sum + (item.totalOut)) ??
0)
.toString(),
),
],
),
],
),
),
],
),
],
),
),
];
}),
);
return HelperPdfService.saveDocument(
name:
'Apskel POS | Inventory Report | ${DateTime.now().millisecondsSinceEpoch}.pdf',
pdf: pdf);
}
static pw.Widget _buildSectionWidget(String title) {
return pw.Text(
title,
style: pw.TextStyle(
fontSize: 20,
fontWeight: pw.FontWeight.bold,
color: primaryColor,
),
);
}
static pw.Widget _buildSummaryItem(
String label,
String value, {
pw.TextStyle? valueStyle,
pw.TextStyle? labelStyle,
}) {
return pw.Container(
padding: pw.EdgeInsets.only(bottom: 8),
margin: pw.EdgeInsets.only(bottom: 16),
decoration: pw.BoxDecoration(
border: pw.Border(
bottom: pw.BorderSide(
color: PdfColors.grey300,
),
),
),
child: pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text(label, style: labelStyle),
pw.Text(
value,
style: valueStyle ??
pw.TextStyle(
fontWeight: pw.FontWeight.bold,
),
),
],
),
);
}
static pw.Widget _buildHeaderCell(String text) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: pw.Text(
text,
style: pw.TextStyle(
color: PdfColors.white,
fontWeight: pw.FontWeight.bold,
fontSize: 12,
),
textAlign: pw.TextAlign.center,
),
);
}
static pw.Widget _buildDataCell(String text,
{pw.Alignment alignment = pw.Alignment.center, PdfColor? textColor}) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
alignment: alignment,
child: pw.Text(
text,
style: pw.TextStyle(
fontSize: 12,
color: textColor ?? PdfColors.black,
fontWeight: pw.FontWeight.normal,
),
textAlign: alignment == pw.Alignment.centerLeft
? pw.TextAlign.left
: pw.TextAlign.center,
),
);
}
static pw.Widget _buildTotalCell(String text) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: pw.Text(
text,
style: pw.TextStyle(
color: PdfColors.white,
fontWeight: pw.FontWeight.bold,
fontSize: 12,
),
textAlign: pw.TextAlign.center,
),
);
}
static pw.TableRow _buildProductDataRow(
InventoryProductItem product, bool isEven) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: product.isZeroStock
? PdfColors.red100
: product.isLowStock
? PdfColors.yellow100
: isEven
? PdfColors.grey50
: PdfColors.white,
),
children: [
_buildDataCell(product.productName, alignment: pw.Alignment.centerLeft),
_buildDataCell(product.categoryName,
alignment: pw.Alignment.centerLeft),
_buildDataCell(product.quantity.toString()),
_buildDataCell(product.totalIn.toString()),
_buildDataCell(product.totalOut.toString()),
],
);
}
static pw.TableRow _buildIngredientsDataRow(
InventoryIngredientItem item, bool isEven) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: item.isZeroStock
? PdfColors.red100
: item.isLowStock
? PdfColors.yellow100
: isEven
? PdfColors.grey50
: PdfColors.white,
),
children: [
_buildDataCell(item.ingredientName, alignment: pw.Alignment.centerLeft),
_buildDataCell(item.quantity.toString()),
_buildDataCell(item.totalIn.toString()),
_buildDataCell(item.totalOut.toString()),
],
);
}
}
+124 -14
View File
@@ -1,4 +1,5 @@
import 'dart:developer'; import 'dart:developer';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart'; import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart'; import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
@@ -20,17 +21,36 @@ class PrinterService {
} }
// Connect to the printer // Connect to the printer
bool connected = await PrintBluetoothThermal.connect( bool connected =
macPrinterAddress: macAddress); await PrintBluetoothThermal.connect(macPrinterAddress: macAddress);
if (connected) { if (connected) {
log("Successfully connected to Bluetooth printer: $macAddress"); log("Successfully connected to Bluetooth printer: $macAddress");
} else { } else {
FirebaseCrashlytics.instance.recordError(
'Failed to connect to Bluetooth printer',
null,
reason: 'Failed to connect to Bluetooth printe',
information: [
'function: connectBluetoothPrinter(String macAddress)',
'macAddress: $macAddress',
],
);
log("Failed to connect to Bluetooth printer: $macAddress"); log("Failed to connect to Bluetooth printer: $macAddress");
} }
return connected; return connected;
} catch (e) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error connecting to Bluetooth printer',
information: [
'function: connectBluetoothPrinter(String macAddress)',
'Printer: Bluetooth printer',
'macAddress: $macAddress',
],
);
log("Error connecting to Bluetooth printer: $e"); log("Error connecting to Bluetooth printer: $e");
return false; return false;
} }
@@ -49,11 +69,30 @@ class PrinterService {
if (printResult) { if (printResult) {
log("Successfully printed via Bluetooth"); log("Successfully printed via Bluetooth");
} else { } else {
FirebaseCrashlytics.instance.recordError(
'Failed to print via Bluetooth',
null,
reason: 'Failed to print via Bluetooth',
information: [
'function: printBluetooth(List<int> printData)',
'printData: $printData',
],
);
log("Failed to print via Bluetooth"); log("Failed to print via Bluetooth");
} }
return printResult; return printResult;
} catch (e) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing via Bluetooth',
information: [
'function: printBluetooth(List<int> printData)',
'Printer: Bluetooth printer',
'printData: $printData',
],
);
log("Error printing via Bluetooth: $e"); log("Error printing via Bluetooth: $e");
return false; return false;
} }
@@ -64,42 +103,94 @@ class PrinterService {
try { try {
final printer = PrinterNetworkManager(ipAddress); final printer = PrinterNetworkManager(ipAddress);
PosPrintResult connect = await printer.connect(); PosPrintResult connect = await printer.connect();
if (connect == PosPrintResult.success) { if (connect == PosPrintResult.success) {
PosPrintResult printing = await printer.printTicket(printData); PosPrintResult printing = await printer.printTicket(printData);
printer.disconnect(); printer.disconnect();
if (printing == PosPrintResult.success) { if (printing == PosPrintResult.success) {
log("Successfully printed via Network printer: $ipAddress"); log("Successfully printed via Network printer: $ipAddress");
return true; return true;
} else { } else {
FirebaseCrashlytics.instance.recordError(
'Failed to print via Network printer: ${printing.msg}',
null,
reason: 'Failed to print via Network printer',
information: [
'function: printNetwork(String ipAddress, List<int> printData)',
'Printer: Network printer',
'ipAddress: $ipAddress',
'printData: $printData',
],
);
log("Failed to print via Network printer: ${printing.msg}"); log("Failed to print via Network printer: ${printing.msg}");
return false; return false;
} }
} else { } else {
FirebaseCrashlytics.instance.recordError(
'Failed to connect to Network printer: ${connect.msg}',
null,
reason: 'Failed to connectNetwork printer',
information: [
'function: printNetwork(String ipAddress, List<int> printData)',
'Printer: Network printer',
'ipAddress: $ipAddress',
'printData: $printData',
],
);
log("Failed to connect to Network printer: ${connect.msg}"); log("Failed to connect to Network printer: ${connect.msg}");
return false; return false;
} }
} catch (e) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing via Network',
information: [
'function: printNetwork(String ipAddress, List<int> printData)',
'Printer: Network printer',
'ipAddress: $ipAddress',
'printData: $printData',
],
);
log("Error printing via Network: $e"); log("Error printing via Network: $e");
return false; return false;
} }
} }
/// Print with automatic printer type detection /// Print with automatic printer type detection
Future<bool> printWithPrinter(PrintModel printer, List<int> printData, BuildContext context) async { Future<bool> printWithPrinter(
PrintModel printer, List<int> printData, BuildContext context) async {
try { try {
if (printer.type == 'Bluetooth') { if (printer.type == 'Bluetooth') {
bool connected = await connectBluetoothPrinter(printer.address); bool connected = await connectBluetoothPrinter(printer.address);
if (!connected) { if (!connected) {
FirebaseCrashlytics.instance.recordError(
'Failed to connect to Bluetooth printer',
null,
reason: 'Failed to connect to Bluetooth printe',
information: [
'function: connectBluetoothPrinter(String macAddress)',
'Printer: ${printer.name}',
'macAddress: ${printer.address}',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to connect to ${printer.name}')), SnackBar(content: Text('Failed to connect to ${printer.name}')),
); );
return false; return false;
} }
bool printResult = await printBluetooth(printData); bool printResult = await printBluetooth(printData);
if (!printResult) { if (!printResult) {
FirebaseCrashlytics.instance.recordError(
'Failed to print to ${printer.name}',
null,
information: [
'function: await printBluetooth(printData);',
'print: $printData',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to print to ${printer.name}')), SnackBar(content: Text('Failed to print to ${printer.name}')),
); );
@@ -108,13 +199,32 @@ class PrinterService {
} else { } else {
bool printResult = await printNetwork(printer.address, printData); bool printResult = await printNetwork(printer.address, printData);
if (!printResult) { if (!printResult) {
FirebaseCrashlytics.instance.recordError(
'Failed to connect to Network Printer',
null,
reason: 'Failed to connect to Network Printer',
information: [
'function: await printNetwork(printer.address, printData);',
'Printer: ${printer.name}',
'ipAddress: ${printer.address}',
'print: $printData',
],
);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to print to ${printer.name}')), SnackBar(content: Text('Failed to print to ${printer.name}')),
); );
} }
return printResult; return printResult;
} }
} catch (e) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError(
e,
stackTrace,
reason: 'Error printing with printer ${printer.name}',
information: [
'Printer: ${printer.name}',
],
);
log("Error printing with printer ${printer.name}: $e"); log("Error printing with printer ${printer.name}: $e");
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error printing to ${printer.name}: $e')), SnackBar(content: Text('Error printing to ${printer.name}: $e')),
@@ -154,4 +264,4 @@ class PrinterService {
return []; return [];
} }
} }
} }
+912
View File
@@ -0,0 +1,912 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:enaklo_pos/core/extensions/string_ext.dart';
import 'package:enaklo_pos/core/utils/helper_pdf_service.dart';
import 'package:enaklo_pos/data/models/response/category_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_method_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/product_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/profit_loss_response_model.dart';
import 'package:enaklo_pos/presentation/home/models/outlet_model.dart';
import 'package:flutter/services.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
class TransactionReport {
static final primaryColor = PdfColor.fromHex("36175e");
static Future<File> previewPdf({
required Outlet outlet,
required String searchDateFormatted,
required CategoryAnalyticData? categoryAnalyticData,
required ProfitLossData? profitLossData,
required PaymentMethodAnalyticData? paymentMethodAnalyticData,
required ProductAnalyticData? productAnalyticData,
}) async {
final pdf = pw.Document();
final ByteData dataImage = await rootBundle.load('assets/logo/logo.png');
final Uint8List bytes = dataImage.buffer.asUint8List();
final profitLossProductSummary = {
'totalRevenue': profitLossData?.productData
.fold<num>(0, (sum, item) => sum + (item.revenue)) ??
0,
'totalCost': profitLossData?.productData
.fold<num>(0, (sum, item) => sum + (item.cost)) ??
0,
'totalGrossProfit': profitLossData?.productData
.fold<num>(0, (sum, item) => sum + (item.grossProfit)) ??
0,
'totalQuantity': profitLossData?.productData
.fold<num>(0, (sum, item) => sum + (item.quantitySold)) ??
0,
};
final categorySummary = {
'totalRevenue': categoryAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.totalRevenue)) ??
0,
'orderCount': categoryAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.orderCount)) ??
0,
'productCount': categoryAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.productCount)) ??
0,
'totalQuantity': categoryAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.totalQuantity)) ??
0,
};
final productItemSummary = {
'totalRevenue': productAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.revenue)) ??
0,
'orderCount': productAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.orderCount)) ??
0,
'totalQuantitySold': productAnalyticData?.data
.fold<num>(0, (sum, item) => sum + (item.quantitySold)) ??
0,
};
// Membuat objek Image dari gambar
final image = pw.MemoryImage(bytes);
pdf.addPage(
pw.MultiPage(
pageFormat: PdfPageFormat.a4,
margin: pw.EdgeInsets.zero,
build: (pw.Context context) {
return [
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
// Bagian kiri - Logo dan Info Perusahaan
pw.Row(
crossAxisAlignment: pw.CrossAxisAlignment.center,
children: [
// Icon/Logo placeholder (bisa diganti dengan gambar logo)
pw.Container(
width: 40,
height: 40,
child: pw.Image(image),
),
pw.SizedBox(width: 15),
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text(
'Apskel',
style: pw.TextStyle(
fontSize: 28,
fontWeight: pw.FontWeight.bold,
color: primaryColor,
),
),
pw.SizedBox(height: 4),
pw.Text(
outlet.name ?? "",
style: pw.TextStyle(
fontSize: 16,
color: PdfColors.grey700,
),
),
pw.SizedBox(height: 2),
pw.Text(
outlet.address ?? "",
style: pw.TextStyle(
fontSize: 12,
color: PdfColors.grey600,
),
),
],
),
],
),
// Bagian kanan - Info Laporan
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.end,
children: [
pw.Text(
'Laporan Transaksi',
style: pw.TextStyle(
fontSize: 24,
fontWeight: pw.FontWeight.bold,
color: PdfColors.grey800,
),
),
pw.SizedBox(height: 8),
pw.Text(
searchDateFormatted,
style: pw.TextStyle(
fontSize: 14,
color: PdfColors.grey600,
),
),
pw.SizedBox(height: 4),
pw.Text(
'Laporan',
style: pw.TextStyle(
fontSize: 12,
color: PdfColors.grey500,
),
),
],
),
],
),
),
pw.Container(
width: double.infinity,
height: 3,
color: primaryColor,
),
// Summary
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('1. Ringkasan'),
pw.SizedBox(height: 30),
pw.Row(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Expanded(
flex: 1,
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSummaryItem(
'Total Penjualan (termasuk rasik)',
(profitLossData?.summary.totalRevenue ?? 0)
.toString()
.currencyFormatRpV2,
),
_buildSummaryItem(
'Total Terjual',
(profitLossData?.summary.totalOrders ?? 0)
.toString(),
),
_buildSummaryItem(
'HPP',
'${(profitLossData?.summary.totalCost ?? 0).toString().currencyFormatRpV2} | ${(((profitLossData?.summary.totalCost ?? 0) / (profitLossData?.summary.totalRevenue ?? 1)) * 100).round()}%',
),
_buildSummaryItem(
'Laba Kotor',
'${(profitLossData?.summary.grossProfit ?? 0).toString().currencyFormatRpV2} | ${(profitLossData?.summary.grossProfitMargin ?? 0).round()}%',
valueStyle: pw.TextStyle(
color: PdfColors.green800,
fontWeight: pw.FontWeight.bold,
fontSize: 16,
),
labelStyle: pw.TextStyle(
color: PdfColors.green800,
fontWeight: pw.FontWeight.bold,
fontSize: 16,
),
),
],
),
),
pw.SizedBox(width: 20),
pw.Expanded(
flex: 1,
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSummaryItem(
'Biaya Lain lain',
'${(profitLossData?.summary.totalTax ?? 0).toString().currencyFormatRpV2} | ${(((profitLossData?.summary.totalTax ?? 0) / (profitLossData?.summary.totalRevenue ?? 1)) * 100).round()}%',
),
_buildSummaryItem(
'Laba/Rugi',
'${(profitLossData?.summary.netProfit ?? 0).toString().currencyFormatRpV2} | ${(profitLossData?.summary.netProfitMargin ?? 0).round()}%',
valueStyle: pw.TextStyle(
color: PdfColors.blue800,
fontWeight: pw.FontWeight.bold,
fontSize: 16,
),
labelStyle: pw.TextStyle(
color: PdfColors.blue800,
fontWeight: pw.FontWeight.bold,
fontSize: 16,
),
),
],
),
),
],
),
pw.SizedBox(height: 16),
pw.Text(
"Laba Rugi Perproduk",
style: pw.TextStyle(
fontSize: 16,
fontWeight: pw.FontWeight.bold,
color: primaryColor,
),
),
pw.SizedBox(height: 20),
pw.Column(
children: [
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(1), // Qty
2: pw.FlexColumnWidth(2.5), // Pendapatan
3: pw.FlexColumnWidth(2), // HPP
4: pw.FlexColumnWidth(2), // Laba Kotor
5: pw.FlexColumnWidth(2), // Margin (%)
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Produk'),
_buildHeaderCell('Qty'),
_buildHeaderCell('Pendapatan'),
_buildHeaderCell('HPP'),
_buildHeaderCell('Laba Kotor'),
_buildHeaderCell('Margin (%)'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(1), // Qty
2: pw.FlexColumnWidth(2.5), // Pendapatan
3: pw.FlexColumnWidth(2), // HPP
4: pw.FlexColumnWidth(2), // Laba Kotor
5: pw.FlexColumnWidth(2), // Margin (%)
},
children: profitLossData?.productData
.map(
(profitLoss) => _buildPerProductDataRow(
product: profitLoss.productName,
qty: profitLoss.quantitySold.toString(),
pendapatan: profitLoss.revenue
.toString()
.currencyFormatRpV2,
hpp: profitLoss.cost
.toString()
.currencyFormatRpV2,
labaKotor: profitLoss.grossProfit
.toString()
.currencyFormatRpV2,
margin:
'${profitLoss.grossProfitMargin.round()}%',
isEven: profitLossData.productData
.indexOf(profitLoss) %
2 ==
0,
),
)
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(1), // Qty
2: pw.FlexColumnWidth(2.5), // Pendapatan
3: pw.FlexColumnWidth(2), // HPP
4: pw.FlexColumnWidth(2), // Laba Kotor
5: pw.FlexColumnWidth(2), // Margin (%)
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(
profitLossProductSummary['totalQuantity']
.toString()),
_buildTotalCell(
profitLossProductSummary['totalRevenue']
.toString()
.currencyFormatRpV2),
_buildTotalCell(
profitLossProductSummary['totalCost']
.toString()
.currencyFormatRpV2),
_buildTotalCell(
profitLossProductSummary['totalGrossProfit']
.toString()
.currencyFormatRpV2),
_buildTotalCell(''),
],
),
],
),
),
],
),
],
),
),
// Summary Payment Method
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
children: [
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('2. Ringkasan Metode Pembayaran'),
pw.SizedBox(height: 30),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Nama
1: pw.FlexColumnWidth(1), // Tipe
2: pw.FlexColumnWidth(2.5), // Jumlah Order
3: pw.FlexColumnWidth(2), // Total Amount
4: pw.FlexColumnWidth(2), // Presentase
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Tipe'),
_buildHeaderCell('Jumlah Order'),
_buildHeaderCell('Total Amount'),
_buildHeaderCell('Presentase'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Nama
1: pw.FlexColumnWidth(1), // Tipe
2: pw.FlexColumnWidth(2.5), // Jumlah Order
3: pw.FlexColumnWidth(2), // Total Amount
4: pw.FlexColumnWidth(2), // Presentase
},
children: paymentMethodAnalyticData?.data
.map(
(payment) => _buildPaymentMethodDataRow(
name: payment.paymentMethodName,
tipe: payment.paymentMethodType
.toTitleCase(),
jumlahOrder:
payment.orderCount.toString(),
totalAmount: payment.totalAmount
.toString()
.currencyFormatRpV2,
presentase:
'${payment.percentage.round()}%',
isEven: paymentMethodAnalyticData.data
.indexOf(payment) %
2 ==
0,
),
)
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(1), // Qty
2: pw.FlexColumnWidth(2.5), // Pendapatan
3: pw.FlexColumnWidth(2), // HPP
4: pw.FlexColumnWidth(2), // Laba Kotor
5: pw.FlexColumnWidth(2), // Margin (%)
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(''),
_buildTotalCell((paymentMethodAnalyticData
?.summary.totalOrders ??
0)
.toString()),
_buildTotalCell((paymentMethodAnalyticData
?.summary.totalAmount ??
0)
.toString()
.currencyFormatRpV2),
_buildTotalCell(''),
],
),
],
),
),
],
),
],
),
),
// Summary Category
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('3. Ringkasan Kategori'),
pw.SizedBox(height: 30),
pw.Column(
children: [
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Nama
1: pw.FlexColumnWidth(2), // Total Product
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Jumlah Order
4: pw.FlexColumnWidth(2.5), // Presentase
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Total Produk'),
_buildHeaderCell('Qty'),
_buildHeaderCell('Jumlah Order'),
_buildHeaderCell('Pendapatan'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Nama
1: pw.FlexColumnWidth(2), // Total Product
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Jumlah Order
4: pw.FlexColumnWidth(2.5), // Presentase
},
children: categoryAnalyticData?.data
.map((category) => _buildCategoryDataRow(
name: category.categoryName,
totalProduct:
category.productCount.toString(),
qty: category.totalQuantity.toString(),
jumlahOrder:
category.orderCount.toString(),
pendapatan: category.totalRevenue
.toString()
.currencyFormatRpV2,
isEven: categoryAnalyticData.data
.indexOf(category) %
2 ==
0,
))
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Nama
1: pw.FlexColumnWidth(2), // Total Product
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Jumlah Order
4: pw.FlexColumnWidth(2.5), // Presentase
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(
categorySummary['productCount'].toString()),
_buildTotalCell(categorySummary['totalQuantity']
.toString()),
_buildTotalCell(
categorySummary['orderCount'].toString()),
_buildTotalCell(categorySummary['totalRevenue']
.toString()
.currencyFormatRpV2),
],
),
],
),
),
],
),
],
),
),
// Summary Item
pw.Container(
padding: pw.EdgeInsets.all(20),
child: pw.Column(
children: [
pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
_buildSectionWidget('4. Ringkasan Item'),
pw.SizedBox(height: 30),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
topLeft: pw.Radius.circular(8),
topRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Order
4: pw.FlexColumnWidth(2), // Pendapatan
5: pw.FlexColumnWidth(2), // Average
},
children: [
pw.TableRow(
children: [
_buildHeaderCell('Produk'),
_buildHeaderCell('Kategori'),
_buildHeaderCell('Qty'),
_buildHeaderCell('Order'),
_buildHeaderCell('Pendapatan'),
_buildHeaderCell('Rata Rata'),
],
),
],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: PdfColors.white,
),
child: pw.Table(
columnWidths: {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Order
4: pw.FlexColumnWidth(2), // Pendapatan
5: pw.FlexColumnWidth(2), // Average
},
children: productAnalyticData?.data
.map((item) => _buildItemDataRow(
product: item.productName,
category: item.categoryName,
qty: item.quantitySold.toString(),
order: item.orderCount.toString(),
pendapatan: item.revenue
.toString()
.currencyFormatRpV2,
average: item.averagePrice
.round()
.toString()
.currencyFormatRpV2,
isEven: productAnalyticData.data
.indexOf(item) %
2 ==
0,
))
.toList() ??
[],
),
),
pw.Container(
decoration: pw.BoxDecoration(
color: primaryColor, // Purple color
borderRadius: pw.BorderRadius.only(
bottomLeft: pw.Radius.circular(8),
bottomRight: pw.Radius.circular(8),
),
),
child: pw.Table(
columnWidths: const {
0: pw.FlexColumnWidth(2.5), // Produk
1: pw.FlexColumnWidth(2), // Kategori
2: pw.FlexColumnWidth(1), // qty
3: pw.FlexColumnWidth(2), // Order
4: pw.FlexColumnWidth(2), // Pendapatan
5: pw.FlexColumnWidth(2), // Average
},
children: [
pw.TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(''),
_buildTotalCell(
productItemSummary['totalQuantitySold']
.toString()),
_buildTotalCell(productItemSummary['orderCount']
.toString()),
_buildTotalCell(
productItemSummary['totalRevenue']
.toString()
.currencyFormatRpV2),
_buildTotalCell(''),
],
),
],
),
),
],
),
],
),
),
];
},
),
);
return HelperPdfService.saveDocument(
name: 'Laporan Transaksi | $searchDateFormatted.pdf', pdf: pdf);
}
static pw.Widget _buildSectionWidget(String title) {
return pw.Text(
title,
style: pw.TextStyle(
fontSize: 20,
fontWeight: pw.FontWeight.bold,
color: primaryColor,
),
);
}
static pw.Widget _buildSummaryItem(
String label,
String value, {
pw.TextStyle? valueStyle,
pw.TextStyle? labelStyle,
}) {
return pw.Container(
padding: pw.EdgeInsets.only(bottom: 8),
margin: pw.EdgeInsets.only(bottom: 16),
decoration: pw.BoxDecoration(
border: pw.Border(
bottom: pw.BorderSide(
color: PdfColors.grey300,
),
),
),
child: pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text(label, style: labelStyle),
pw.Text(
value,
style: valueStyle ??
pw.TextStyle(
fontWeight: pw.FontWeight.bold,
),
),
],
),
);
}
static pw.Widget _buildHeaderCell(String text) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: pw.Text(
text,
style: pw.TextStyle(
color: PdfColors.white,
fontWeight: pw.FontWeight.bold,
fontSize: 12,
),
textAlign: pw.TextAlign.center,
),
);
}
static pw.Widget _buildDataCell(String text,
{pw.Alignment alignment = pw.Alignment.center, PdfColor? textColor}) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
alignment: alignment,
child: pw.Text(
text,
style: pw.TextStyle(
fontSize: 12,
color: textColor ?? PdfColors.black,
fontWeight: pw.FontWeight.normal,
),
textAlign: alignment == pw.Alignment.centerLeft
? pw.TextAlign.left
: pw.TextAlign.center,
),
);
}
static pw.Widget _buildTotalCell(String text) {
return pw.Container(
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: pw.Text(
text,
style: pw.TextStyle(
color: PdfColors.white,
fontWeight: pw.FontWeight.bold,
fontSize: 12,
),
textAlign: pw.TextAlign.center,
),
);
}
static pw.TableRow _buildPerProductDataRow({
required String product,
required String qty,
required String pendapatan,
required String hpp,
required String labaKotor,
required String margin,
required bool isEven,
}) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: isEven ? PdfColors.grey50 : PdfColors.white,
),
children: [
_buildDataCell(product, alignment: pw.Alignment.centerLeft),
_buildDataCell(qty),
_buildDataCell(pendapatan),
_buildDataCell(hpp, textColor: PdfColors.red600),
_buildDataCell(labaKotor, textColor: PdfColors.green600),
_buildDataCell(margin),
],
);
}
static pw.TableRow _buildPaymentMethodDataRow({
required String name,
required String tipe,
required String jumlahOrder,
required String totalAmount,
required String presentase,
required bool isEven,
}) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: isEven ? PdfColors.grey50 : PdfColors.white,
),
children: [
_buildDataCell(name, alignment: pw.Alignment.centerLeft),
_buildDataCell(tipe),
_buildDataCell(jumlahOrder),
_buildDataCell(totalAmount),
_buildDataCell(presentase),
],
);
}
static pw.TableRow _buildCategoryDataRow({
required String name,
required String totalProduct,
required String qty,
required String jumlahOrder,
required String pendapatan,
required bool isEven,
}) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: isEven ? PdfColors.grey50 : PdfColors.white,
),
children: [
_buildDataCell(name, alignment: pw.Alignment.centerLeft),
_buildDataCell(totalProduct),
_buildDataCell(qty),
_buildDataCell(jumlahOrder),
_buildDataCell(pendapatan),
],
);
}
static pw.TableRow _buildItemDataRow({
required String product,
required String category,
required String qty,
required String order,
required String pendapatan,
required String average,
required bool isEven,
}) {
return pw.TableRow(
decoration: pw.BoxDecoration(
color: isEven ? PdfColors.grey50 : PdfColors.white,
),
children: [
_buildDataCell(product, alignment: pw.Alignment.centerLeft),
_buildDataCell(category, alignment: pw.Alignment.centerLeft),
_buildDataCell(qty),
_buildDataCell(order),
_buildDataCell(pendapatan),
_buildDataCell(average),
],
);
}
}
+296 -29
View File
@@ -534,7 +534,7 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', text: '${DateFormat('yyyyMMddhhmm').format(DateTime.now())}',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
@@ -751,6 +751,7 @@ class PrintDataoutputs {
int paper, int paper,
String orderType, String orderType,
Outlet outlet, Outlet outlet,
List<ProductQuantity> products,
) async { ) async {
List<int> bytes = []; List<int> bytes = [];
@@ -798,7 +799,7 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', text: DateFormat('yyyyMMddhhmm').format(DateTime.now()),
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
@@ -840,18 +841,20 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
]); ]);
bytes += generator.row([ if (paymentMethod != '') {
PosColumn( bytes += generator.row([
text: 'Pembayaran', PosColumn(
width: 8, text: 'Payment',
styles: const PosStyles(align: PosAlign.left), width: 8,
), styles: const PosStyles(align: PosAlign.left),
PosColumn( ),
text: paymentMethod, PosColumn(
width: 4, text: paymentMethod,
styles: const PosStyles(align: PosAlign.right), width: 4,
), styles: const PosStyles(align: PosAlign.right),
]); ),
]);
}
bytes += generator.text( bytes += generator.text(
paper == 80 paper == 80
@@ -865,15 +868,16 @@ class PrintDataoutputs {
? '------------------------------------------------' ? '------------------------------------------------'
: '--------------------------------', : '--------------------------------',
styles: const PosStyles(bold: false, align: PosAlign.center)); styles: const PosStyles(bold: false, align: PosAlign.center));
for (final product in (order.orderItems ?? <OrderItem>[])) { for (final product in (products)) {
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
text: '${product.quantity} x ${product.productName}', text: '${product.quantity} x ${product.product.name}',
width: 8, width: 8,
styles: const PosStyles(bold: true, align: PosAlign.left), styles: const PosStyles(bold: true, align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: (product.totalPrice ?? 0).currencyFormatRpV2, text: (((product.product.price ?? 0) * product.quantity))
.currencyFormatRpV2,
width: 4, width: 4,
styles: const PosStyles(bold: true, align: PosAlign.right), styles: const PosStyles(bold: true, align: PosAlign.right),
), ),
@@ -887,7 +891,7 @@ class PrintDataoutputs {
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
text: 'Subtotal ${order.orderItems?.length ?? "0"} Product', text: 'Subtotal ${products.length} Product',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
@@ -1000,6 +1004,239 @@ class PrintDataoutputs {
return bytes; return bytes;
} }
Future<List<int>> printVoidOrder(
Order order,
String chashierName,
int taxPercentage,
int paper,
int nominalDikembalikan,
Outlet outlet,
List<OrderItem> productItemVoid,
) async {
List<int> bytes = [];
final profile = await CapabilityProfile.load();
final generator =
Generator(paper == 58 ? PaperSize.mm58 : PaperSize.mm80, profile);
bytes += generator.reset();
bytes += generator.text(outlet.name ?? "",
styles: const PosStyles(
bold: true,
align: PosAlign.center,
height: PosTextSize.size1,
width: PosTextSize.size1,
));
bytes += generator.text(outlet.address ?? "",
styles: const PosStyles(bold: false, align: PosAlign.center));
bytes += generator.text(outlet.phoneNumber ?? "",
styles: const PosStyles(bold: false, align: PosAlign.center));
bytes += generator.text(
paper == 80
? '------------------------------------------------'
: '--------------------------------',
styles: const PosStyles(bold: false, align: PosAlign.center));
bytes += generator.row([
PosColumn(
text: DateFormat('dd MMM yyyy').format(DateTime.now()),
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: DateFormat('HH:mm').format(DateTime.now()),
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Receipt Number',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: '${DateFormat('yyyyMMddhhmm').format(DateTime.now())}',
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Order ID',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: Random().nextInt(100000).toString(),
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Bill Name',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: order.metadata?['customer_name'] ?? '',
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Collected By',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: chashierName,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Status',
width: 8,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: 'Dibatalkan',
width: 4,
styles: const PosStyles(align: PosAlign.right),
),
]);
for (final product in (productItemVoid)) {
bytes += generator.row([
PosColumn(
text: '${product.quantity} x ${product.productName}',
width: 8,
styles: const PosStyles(bold: true, align: PosAlign.left),
),
PosColumn(
text: ((product.totalPrice ?? 0)).currencyFormatRpV2,
width: 4,
styles: const PosStyles(bold: true, align: PosAlign.right),
),
]);
}
bytes += generator.text(
paper == 80
? '------------------------------------------------'
: '--------------------------------',
styles: const PosStyles(bold: false, align: PosAlign.center));
bytes += generator.row([
PosColumn(
text: 'Subtotal ${productItemVoid.length} Product',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: (order.subtotal ?? 0).currencyFormatRpV2,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Discount',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: (order.discountAmount ?? 0).currencyFormatRpV2,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
// Only show tax if it's greater than 0
if ((order.taxAmount ?? 0) > 0) {
bytes += generator.row([
PosColumn(
text: 'Tax PB1 ($taxPercentage%)',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: (order.taxAmount ?? 0).currencyFormatRpV2,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
}
// Only show service charge if it's greater than 0
// if (serviceCharge > 0) {
// bytes += generator.row([
// PosColumn(
// text: 'Service Charge($serviceChargePercentage%)',
// width: 6,
// styles: const PosStyles(align: PosAlign.left),
// ),
// PosColumn(
// text: serviceCharge.currencyFormatRpV2,
// width: 6,
// styles: const PosStyles(align: PosAlign.right),
// ),
// ]);
// }
bytes += generator.text(
paper == 80
? '------------------------------------------------'
: '--------------------------------',
styles: const PosStyles(bold: false, align: PosAlign.center));
bytes += generator.row([
PosColumn(
text: 'Total',
width: 6,
styles: const PosStyles(bold: true, align: PosAlign.left),
),
PosColumn(
text: '${order.totalAmount ?? ""}'.currencyFormatRpV2,
width: 6,
styles: const PosStyles(bold: true, align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: 'Dikembalikan',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: nominalDikembalikan.currencyFormatRpV2,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.text(
paper == 80
? '------------------------------------------------'
: '--------------------------------',
styles: const PosStyles(bold: false, align: PosAlign.center));
// bytes += generator.text('Notes',
// styles: const PosStyles(bold: false, align: PosAlign.center));
// bytes += generator.text('Pass Wifi: fic14jilid2',
// styles: const PosStyles(bold: false, align: PosAlign.center));
// //terima kasih
// bytes += generator.text('Terima Kasih',
// styles: const PosStyles(bold: true, align: PosAlign.center));
paper == 80 ? bytes += generator.feed(3) : bytes += generator.feed(1);
bytes += generator.cut();
return bytes;
}
Future<List<int>> printQRIS( Future<List<int>> printQRIS(
int totalPrice, Uint8List imageQris, int paper) async { int totalPrice, Uint8List imageQris, int paper) async {
List<int> bytes = []; List<int> bytes = [];
@@ -1040,6 +1277,7 @@ class PrintDataoutputs {
String tableName, String tableName,
String draftName, String draftName,
String cashierName, String cashierName,
String customerName,
int paper, int paper,
String orderType) async { String orderType) async {
List<int> bytes = []; List<int> bytes = [];
@@ -1090,14 +1328,11 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', text: '${DateFormat('yyyyMMddhhmm').format(DateTime.now())}',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
]); ]);
// bytes += generator.text(
// 'Receipt: JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}',
// styles: const PosStyles(bold: false, align: PosAlign.left));
//cashier name //cashier name
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
@@ -1117,7 +1352,7 @@ class PrintDataoutputs {
//column 2 //column 2
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
text: 'Customer - $draftName', text: '$customerName - $draftName',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
@@ -1175,6 +1410,7 @@ class PrintDataoutputs {
String tableNumber, String tableNumber,
String draftName, String draftName,
String cashierName, String cashierName,
String customerName,
int paper, int paper,
String orderType) async { String orderType) async {
List<int> bytes = []; List<int> bytes = [];
@@ -1227,14 +1463,26 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', text: DateFormat('yyyyMMddhhmm').format(DateTime.now()),
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
]); ]);
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
text: 'Customer - $draftName', text: 'Cashier',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: cashierName,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: '$customerName - $draftName',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
@@ -1289,8 +1537,15 @@ class PrintDataoutputs {
return bytes; return bytes;
} }
Future<List<int>> printBar(List<ProductQuantity> products, String tableNumber, Future<List<int>> printBar(
String draftName, String cashierName, int paper, String orderType) async { List<ProductQuantity> products,
String tableNumber,
String draftName,
String cashierName,
String customerName,
int paper,
String orderType,
) async {
List<int> bytes = []; List<int> bytes = [];
final profile = await CapabilityProfile.load(); final profile = await CapabilityProfile.load();
@@ -1341,14 +1596,26 @@ class PrintDataoutputs {
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
PosColumn( PosColumn(
text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', text: DateFormat('yyyyMMddhhmm').format(DateTime.now()),
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.right), styles: const PosStyles(align: PosAlign.right),
), ),
]); ]);
bytes += generator.row([ bytes += generator.row([
PosColumn( PosColumn(
text: 'Customer - $draftName', text: 'Cashier',
width: 6,
styles: const PosStyles(align: PosAlign.left),
),
PosColumn(
text: cashierName,
width: 6,
styles: const PosStyles(align: PosAlign.right),
),
]);
bytes += generator.row([
PosColumn(
text: '$customerName - $draftName',
width: 6, width: 6,
styles: const PosStyles(align: PosAlign.left), styles: const PosStyles(align: PosAlign.left),
), ),
@@ -5,7 +5,9 @@ import 'package:dio/dio.dart';
import 'package:enaklo_pos/core/constants/variables.dart'; import 'package:enaklo_pos/core/constants/variables.dart';
import 'package:enaklo_pos/core/network/dio_client.dart'; import 'package:enaklo_pos/core/network/dio_client.dart';
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart'; import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/category_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/dashboard_analytic_response_model.dart'; import 'package:enaklo_pos/data/models/response/dashboard_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/inventory_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_method_analytic_response_model.dart'; import 'package:enaklo_pos/data/models/response/payment_method_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/product_analytic_response_model.dart'; import 'package:enaklo_pos/data/models/response/product_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/profit_loss_response_model.dart'; import 'package:enaklo_pos/data/models/response/profit_loss_response_model.dart';
@@ -184,4 +186,72 @@ class AnalyticRemoteDatasource {
return left('Unexpected error occurred'); return left('Unexpected error occurred');
} }
} }
Future<Either<String, CategoryAnalyticResponseModel>> getCategory({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final headers = {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
};
try {
final response = await dio.get(
'${Variables.baseUrl}/api/v1/analytics/categories',
queryParameters: {
'date_from': DateFormat('dd-MM-yyyy').format(dateFrom),
'date_to': DateFormat('dd-MM-yyyy').format(dateTo),
},
options: Options(headers: headers),
);
if (response.statusCode == 200) {
return right(CategoryAnalyticResponseModel.fromMap(response.data));
} else {
return left('Terjadi Kesalahan, Coba lagi nanti.');
}
} on DioException catch (e) {
log('Dio error: ${e.message}');
return left(e.response?.data.toString() ?? e.message ?? 'Unknown error');
} catch (e) {
log('Unexpected error: $e');
return left('Unexpected error occurred');
}
}
Future<Either<String, InventoryAnalyticResponseModel>> getInventory({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final headers = {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
};
try {
final response = await dio.get(
'${Variables.baseUrl}/api/v1/inventory/report/details/${authData.user?.outletId}',
queryParameters: {
'date_from': DateFormat('dd-MM-yyyy').format(dateFrom),
'date_to': DateFormat('dd-MM-yyyy').format(dateTo),
},
options: Options(headers: headers),
);
if (response.statusCode == 200) {
return right(InventoryAnalyticResponseModel.fromMap(response.data));
} else {
return left('Terjadi Kesalahan, Coba lagi nanti.');
}
} on DioException catch (e) {
log('Dio error: ${e.message}');
return left(e.response?.data.toString() ?? e.message ?? 'Unknown error');
} catch (e) {
log('Unexpected error: $e');
return left('Unexpected error occurred');
}
}
} }
@@ -56,7 +56,7 @@ class ProductRemoteDatasource {
log("Dio error: ${e.message}"); log("Dio error: ${e.message}");
return Left(e.response?.data['message'] ?? 'Gagal mengambil produk'); return Left(e.response?.data['message'] ?? 'Gagal mengambil produk');
} catch (e) { } catch (e) {
log("Unexpected error: $e"); log("Unexpected error: $e", name: "productRemoteDatasource");
return const Left('Unexpected error occurred'); return const Left('Unexpected error occurred');
} }
} }
@@ -19,7 +19,7 @@ class SettingsLocalDatasource {
return TaxModel( return TaxModel(
name: 'Tax', name: 'Tax',
type: TaxType.pajak, type: TaxType.pajak,
value: 11, value: 0,
); );
} }
} }
@@ -0,0 +1,129 @@
class CategoryAnalyticResponseModel {
final bool success;
final CategoryAnalyticData? data;
final dynamic errors;
CategoryAnalyticResponseModel({
required this.success,
required this.data,
this.errors,
});
// Dari JSON String ke Model
factory CategoryAnalyticResponseModel.fromJson(Map<String, dynamic> json) {
return CategoryAnalyticResponseModel(
success: json['success'],
data: json['data'] == null
? null
: CategoryAnalyticData.fromMap(json['data']),
errors: json['errors'],
);
}
// Dari Model ke JSON String
Map<String, dynamic> toJson() {
return {
'success': success,
'data': data?.toMap(),
'errors': errors,
};
}
// Dari Map ke Model
factory CategoryAnalyticResponseModel.fromMap(Map<String, dynamic> map) {
return CategoryAnalyticResponseModel(
success: map['success'],
data: CategoryAnalyticData.fromMap(map['data']),
errors: map['errors'],
);
}
// Dari Model ke Map
Map<String, dynamic> toMap() {
return {
'success': success,
'data': data?.toMap(),
'errors': errors,
};
}
}
class CategoryAnalyticData {
final String organizationId;
final String outletId;
final DateTime dateFrom;
final DateTime dateTo;
final List<CategoryAnalyticItem> data;
CategoryAnalyticData({
required this.organizationId,
required this.outletId,
required this.dateFrom,
required this.dateTo,
required this.data,
});
factory CategoryAnalyticData.fromMap(Map<String, dynamic> map) {
return CategoryAnalyticData(
organizationId: map['organization_id'],
outletId: map['outlet_id'],
dateFrom: DateTime.parse(map['date_from']),
dateTo: DateTime.parse(map['date_to']),
data: map['data'] == null
? []
: List<CategoryAnalyticItem>.from(
map['data']?.map((x) => CategoryAnalyticItem.fromMap(x)) ?? [],
),
);
}
Map<String, dynamic> toMap() {
return {
'organization_id': organizationId,
'outlet_id': outletId,
'date_from': dateFrom.toIso8601String(),
'date_to': dateTo.toIso8601String(),
'data': data.map((x) => x.toMap()).toList(),
};
}
}
class CategoryAnalyticItem {
final String categoryId;
final String categoryName;
final int totalRevenue;
final int totalQuantity;
final int productCount;
final int orderCount;
CategoryAnalyticItem({
required this.categoryId,
required this.categoryName,
required this.totalRevenue,
required this.totalQuantity,
required this.productCount,
required this.orderCount,
});
factory CategoryAnalyticItem.fromMap(Map<String, dynamic> map) {
return CategoryAnalyticItem(
categoryId: map['category_id'],
categoryName: map['category_name'],
totalRevenue: map['total_revenue'] ?? 0,
totalQuantity: map['total_quantity'] ?? 0,
productCount: map['product_count'] ?? 0,
orderCount: map['order_count'] ?? 0,
);
}
Map<String, dynamic> toMap() {
return {
'category_id': categoryId,
'category_name': categoryName,
'total_revenue': totalRevenue,
'total_quantity': totalQuantity,
'product_count': productCount,
'order_count': orderCount,
};
}
}
@@ -0,0 +1,290 @@
class InventoryAnalyticResponseModel {
final bool success;
final InventoryAnalyticData? data;
final dynamic errors;
InventoryAnalyticResponseModel({
required this.success,
required this.data,
this.errors,
});
// From JSON
factory InventoryAnalyticResponseModel.fromJson(Map<String, dynamic> json) {
return InventoryAnalyticResponseModel(
success: json['success'],
data: json['data'] != null
? InventoryAnalyticData.fromMap(json['data'])
: null,
errors: json['errors'],
);
}
// To JSON
Map<String, dynamic> toJson() {
return {
'success': success,
'data': data?.toMap(),
'errors': errors,
};
}
// From Map
factory InventoryAnalyticResponseModel.fromMap(Map<String, dynamic> map) {
return InventoryAnalyticResponseModel(
success: map['success'],
data: map['data'] != null
? InventoryAnalyticData.fromMap(map['data'])
: null,
errors: map['errors'],
);
}
// To Map
Map<String, dynamic> toMap() {
return {
'success': success,
'data': data?.toMap(),
'errors': errors,
};
}
}
class InventoryAnalyticData {
final InventorySummary summary;
final List<InventoryProductItem> products;
final List<InventoryIngredientItem> ingredients;
InventoryAnalyticData({
required this.summary,
required this.products,
required this.ingredients,
});
factory InventoryAnalyticData.fromMap(Map<String, dynamic> map) {
return InventoryAnalyticData(
summary: InventorySummary.fromMap(map['summary']),
products: map['products'] == null
? []
: List<InventoryProductItem>.from(
map['products']?.map((x) => InventoryProductItem.fromMap(x)) ??
[],
),
ingredients: map['ingredients'] == null
? []
: List<InventoryIngredientItem>.from(
map['ingredients']
?.map((x) => InventoryIngredientItem.fromMap(x)) ??
[],
),
);
}
Map<String, dynamic> toMap() {
return {
'summary': summary.toMap(),
'products': products.map((x) => x.toMap()).toList(),
'ingredients': ingredients.map((x) => x.toMap()).toList(),
};
}
}
class InventorySummary {
final int totalProducts;
final int totalIngredients;
final int totalValue;
final int lowStockProducts;
final int lowStockIngredients;
final int zeroStockProducts;
final int zeroStockIngredients;
final int totalSoldProducts;
final int totalSoldIngredients;
final String outletId;
final String outletName;
final DateTime generatedAt;
InventorySummary({
required this.totalProducts,
required this.totalIngredients,
required this.totalValue,
required this.lowStockProducts,
required this.lowStockIngredients,
required this.zeroStockProducts,
required this.zeroStockIngredients,
required this.totalSoldProducts,
required this.totalSoldIngredients,
required this.outletId,
required this.outletName,
required this.generatedAt,
});
factory InventorySummary.fromMap(Map<String, dynamic> map) {
return InventorySummary(
totalProducts: map['total_products'] ?? 0,
totalIngredients: map['total_ingredients'] ?? 0,
totalValue: map['total_value'] ?? 0,
lowStockProducts: map['low_stock_products'] ?? 0,
lowStockIngredients: map['low_stock_ingredients'] ?? 0,
zeroStockProducts: map['zero_stock_products'] ?? 0,
zeroStockIngredients: map['zero_stock_ingredients'] ?? 0,
totalSoldProducts: map['total_sold_products'] ?? 0,
totalSoldIngredients: map['total_sold_ingredients'] ?? 0,
outletId: map['outlet_id'],
outletName: map['outlet_name'],
generatedAt: DateTime.parse(map['generated_at']),
);
}
Map<String, dynamic> toMap() {
return {
'total_products': totalProducts,
'total_ingredients': totalIngredients,
'total_value': totalValue,
'low_stock_products': lowStockProducts,
'low_stock_ingredients': lowStockIngredients,
'zero_stock_products': zeroStockProducts,
'zero_stock_ingredients': zeroStockIngredients,
'total_sold_products': totalSoldProducts,
'total_sold_ingredients': totalSoldIngredients,
'outlet_id': outletId,
'outlet_name': outletName,
'generated_at': generatedAt.toIso8601String(),
};
}
}
class InventoryProductItem {
final String id;
final String productId;
final String productName;
final String categoryName;
final int quantity;
final int reorderLevel;
final num unitCost;
final int totalValue;
final int totalIn;
final int totalOut;
final bool isLowStock;
final bool isZeroStock;
final DateTime updatedAt;
InventoryProductItem({
required this.id,
required this.productId,
required this.productName,
required this.categoryName,
required this.quantity,
required this.reorderLevel,
required this.unitCost,
required this.totalValue,
required this.totalIn,
required this.totalOut,
required this.isLowStock,
required this.isZeroStock,
required this.updatedAt,
});
factory InventoryProductItem.fromMap(Map<String, dynamic> map) {
return InventoryProductItem(
id: map['id'],
productId: map['product_id'],
productName: map['product_name'],
categoryName: map['category_name'],
quantity: map['quantity'] ?? 0,
reorderLevel: map['reorder_level'] ?? 0,
unitCost: map['unit_cost'] ?? 0,
totalValue: map['total_value'] ?? 0,
totalIn: map['total_in'] ?? 0,
totalOut: map['total_out'] ?? 0,
isLowStock: map['is_low_stock'] ?? false,
isZeroStock: map['is_zero_stock'] ?? false,
updatedAt: DateTime.parse(map['updated_at']),
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'product_id': productId,
'product_name': productName,
'category_name': categoryName,
'quantity': quantity,
'reorder_level': reorderLevel,
'unit_cost': unitCost,
'total_value': totalValue,
'total_in': totalIn,
'total_out': totalOut,
'is_low_stock': isLowStock,
'is_zero_stock': isZeroStock,
'updated_at': updatedAt.toIso8601String(),
};
}
}
class InventoryIngredientItem {
final String id;
final String ingredientId;
final String ingredientName;
final String unitName;
final int quantity;
final int reorderLevel;
final num unitCost;
final int totalValue;
final int totalIn;
final int totalOut;
final bool isLowStock;
final bool isZeroStock;
final DateTime updatedAt;
InventoryIngredientItem({
required this.id,
required this.ingredientId,
required this.ingredientName,
required this.unitName,
required this.quantity,
required this.reorderLevel,
required this.unitCost,
required this.totalValue,
required this.totalIn,
required this.totalOut,
required this.isLowStock,
required this.isZeroStock,
required this.updatedAt,
});
factory InventoryIngredientItem.fromMap(Map<String, dynamic> map) {
return InventoryIngredientItem(
id: map['id'],
ingredientId: map['ingredient_id'],
ingredientName: map['ingredient_name'],
unitName: map['unit_name'],
quantity: map['quantity'] ?? 0,
reorderLevel: map['reorder_level'] ?? 0,
unitCost: map['unit_cost'] ?? 0,
totalValue: map['total_value'] ?? 0,
totalIn: map['total_in'] ?? 0,
totalOut: map['total_out'] ?? 0,
isLowStock: map['is_low_stock'] ?? false,
isZeroStock: map['is_zero_stock'] ?? false,
updatedAt: DateTime.parse(map['updated_at']),
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'ingredient_id': ingredientId,
'ingredient_name': ingredientName,
'unit_name': unitName,
'quantity': quantity,
'reorder_level': reorderLevel,
'unit_cost': unitCost,
'total_value': totalValue,
'total_in': totalIn,
'total_out': totalOut,
'is_low_stock': isLowStock,
'is_zero_stock': isZeroStock,
'updated_at': updatedAt.toIso8601String(),
};
}
}
@@ -1,5 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
class OrderDetailResponseModel { class OrderDetailResponseModel {
final bool? success; final bool? success;
final Order? data; final Order? data;
@@ -115,7 +118,7 @@ class Order {
final int? taxAmount; final int? taxAmount;
final int? discountAmount; final int? discountAmount;
final int? totalAmount; final int? totalAmount;
final int? totalCost; final num? totalCost;
final int? remainingAmount; final int? remainingAmount;
final String? paymentStatus; final String? paymentStatus;
final int? refundAmount; final int? refundAmount;
@@ -380,3 +383,21 @@ class Payment {
}; };
} }
} }
extension OrderItemListExtension on List<OrderItem> {
List<ProductQuantity> toProductQuantities() => map((e) => ProductQuantity(
product: Product(
id: e.productId,
name: e.productName,
price: e.unitPrice,
printerType: e.printerType,
),
variant: ProductVariant(
id: e.productVariantId,
name: e.productVariantName,
productId: e.productId,
),
notes: e.notes ?? '',
quantity: e.quantity ?? 0,
)).toList();
}
@@ -1,6 +1,6 @@
class PaymentMethodAnalyticResponseModel { class PaymentMethodAnalyticResponseModel {
final bool success; final bool success;
final PaymentMethodAnalyticData data; final PaymentMethodAnalyticData? data;
final dynamic errors; final dynamic errors;
PaymentMethodAnalyticResponseModel({ PaymentMethodAnalyticResponseModel({
@@ -18,7 +18,9 @@ class PaymentMethodAnalyticResponseModel {
factory PaymentMethodAnalyticResponseModel.fromMap(Map<String, dynamic> map) { factory PaymentMethodAnalyticResponseModel.fromMap(Map<String, dynamic> map) {
return PaymentMethodAnalyticResponseModel( return PaymentMethodAnalyticResponseModel(
success: map['success'], success: map['success'],
data: PaymentMethodAnalyticData.fromMap(map['data']), data: map['data'] == null
? null
: PaymentMethodAnalyticData.fromMap(map['data']),
errors: map['errors'], errors: map['errors'],
); );
} }
@@ -26,7 +28,7 @@ class PaymentMethodAnalyticResponseModel {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'success': success, 'success': success,
'data': data.toMap(), 'data': data?.toMap(),
'errors': errors, 'errors': errors,
}; };
} }
@@ -130,7 +132,7 @@ class PaymentMethodAnalyticItem {
final int totalAmount; final int totalAmount;
final int orderCount; final int orderCount;
final int paymentCount; final int paymentCount;
final int percentage; final num percentage;
PaymentMethodAnalyticItem({ PaymentMethodAnalyticItem({
required this.paymentMethodId, required this.paymentMethodId,
@@ -1,6 +1,6 @@
class ProductAnalyticResponseModel { class ProductAnalyticResponseModel {
final bool success; final bool success;
final ProductAnalyticData data; final ProductAnalyticData? data;
final dynamic errors; final dynamic errors;
ProductAnalyticResponseModel({ ProductAnalyticResponseModel({
@@ -17,7 +17,8 @@ class ProductAnalyticResponseModel {
factory ProductAnalyticResponseModel.fromMap(Map<String, dynamic> map) { factory ProductAnalyticResponseModel.fromMap(Map<String, dynamic> map) {
return ProductAnalyticResponseModel( return ProductAnalyticResponseModel(
success: map['success'] ?? false, success: map['success'] ?? false,
data: ProductAnalyticData.fromMap(map['data']), data:
map['data'] == null ? null : ProductAnalyticData.fromMap(map['data']),
errors: map['errors'], errors: map['errors'],
); );
} }
@@ -25,7 +26,7 @@ class ProductAnalyticResponseModel {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'success': success, 'success': success,
'data': data.toMap(), 'data': data?.toMap(),
'errors': errors, 'errors': errors,
}; };
} }
@@ -1,6 +1,14 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first // ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert'; import 'dart:convert';
int? parseInt(dynamic value) {
if (value == null) return null;
if (value is int) return value;
if (value is double) return value.toInt();
if (value is String) return int.tryParse(value);
return null;
}
class ProductResponseModel { class ProductResponseModel {
final bool? success; final bool? success;
final ProductData? data; final ProductData? data;
@@ -51,10 +59,10 @@ class ProductData {
? [] ? []
: List<Product>.from( : List<Product>.from(
json["products"].map((x) => Product.fromMap(x))), json["products"].map((x) => Product.fromMap(x))),
totalCount: json["total_count"], totalCount: parseInt(json["total_count"]),
page: json["page"], page: parseInt(json["page"]),
limit: json["limit"], limit: parseInt(json["limit"]),
totalPages: json["total_pages"], totalPages: parseInt(json["total_pages"]),
); );
Map<String, dynamic> toMap() => { Map<String, dynamic> toMap() => {
@@ -116,8 +124,8 @@ class Product {
sku: json["sku"], sku: json["sku"],
name: json["name"], name: json["name"],
description: json["description"], description: json["description"],
price: json["price"], price: parseInt(json["price"]),
cost: json["cost"], cost: parseInt(json["cost"]),
businessType: json["business_type"], businessType: json["business_type"],
imageUrl: json["image_url"], imageUrl: json["image_url"],
printerType: json["printer_type"], printerType: json["printer_type"],
@@ -137,7 +145,7 @@ class Product {
factory Product.fromOrderMap(Map<String, dynamic> json) => Product( factory Product.fromOrderMap(Map<String, dynamic> json) => Product(
id: json["id_product"], id: json["id_product"],
price: json["price"], price: parseInt(json["price"]),
); );
factory Product.fromLocalMap(Map<String, dynamic> json) => Product( factory Product.fromLocalMap(Map<String, dynamic> json) => Product(
@@ -147,8 +155,8 @@ class Product {
sku: json["sku"], sku: json["sku"],
name: json["name"], name: json["name"],
description: json["description"], description: json["description"],
price: json["price"], price: parseInt(json["price"]),
cost: json["cost"], cost: parseInt(json["cost"]),
businessType: json["business_type"], businessType: json["business_type"],
imageUrl: json["image_url"], imageUrl: json["image_url"],
printerType: json["printer_type"], printerType: json["printer_type"],
@@ -207,96 +215,6 @@ class Product {
? [] ? []
: List<dynamic>.from(variants!.map((x) => x.toMap())), : List<dynamic>.from(variants!.map((x) => x.toMap())),
}; };
@override
bool operator ==(covariant Product other) {
if (identical(this, other)) return true;
return other.id == id &&
other.organizationId == organizationId &&
other.categoryId == categoryId &&
other.sku == sku &&
other.name == name &&
other.description == description &&
other.price == price &&
other.cost == cost &&
other.businessType == businessType &&
other.imageUrl == imageUrl &&
other.printerType == printerType &&
other.metadata == metadata &&
other.isActive == isActive &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
_listEquals(other.variants, variants);
}
bool _listEquals(List<ProductVariant>? a, List<ProductVariant>? b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
@override
int get hashCode {
return id.hashCode ^
organizationId.hashCode ^
categoryId.hashCode ^
sku.hashCode ^
name.hashCode ^
description.hashCode ^
price.hashCode ^
cost.hashCode ^
businessType.hashCode ^
imageUrl.hashCode ^
printerType.hashCode ^
metadata.hashCode ^
isActive.hashCode ^
createdAt.hashCode ^
updatedAt.hashCode ^
variants.hashCode;
}
Product copyWith({
String? id,
String? organizationId,
String? categoryId,
String? sku,
String? name,
String? description,
int? price,
int? cost,
String? businessType,
String? imageUrl,
String? printerType,
Map<String, dynamic>? metadata,
bool? isActive,
DateTime? createdAt,
DateTime? updatedAt,
List<ProductVariant>? variants,
}) {
return Product(
id: id ?? this.id,
organizationId: organizationId ?? this.organizationId,
categoryId: categoryId ?? this.categoryId,
sku: sku ?? this.sku,
name: name ?? this.name,
description: description ?? this.description,
price: price ?? this.price,
cost: cost ?? this.cost,
businessType: businessType ?? this.businessType,
imageUrl: imageUrl ?? this.imageUrl,
printerType: printerType ?? this.printerType,
metadata: metadata ?? this.metadata,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
variants: variants ?? this.variants,
);
}
} }
class Category { class Category {
@@ -341,28 +259,6 @@ class Category {
"created_at": createdAt?.toIso8601String(), "created_at": createdAt?.toIso8601String(),
"updated_at": updatedAt?.toIso8601String(), "updated_at": updatedAt?.toIso8601String(),
}; };
@override
bool operator ==(covariant Category other) {
if (identical(this, other)) return true;
return other.id == id &&
other.name == name &&
other.description == description &&
other.image == image &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt;
}
@override
int get hashCode {
return id.hashCode ^
name.hashCode ^
description.hashCode ^
image.hashCode ^
createdAt.hashCode ^
updatedAt.hashCode;
}
} }
class ProductVariant { class ProductVariant {
@@ -390,8 +286,8 @@ class ProductVariant {
id: json["id"], id: json["id"],
productId: json["product_id"], productId: json["product_id"],
name: json["name"], name: json["name"],
priceModifier: json["price_modifier"], priceModifier: parseInt(json["price_modifier"]),
cost: json["cost"], cost: parseInt(json["cost"]),
metadata: json["metadata"] ?? {}, metadata: json["metadata"] ?? {},
createdAt: json["created_at"] == null createdAt: json["created_at"] == null
? null ? null
@@ -1,6 +1,6 @@
class ProfitLossResponseModel { class ProfitLossResponseModel {
final bool success; final bool success;
final ProfitLossData data; final ProfitLossData? data;
final dynamic errors; final dynamic errors;
ProfitLossResponseModel({ ProfitLossResponseModel({
@@ -13,7 +13,7 @@ class ProfitLossResponseModel {
factory ProfitLossResponseModel.fromJson(Map<String, dynamic> json) { factory ProfitLossResponseModel.fromJson(Map<String, dynamic> json) {
return ProfitLossResponseModel( return ProfitLossResponseModel(
success: json['success'], success: json['success'],
data: ProfitLossData.fromMap(json['data']), data: json['data'] == null ? null : ProfitLossData.fromMap(json['data']),
errors: json['errors'], errors: json['errors'],
); );
} }
@@ -22,7 +22,7 @@ class ProfitLossResponseModel {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'success': success, 'success': success,
'data': data.toMap(), 'data': data?.toMap(),
'errors': errors, 'errors': errors,
}; };
} }
@@ -40,7 +40,7 @@ class ProfitLossResponseModel {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'success': success, 'success': success,
'data': data.toMap(), 'data': data?.toMap(),
'errors': errors, 'errors': errors,
}; };
} }
@@ -98,15 +98,15 @@ class ProfitLossData {
class ProfitLossSummary { class ProfitLossSummary {
final int totalRevenue; final int totalRevenue;
final int totalCost; final num totalCost;
final int grossProfit; final num grossProfit;
final double grossProfitMargin; final double grossProfitMargin;
final int totalTax; final int totalTax;
final int totalDiscount; final int totalDiscount;
final int netProfit; final num netProfit;
final double netProfitMargin; final double netProfitMargin;
final int totalOrders; final int totalOrders;
final int averageProfit; final double averageProfit;
final double profitabilityRatio; final double profitabilityRatio;
ProfitLossSummary({ ProfitLossSummary({
@@ -134,7 +134,7 @@ class ProfitLossSummary {
netProfit: map['net_profit'], netProfit: map['net_profit'],
netProfitMargin: (map['net_profit_margin'] as num).toDouble(), netProfitMargin: (map['net_profit_margin'] as num).toDouble(),
totalOrders: map['total_orders'], totalOrders: map['total_orders'],
averageProfit: map['average_profit'], averageProfit: (map['average_profit'] as num).toDouble(),
profitabilityRatio: (map['profitability_ratio'] as num).toDouble(), profitabilityRatio: (map['profitability_ratio'] as num).toDouble(),
); );
} }
@@ -159,12 +159,12 @@ class ProfitLossSummary {
class ProfitLossItem { class ProfitLossItem {
final String date; final String date;
final int revenue; final int revenue;
final int cost; final num cost;
final int grossProfit; final num grossProfit;
final double grossProfitMargin; final double grossProfitMargin;
final int tax; final int tax;
final int discount; final int discount;
final int netProfit; final num netProfit;
final double netProfitMargin; final double netProfitMargin;
final int orders; final int orders;
@@ -219,12 +219,12 @@ class ProfitLossProduct {
final String categoryName; final String categoryName;
final int quantitySold; final int quantitySold;
final int revenue; final int revenue;
final int cost; final num cost;
final int grossProfit; final num grossProfit;
final double grossProfitMargin; final double grossProfitMargin;
final int averagePrice; final int averagePrice;
final int averageCost; final num averageCost;
final int profitPerUnit; final num profitPerUnit;
ProfitLossProduct({ ProfitLossProduct({
required this.productId, required this.productId,
@@ -252,8 +252,8 @@ class ProfitLossProduct {
cost: map['cost'], cost: map['cost'],
grossProfit: map['gross_profit'], grossProfit: map['gross_profit'],
grossProfitMargin: (map['gross_profit_margin'] as num).toDouble(), grossProfitMargin: (map['gross_profit_margin'] as num).toDouble(),
averagePrice: map['average_price'], averagePrice: (map['average_price'] as num).toInt(),
averageCost: map['average_cost'], averageCost: (map['average_cost'] as num).toInt(),
profitPerUnit: map['profit_per_unit'], profitPerUnit: map['profit_per_unit'],
); );
} }
+38 -12
View File
@@ -1,4 +1,6 @@
import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'dart:ui';
import 'package:enaklo_pos/core/constants/theme.dart'; import 'package:enaklo_pos/core/constants/theme.dart';
import 'package:enaklo_pos/core/network/dio_client.dart'; import 'package:enaklo_pos/core/network/dio_client.dart';
import 'package:enaklo_pos/data/datasources/analytic_remote_datasource.dart'; import 'package:enaklo_pos/data/datasources/analytic_remote_datasource.dart';
@@ -16,13 +18,18 @@ import 'package:enaklo_pos/presentation/home/bloc/outlet_loader/outlet_loader_bl
import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/user_update_outlet/user_update_outlet_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/user_update_outlet/user_update_outlet_bloc.dart';
import 'package:enaklo_pos/presentation/refund/bloc/refund_bloc.dart'; import 'package:enaklo_pos/presentation/refund/bloc/refund_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/category_report/category_report_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/inventory_report/inventory_report_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/profit_loss/profit_loss_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/profit_loss/profit_loss_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/report/report_bloc.dart';
import 'package:enaklo_pos/presentation/sales/blocs/order_loader/order_loader_bloc.dart'; import 'package:enaklo_pos/presentation/sales/blocs/order_loader/order_loader_bloc.dart';
import 'package:enaklo_pos/presentation/sales/blocs/payment_form/payment_form_bloc.dart'; import 'package:enaklo_pos/presentation/sales/blocs/payment_form/payment_form_bloc.dart';
import 'package:enaklo_pos/presentation/setting/bloc/get_printer_ticket/get_printer_ticket_bloc.dart'; import 'package:enaklo_pos/presentation/setting/bloc/get_printer_ticket/get_printer_ticket_bloc.dart';
import 'package:enaklo_pos/presentation/setting/bloc/upload_file/upload_file_bloc.dart'; import 'package:enaklo_pos/presentation/setting/bloc/upload_file/upload_file_bloc.dart';
import 'package:enaklo_pos/presentation/table/blocs/transfer_table/transfer_table_bloc.dart'; import 'package:enaklo_pos/presentation/table/blocs/transfer_table/transfer_table_bloc.dart';
import 'package:enaklo_pos/presentation/void/bloc/void_order_bloc.dart'; import 'package:enaklo_pos/presentation/void/bloc/void_order_bloc.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart'; import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
import 'package:enaklo_pos/data/datasources/auth_remote_datasource.dart'; import 'package:enaklo_pos/data/datasources/auth_remote_datasource.dart';
@@ -71,8 +78,6 @@ import 'package:enaklo_pos/presentation/setting/bloc/sync_product/sync_product_b
import 'package:enaklo_pos/presentation/setting/bloc/tax_settings/tax_settings_bloc.dart'; import 'package:enaklo_pos/presentation/setting/bloc/tax_settings/tax_settings_bloc.dart';
import 'package:enaklo_pos/presentation/table/blocs/update_table/update_table_bloc.dart'; import 'package:enaklo_pos/presentation/table/blocs/update_table/update_table_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/add_order_items/add_order_items_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/add_order_items/add_order_items_bloc.dart';
import 'package:flutter/services.dart';
import 'presentation/auth/bloc/login/login_bloc.dart'; import 'presentation/auth/bloc/login/login_bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@@ -80,16 +85,28 @@ import 'presentation/home/pages/dashboard_page.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); runZonedGuarded(() async {
await SystemChrome.setPreferredOrientations([ WidgetsFlutterBinding.ensureInitialized();
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight, await Firebase.initializeApp();
]); await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
// await LamanPrint.init();
// final dir = await getApplicationDocumentsDirectory(); // âś… Tambah custom logs
// Hive.init(dir.path); FlutterError.onError = (errorDetails) {
// Hive.registerAdapter(TableDataAdapter()); FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
runApp(ProviderScope(child: MyApp())); };
// âś… Catch platform errors juga
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
runApp(ProviderScope(child: MyApp()));
}, (error, stack) {
// âś… Ini udah bener
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
});
} }
class MyApp extends StatefulWidget { class MyApp extends StatefulWidget {
@@ -288,6 +305,15 @@ class _MyAppState extends State<MyApp> {
BlocProvider( BlocProvider(
create: (context) => TransferTableBloc(TableRemoteDataSource()), create: (context) => TransferTableBloc(TableRemoteDataSource()),
), ),
BlocProvider(
create: (context) => ReportBloc(AnalyticRemoteDatasource()),
),
BlocProvider(
create: (context) => InventoryReportBloc(AnalyticRemoteDatasource()),
),
BlocProvider(
create: (context) => CategoryReportBloc(AnalyticRemoteDatasource()),
),
], ],
child: MaterialApp( child: MaterialApp(
navigatorKey: AuthInterceptor.navigatorKey, navigatorKey: AuthInterceptor.navigatorKey,
@@ -131,7 +131,7 @@ class CheckoutBloc extends Bloc<CheckoutEvent, CheckoutState> {
final serviceCharge = await settingsLocalDatasource.getServiceCharge(); final serviceCharge = await settingsLocalDatasource.getServiceCharge();
emit(_Loaded( emit(_Loaded(
[], event.items,
null, null,
0, 0,
0, 0,
@@ -18,7 +18,7 @@ final _privateConstructorUsedError = UnsupportedError(
mixin _$CheckoutEvent { mixin _$CheckoutEvent {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -41,7 +41,7 @@ mixin _$CheckoutEvent {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -61,7 +61,7 @@ mixin _$CheckoutEvent {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -166,6 +166,8 @@ abstract class _$$StartedImplCopyWith<$Res> {
factory _$$StartedImplCopyWith( factory _$$StartedImplCopyWith(
_$StartedImpl value, $Res Function(_$StartedImpl) then) = _$StartedImpl value, $Res Function(_$StartedImpl) then) =
__$$StartedImplCopyWithImpl<$Res>; __$$StartedImplCopyWithImpl<$Res>;
@useResult
$Res call({List<ProductQuantity> items});
} }
/// @nodoc /// @nodoc
@@ -178,31 +180,62 @@ class __$$StartedImplCopyWithImpl<$Res>
/// Create a copy of CheckoutEvent /// Create a copy of CheckoutEvent
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? items = null,
}) {
return _then(_$StartedImpl(
null == items
? _value._items
: items // ignore: cast_nullable_to_non_nullable
as List<ProductQuantity>,
));
}
} }
/// @nodoc /// @nodoc
class _$StartedImpl implements _Started { class _$StartedImpl implements _Started {
const _$StartedImpl(); const _$StartedImpl(final List<ProductQuantity> items) : _items = items;
final List<ProductQuantity> _items;
@override
List<ProductQuantity> get items {
if (_items is EqualUnmodifiableListView) return _items;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_items);
}
@override @override
String toString() { String toString() {
return 'CheckoutEvent.started()'; return 'CheckoutEvent.started(items: $items)';
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$StartedImpl); (other.runtimeType == runtimeType &&
other is _$StartedImpl &&
const DeepCollectionEquality().equals(other._items, _items));
} }
@override @override
int get hashCode => runtimeType.hashCode; int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(_items));
/// Create a copy of CheckoutEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$StartedImplCopyWith<_$StartedImpl> get copyWith =>
__$$StartedImplCopyWithImpl<_$StartedImpl>(this, _$identity);
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -222,13 +255,13 @@ class _$StartedImpl implements _Started {
required TResult Function(DraftOrderModel data) loadDraftOrder, required TResult Function(DraftOrderModel data) loadDraftOrder,
required TResult Function(DeliveryModel delivery) updateDeliveryType, required TResult Function(DeliveryModel delivery) updateDeliveryType,
}) { }) {
return started(); return started(items);
} }
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -245,13 +278,13 @@ class _$StartedImpl implements _Started {
TResult? Function(DraftOrderModel data)? loadDraftOrder, TResult? Function(DraftOrderModel data)? loadDraftOrder,
TResult? Function(DeliveryModel delivery)? updateDeliveryType, TResult? Function(DeliveryModel delivery)? updateDeliveryType,
}) { }) {
return started?.call(); return started?.call(items);
} }
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -270,7 +303,7 @@ class _$StartedImpl implements _Started {
required TResult orElse(), required TResult orElse(),
}) { }) {
if (started != null) { if (started != null) {
return started(); return started(items);
} }
return orElse(); return orElse();
} }
@@ -347,7 +380,15 @@ class _$StartedImpl implements _Started {
} }
abstract class _Started implements CheckoutEvent { abstract class _Started implements CheckoutEvent {
const factory _Started() = _$StartedImpl; const factory _Started(final List<ProductQuantity> items) = _$StartedImpl;
List<ProductQuantity> get items;
/// Create a copy of CheckoutEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$StartedImplCopyWith<_$StartedImpl> get copyWith =>
throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
@@ -426,7 +467,7 @@ class _$AddItemImpl implements _AddItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -452,7 +493,7 @@ class _$AddItemImpl implements _AddItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -475,7 +516,7 @@ class _$AddItemImpl implements _AddItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -660,7 +701,7 @@ class _$RemoveItemImpl implements _RemoveItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -686,7 +727,7 @@ class _$RemoveItemImpl implements _RemoveItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -709,7 +750,7 @@ class _$RemoveItemImpl implements _RemoveItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -894,7 +935,7 @@ class _$DeleteItemImpl implements _DeleteItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -920,7 +961,7 @@ class _$DeleteItemImpl implements _DeleteItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -943,7 +984,7 @@ class _$DeleteItemImpl implements _DeleteItem {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1121,7 +1162,7 @@ class _$AddDiscountImpl implements _AddDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -1147,7 +1188,7 @@ class _$AddDiscountImpl implements _AddDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1170,7 +1211,7 @@ class _$AddDiscountImpl implements _AddDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1318,7 +1359,7 @@ class _$RemoveDiscountImpl implements _RemoveDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -1344,7 +1385,7 @@ class _$RemoveDiscountImpl implements _RemoveDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1367,7 +1408,7 @@ class _$RemoveDiscountImpl implements _RemoveDiscount {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1534,7 +1575,7 @@ class _$AddTaxImpl implements _AddTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -1560,7 +1601,7 @@ class _$AddTaxImpl implements _AddTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1583,7 +1624,7 @@ class _$AddTaxImpl implements _AddTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1760,7 +1801,7 @@ class _$AddServiceChargeImpl implements _AddServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -1786,7 +1827,7 @@ class _$AddServiceChargeImpl implements _AddServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1809,7 +1850,7 @@ class _$AddServiceChargeImpl implements _AddServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -1958,7 +1999,7 @@ class _$RemoveTaxImpl implements _RemoveTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -1984,7 +2025,7 @@ class _$RemoveTaxImpl implements _RemoveTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2007,7 +2048,7 @@ class _$RemoveTaxImpl implements _RemoveTax {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2148,7 +2189,7 @@ class _$RemoveServiceChargeImpl implements _RemoveServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -2174,7 +2215,7 @@ class _$RemoveServiceChargeImpl implements _RemoveServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2197,7 +2238,7 @@ class _$RemoveServiceChargeImpl implements _RemoveServiceCharge {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2366,7 +2407,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -2392,7 +2433,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2415,7 +2456,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2600,7 +2641,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -2626,7 +2667,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2649,7 +2690,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2848,7 +2889,7 @@ class _$SaveDraftOrderImpl implements _SaveDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -2874,7 +2915,7 @@ class _$SaveDraftOrderImpl implements _SaveDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2897,7 +2938,7 @@ class _$SaveDraftOrderImpl implements _SaveDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -3076,7 +3117,7 @@ class _$LoadDraftOrderImpl implements _LoadDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -3102,7 +3143,7 @@ class _$LoadDraftOrderImpl implements _LoadDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -3125,7 +3166,7 @@ class _$LoadDraftOrderImpl implements _LoadDraftOrder {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -3303,7 +3344,7 @@ class _$UpdateDeliveryTypeImpl implements _UpdateDeliveryType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() started, required TResult Function(List<ProductQuantity> items) started,
required TResult Function(Product product, ProductVariant? variant) addItem, required TResult Function(Product product, ProductVariant? variant) addItem,
required TResult Function(Product product, ProductVariant? variant) required TResult Function(Product product, ProductVariant? variant)
removeItem, removeItem,
@@ -3329,7 +3370,7 @@ class _$UpdateDeliveryTypeImpl implements _UpdateDeliveryType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? started, TResult? Function(List<ProductQuantity> items)? started,
TResult? Function(Product product, ProductVariant? variant)? addItem, TResult? Function(Product product, ProductVariant? variant)? addItem,
TResult? Function(Product product, ProductVariant? variant)? removeItem, TResult? Function(Product product, ProductVariant? variant)? removeItem,
TResult? Function(Product product, ProductVariant? variant)? deleteItem, TResult? Function(Product product, ProductVariant? variant)? deleteItem,
@@ -3352,7 +3393,7 @@ class _$UpdateDeliveryTypeImpl implements _UpdateDeliveryType {
@override @override
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? started, TResult Function(List<ProductQuantity> items)? started,
TResult Function(Product product, ProductVariant? variant)? addItem, TResult Function(Product product, ProductVariant? variant)? addItem,
TResult Function(Product product, ProductVariant? variant)? removeItem, TResult Function(Product product, ProductVariant? variant)? removeItem,
TResult Function(Product product, ProductVariant? variant)? deleteItem, TResult Function(Product product, ProductVariant? variant)? deleteItem,
@@ -2,7 +2,7 @@ part of 'checkout_bloc.dart';
@freezed @freezed
class CheckoutEvent with _$CheckoutEvent { class CheckoutEvent with _$CheckoutEvent {
const factory CheckoutEvent.started() = _Started; const factory CheckoutEvent.started(List<ProductQuantity> items) = _Started;
//add item //add item
const factory CheckoutEvent.addItem( const factory CheckoutEvent.addItem(
Product product, ProductVariant? variant) = _AddItem; Product product, ProductVariant? variant) = _AddItem;
@@ -12,7 +12,7 @@ import 'package:intl/intl.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/presentation/home/bloc/qris/qris_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/qris/qris_bloc.dart';
import 'package:enaklo_pos/presentation/home/widgets/success_payment_dialog.dart'; // import 'package:enaklo_pos/presentation/home/widgets/success_payment_dialog.dart';
import 'package:widgets_to_image/widgets_to_image.dart'; import 'package:widgets_to_image/widgets_to_image.dart';
import 'package:enaklo_pos/core/utils/printer_service.dart'; import 'package:enaklo_pos/core/utils/printer_service.dart';
@@ -124,36 +124,36 @@ class _PaymentQrisDialogState extends State<PaymentQrisDialog> {
)); ));
}); });
}, success: (message) async { }, success: (message) async {
context.read<OrderBloc>().add(OrderEvent.order( // context.read<OrderBloc>().add(OrderEvent.order(
widget.items, // widget.items,
widget.discount, // widget.discount,
widget.discountAmount, // widget.discountAmount,
widget.tax, // widget.tax,
widget.serviceCharge, // widget.serviceCharge,
widget.paymentAmount, // widget.paymentAmount,
widget.customerName, // widget.customerName,
widget.tableNumber, // widget.tableNumber,
'completed', // 'completed',
'paid', // 'paid',
'Qris', // 'Qris',
widget.price, // widget.price,
OrderType.dineIn)); // OrderType.dineIn));
await showDialog( // await showDialog(
context: context, // context: context,
barrierDismissible: false, // barrierDismissible: false,
builder: (context) => SuccessPaymentDialog( // builder: (context) => SuccessPaymentDialog(
isTablePaymentPage: widget.isTablePaymentPage, // isTablePaymentPage: widget.isTablePaymentPage,
data: widget.items, // data: widget.items,
totalQty: widget.totalQty, // totalQty: widget.totalQty,
totalPrice: widget.price, // totalPrice: widget.price,
totalTax: widget.tax, // totalTax: widget.tax,
totalDiscount: widget.discountAmount, // totalDiscount: widget.discountAmount,
subTotal: widget.subTotal, // subTotal: widget.subTotal,
normalPrice: widget.price, // normalPrice: widget.price,
totalService: widget.serviceCharge, // totalService: widget.serviceCharge,
draftName: widget.customerName, // draftName: widget.customerName,
), // ),
); // );
}); });
}, },
child: BlocBuilder<QrisBloc, QrisState>( child: BlocBuilder<QrisBloc, QrisState>(
@@ -13,7 +13,7 @@ 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/payment_methods/payment_methods_bloc.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.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/models/order_type.dart';
import 'package:enaklo_pos/presentation/home/widgets/save_order_dialog.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/models/response/payment_methods_response_model.dart';
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart'; import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
@@ -4,6 +4,7 @@ import 'dart:developer';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:enaklo_pos/presentation/customer/pages/customer_page.dart'; import 'package:enaklo_pos/presentation/customer/pages/customer_page.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:enaklo_pos/presentation/setting/pages/setting_page.dart'; import 'package:enaklo_pos/presentation/setting/pages/setting_page.dart';
import 'package:enaklo_pos/presentation/table/pages/table_page.dart'; import 'package:enaklo_pos/presentation/table/pages/table_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -26,10 +27,13 @@ import 'home_page.dart';
class DashboardPage extends StatefulWidget { class DashboardPage extends StatefulWidget {
final int? index; final int? index;
final TableModel? table; final TableModel? table;
final List<ProductQuantity>? items;
const DashboardPage({ const DashboardPage({
super.key, super.key,
this.index = 0, this.index = 0,
this.table, this.table,
this.items,
}); });
@override @override
@@ -56,8 +60,11 @@ class _DashboardPageState extends State<DashboardPage> {
HomePage( HomePage(
isTable: false, isTable: false,
table: widget.table, table: widget.table,
items: widget.items ?? [],
),
TablePage(
items: widget.items ?? [],
), ),
const TablePage(),
const ReportPage(), const ReportPage(),
const CustomerPage(), const CustomerPage(),
const SettingPage(), const SettingPage(),
+54 -64
View File
@@ -4,6 +4,7 @@ import 'package:enaklo_pos/presentation/home/bloc/category_loader/category_loade
import 'package:enaklo_pos/presentation/home/bloc/current_outlet/current_outlet_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/current_outlet/current_outlet_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/product_loader/product_loader_bloc.dart';
import 'package:enaklo_pos/presentation/home/bloc/user_update_outlet/user_update_outlet_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/user_update_outlet/user_update_outlet_bloc.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:enaklo_pos/presentation/home/widgets/category_tab_bar.dart'; import 'package:enaklo_pos/presentation/home/widgets/category_tab_bar.dart';
import 'package:enaklo_pos/presentation/home/widgets/home_right_title.dart'; import 'package:enaklo_pos/presentation/home/widgets/home_right_title.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -13,7 +14,6 @@ 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/int_ext.dart';
import 'package:enaklo_pos/data/models/response/table_model.dart'; import 'package:enaklo_pos/data/models/response/table_model.dart';
import 'package:enaklo_pos/presentation/home/pages/confirm_payment_page.dart'; import 'package:enaklo_pos/presentation/home/pages/confirm_payment_page.dart';
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
import '../../../core/assets/assets.gen.dart'; import '../../../core/assets/assets.gen.dart';
import '../../../core/components/buttons.dart'; import '../../../core/components/buttons.dart';
@@ -27,10 +27,12 @@ import '../widgets/product_card.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
final bool isTable; final bool isTable;
final TableModel? table; final TableModel? table;
final List<ProductQuantity> items;
const HomePage({ const HomePage({
super.key, super.key,
required this.isTable, required this.isTable,
this.table, this.table,
required this.items,
}); });
@override @override
@@ -75,7 +77,7 @@ class _HomePageState extends State<HomePage> {
.add(const ProductLoaderEvent.getProduct()); .add(const ProductLoaderEvent.getProduct());
// Initialize checkout with tax and service charge settings // Initialize checkout with tax and service charge settings
context.read<CheckoutBloc>().add(const CheckoutEvent.started()); context.read<CheckoutBloc>().add(CheckoutEvent.started(widget.items));
// Get Category // Get Category
context.read<CategoryLoaderBloc>().add(CategoryLoaderEvent.get()); context.read<CategoryLoaderBloc>().add(CategoryLoaderEvent.get());
@@ -91,25 +93,8 @@ class _HomePageState extends State<HomePage> {
}); });
} }
List<Product> _filterProducts(List<Product> products) {
if (searchQuery.isEmpty) {
return products;
}
return products.where((product) {
final productName = product.name?.toLowerCase() ?? '';
final queryLower = searchQuery.toLowerCase();
return productName.contains(queryLower);
}).toList();
}
bool _handleScrollNotification( bool _handleScrollNotification(
ScrollNotification notification, String? categoryId) { ScrollNotification notification, String? categoryId) {
// Check if the ScrollController is attached before accessing position
if (!scrollController.hasClients) {
return false;
}
if (notification is ScrollEndNotification && if (notification is ScrollEndNotification &&
scrollController.position.extentAfter == 0) { scrollController.position.extentAfter == 0) {
context.read<ProductLoaderBloc>().add( context.read<ProductLoaderBloc>().add(
@@ -178,48 +163,53 @@ class _HomePageState extends State<HomePage> {
), ),
BlocBuilder<ProductLoaderBloc, ProductLoaderState>( BlocBuilder<ProductLoaderBloc, ProductLoaderState>(
builder: (context, state) { builder: (context, state) {
return NotificationListener<ScrollNotification>( return Expanded(
onNotification: (notification) { child: CategoryTabBar(
return state.maybeWhen( categories: categories,
orElse: () => false, tabViews: categories.map((category) {
loaded: (products, hasReachedMax, return SizedBox(
currentPage, isLoadingMore) { child: state.maybeWhen(orElse: () {
return _handleScrollNotification( return const Center(
notification, categoryId); child: CircularProgressIndicator(),
}, );
); }, loading: () {
}, return const Center(
child: Expanded( child: CircularProgressIndicator(),
child: CategoryTabBar( );
categories: categories, }, loaded: (products, hashasReachedMax,
tabViews: categories.map((category) { currentPage, isLoadingMore) {
return SizedBox( if (products.isEmpty) {
child: state.maybeWhen(orElse: () { return Center(
return const Center( child: Column(
child: children: [
CircularProgressIndicator(), Text('No Items Found'),
SpaceHeight(20),
Button.filled(
width: 120,
onPressed: () {
context
.read<
ProductLoaderBloc>()
.add(const ProductLoaderEvent
.getProduct());
},
label: 'Retry',
),
],
),
); );
}, loading: () { }
return const Center( return NotificationListener<
child: ScrollNotification>(
CircularProgressIndicator(), onNotification: (notification) {
); return _handleScrollNotification(
}, loaded: (products, notification, categoryId);
hashasReachedMax, },
currentPage, child: GridView.builder(
isLoadingMore) { itemCount: products.length,
final filteredProducts =
_filterProducts(products);
if (filteredProducts.isEmpty) {
return const Center(
child: Text('No Items Found'),
);
}
return GridView.builder(
itemCount:
filteredProducts.length,
controller: scrollController, controller: scrollController,
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
cacheExtent: 80.0,
gridDelegate: gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent( SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 180, maxCrossAxisExtent: 180,
@@ -229,14 +219,14 @@ class _HomePageState extends State<HomePage> {
), ),
itemBuilder: (context, index) => itemBuilder: (context, index) =>
ProductCard( ProductCard(
data: filteredProducts[index], data: products[index],
onCartButton: () {}, onCartButton: () {},
), ),
); ),
}), );
); }),
}).toList(), );
), }).toList(),
), ),
); );
}, },
@@ -135,6 +135,7 @@ class HomeRightTitle extends StatelessWidget {
if (table == null) { if (table == null) {
context.push(DashboardPage( context.push(DashboardPage(
index: 1, index: 1,
items: items,
)); ));
} }
}, },
@@ -60,6 +60,8 @@ class ProductCard extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
width: double.infinity, width: double.infinity,
height: 120, height: 120,
memCacheHeight: 120,
memCacheWidth: 120,
errorWidget: (context, url, error) => Container( errorWidget: (context, url, error) => Container(
width: double.infinity, width: double.infinity,
height: 120, height: 120,
@@ -1,211 +0,0 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:enaklo_pos/core/extensions/string_ext.dart';
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/data/dataoutputs/print_dataoutputs.dart';
import 'package:enaklo_pos/data/models/response/table_model.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.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 '../models/order_type.dart';
import 'package:enaklo_pos/core/utils/printer_service.dart';
class SaveOrderDialog extends StatefulWidget {
const SaveOrderDialog({
super.key,
required this.data,
required this.totalQty,
required this.totalPrice,
required this.totalTax,
required this.totalDiscount,
required this.subTotal,
required this.normalPrice,
required this.table,
required this.draftName,
});
final List<ProductQuantity> data;
final int totalQty;
final int totalPrice;
final int totalTax;
final int totalDiscount;
final int subTotal;
final int normalPrice;
final TableModel table;
final String draftName;
@override
State<SaveOrderDialog> createState() => _SaveOrderDialogState();
}
class _SaveOrderDialogState extends State<SaveOrderDialog> {
// 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(
'Order Berhasil Disimpan',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
),
),
),
const SpaceHeight(20.0),
Row(
children: [
Flexible(
child: Button.outlined(
onPressed: () {
context
.read<CheckoutBloc>()
.add(const CheckoutEvent.started());
context
.read<GetTableBloc>()
.add(const GetTableEvent.getTables());
context.popToRoot();
},
label: 'Kembali',
),
),
const SpaceWidth(8.0),
Flexible(
child: BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, state) {
final orderType = state.maybeWhen(
orElse: () => OrderType.dineIn,
loaded: (
items,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType,
deliveryType,
) =>
orderType,
);
return Button.filled(
onPressed: () async {
final checkerPrinter = await ProductLocalDatasource
.instance
.getPrinterByCode('checker');
final kitchenPrinter = await ProductLocalDatasource
.instance
.getPrinterByCode('kitchen');
final barPrinter = await ProductLocalDatasource
.instance
.getPrinterByCode('bar');
log("Checker printer: ${checkerPrinter?.toMap()}");
log("Kitchen printer: ${kitchenPrinter?.toMap()}");
log("Bar printer: ${barPrinter?.toMap()}");
// Checker printer
if (checkerPrinter != null) {
try {
final printValue = await PrintDataoutputs.instance
.printChecker(
widget.data,
widget.table.tableName!,
widget.draftName,
'kasir',
checkerPrinter.paper.toIntegerFromText,
orderType.value);
await PrinterService().printWithPrinter(
checkerPrinter, printValue, context);
} catch (e) {
log("Error printing checker: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Error printing checker: $e')),
);
}
}
// Kitchen printer
if (kitchenPrinter != null) {
try {
final printValue =
await PrintDataoutputs.instance.printKitchen(
widget.data,
widget.table.tableName!,
widget.draftName,
'kasir',
kitchenPrinter.paper.toIntegerFromText,
orderType.value,
);
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')),
);
}
}
// Bar printer
if (barPrinter != null) {
try {
final printValue =
await PrintDataoutputs.instance.printBar(
widget.data,
widget.table.tableName!,
widget.draftName,
'kasir',
barPrinter.paper.toIntegerFromText,
orderType.value,
);
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')),
);
}
}
},
label: 'Print Checker',
);
},
),
),
],
),
],
),
),
);
}
}
@@ -1,349 +0,0 @@
// 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) {
state.maybeWhen(
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>()
.add(const CheckoutEvent.started());
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;
return BlocBuilder<CheckoutBloc, CheckoutState>(
builder: (context, checkoutState) {
final orderType = checkoutState.maybeWhen(
orElse: () => OrderType.dineIn,
loaded: (
items,
discountModel,
discount,
discountAmount,
tax,
serviceCharge,
totalQuantity,
totalPrice,
draftName,
orderType,
deliveryType,
) =>
orderType,
);
return Button.filled(
onPressed: () async {
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,
);
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')),
);
}
}
// 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,
);
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')),
);
}
}
},
label: 'Print',
);
},
);
},
),
),
],
),
],
),
),
);
}
}
@@ -0,0 +1,28 @@
import 'package:bloc/bloc.dart';
import 'package:enaklo_pos/data/datasources/analytic_remote_datasource.dart';
import 'package:enaklo_pos/data/models/response/category_analytic_response_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'category_report_event.dart';
part 'category_report_state.dart';
part 'category_report_bloc.freezed.dart';
class CategoryReportBloc
extends Bloc<CategoryReportEvent, CategoryReportState> {
final AnalyticRemoteDatasource _datasource;
CategoryReportBloc(this._datasource) : super(CategoryReportState.initial()) {
on<_Get>((event, emit) async {
emit(_Loading());
final result = await _datasource.getCategory(
dateFrom: event.startDate,
dateTo: event.endDate,
);
result.fold(
(l) => emit(_Error(l)),
(r) => emit(_Loaded(r.data!)),
);
});
}
}
@@ -0,0 +1,861 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'category_report_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$CategoryReportEvent {
DateTime get startDate => throw _privateConstructorUsedError;
DateTime get endDate => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
/// Create a copy of CategoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$CategoryReportEventCopyWith<CategoryReportEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryReportEventCopyWith<$Res> {
factory $CategoryReportEventCopyWith(
CategoryReportEvent value, $Res Function(CategoryReportEvent) then) =
_$CategoryReportEventCopyWithImpl<$Res, CategoryReportEvent>;
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class _$CategoryReportEventCopyWithImpl<$Res, $Val extends CategoryReportEvent>
implements $CategoryReportEventCopyWith<$Res> {
_$CategoryReportEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_value.copyWith(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
) as $Val);
}
}
/// @nodoc
abstract class _$$GetImplCopyWith<$Res>
implements $CategoryReportEventCopyWith<$Res> {
factory _$$GetImplCopyWith(_$GetImpl value, $Res Function(_$GetImpl) then) =
__$$GetImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class __$$GetImplCopyWithImpl<$Res>
extends _$CategoryReportEventCopyWithImpl<$Res, _$GetImpl>
implements _$$GetImplCopyWith<$Res> {
__$$GetImplCopyWithImpl(_$GetImpl _value, $Res Function(_$GetImpl) _then)
: super(_value, _then);
/// Create a copy of CategoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_$GetImpl(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
));
}
}
/// @nodoc
class _$GetImpl implements _Get {
const _$GetImpl({required this.startDate, required this.endDate});
@override
final DateTime startDate;
@override
final DateTime endDate;
@override
String toString() {
return 'CategoryReportEvent.get(startDate: $startDate, endDate: $endDate)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GetImpl &&
(identical(other.startDate, startDate) ||
other.startDate == startDate) &&
(identical(other.endDate, endDate) || other.endDate == endDate));
}
@override
int get hashCode => Object.hash(runtimeType, startDate, endDate);
/// Create a copy of CategoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
__$$GetImplCopyWithImpl<_$GetImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) {
return get(startDate, endDate);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) {
return get?.call(startDate, endDate);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(startDate, endDate);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) {
return get(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) {
return get?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(this);
}
return orElse();
}
}
abstract class _Get implements CategoryReportEvent {
const factory _Get(
{required final DateTime startDate,
required final DateTime endDate}) = _$GetImpl;
@override
DateTime get startDate;
@override
DateTime get endDate;
/// Create a copy of CategoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$CategoryReportState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(CategoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(CategoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(CategoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CategoryReportStateCopyWith<$Res> {
factory $CategoryReportStateCopyWith(
CategoryReportState value, $Res Function(CategoryReportState) then) =
_$CategoryReportStateCopyWithImpl<$Res, CategoryReportState>;
}
/// @nodoc
class _$CategoryReportStateCopyWithImpl<$Res, $Val extends CategoryReportState>
implements $CategoryReportStateCopyWith<$Res> {
_$CategoryReportStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$InitialImplCopyWith<$Res> {
factory _$$InitialImplCopyWith(
_$InitialImpl value, $Res Function(_$InitialImpl) then) =
__$$InitialImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$InitialImplCopyWithImpl<$Res>
extends _$CategoryReportStateCopyWithImpl<$Res, _$InitialImpl>
implements _$$InitialImplCopyWith<$Res> {
__$$InitialImplCopyWithImpl(
_$InitialImpl _value, $Res Function(_$InitialImpl) _then)
: super(_value, _then);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$InitialImpl implements _Initial {
const _$InitialImpl();
@override
String toString() {
return 'CategoryReportState.initial()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$InitialImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(CategoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(CategoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return initial?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(CategoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return initial?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements CategoryReportState {
const factory _Initial() = _$InitialImpl;
}
/// @nodoc
abstract class _$$LoadingImplCopyWith<$Res> {
factory _$$LoadingImplCopyWith(
_$LoadingImpl value, $Res Function(_$LoadingImpl) then) =
__$$LoadingImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$LoadingImplCopyWithImpl<$Res>
extends _$CategoryReportStateCopyWithImpl<$Res, _$LoadingImpl>
implements _$$LoadingImplCopyWith<$Res> {
__$$LoadingImplCopyWithImpl(
_$LoadingImpl _value, $Res Function(_$LoadingImpl) _then)
: super(_value, _then);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$LoadingImpl implements _Loading {
const _$LoadingImpl();
@override
String toString() {
return 'CategoryReportState.loading()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(CategoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return loading();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(CategoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return loading?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(CategoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loading(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loading?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading(this);
}
return orElse();
}
}
abstract class _Loading implements CategoryReportState {
const factory _Loading() = _$LoadingImpl;
}
/// @nodoc
abstract class _$$LoadedImplCopyWith<$Res> {
factory _$$LoadedImplCopyWith(
_$LoadedImpl value, $Res Function(_$LoadedImpl) then) =
__$$LoadedImplCopyWithImpl<$Res>;
@useResult
$Res call({CategoryAnalyticData data});
}
/// @nodoc
class __$$LoadedImplCopyWithImpl<$Res>
extends _$CategoryReportStateCopyWithImpl<$Res, _$LoadedImpl>
implements _$$LoadedImplCopyWith<$Res> {
__$$LoadedImplCopyWithImpl(
_$LoadedImpl _value, $Res Function(_$LoadedImpl) _then)
: super(_value, _then);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? data = null,
}) {
return _then(_$LoadedImpl(
null == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as CategoryAnalyticData,
));
}
}
/// @nodoc
class _$LoadedImpl implements _Loaded {
const _$LoadedImpl(this.data);
@override
final CategoryAnalyticData data;
@override
String toString() {
return 'CategoryReportState.loaded(data: $data)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoadedImpl &&
(identical(other.data, data) || other.data == data));
}
@override
int get hashCode => Object.hash(runtimeType, data);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
__$$LoadedImplCopyWithImpl<_$LoadedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(CategoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return loaded(data);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(CategoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return loaded?.call(data);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(CategoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(data);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loaded(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loaded?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(this);
}
return orElse();
}
}
abstract class _Loaded implements CategoryReportState {
const factory _Loaded(final CategoryAnalyticData data) = _$LoadedImpl;
CategoryAnalyticData get data;
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$ErrorImplCopyWith<$Res> {
factory _$$ErrorImplCopyWith(
_$ErrorImpl value, $Res Function(_$ErrorImpl) then) =
__$$ErrorImplCopyWithImpl<$Res>;
@useResult
$Res call({String message});
}
/// @nodoc
class __$$ErrorImplCopyWithImpl<$Res>
extends _$CategoryReportStateCopyWithImpl<$Res, _$ErrorImpl>
implements _$$ErrorImplCopyWith<$Res> {
__$$ErrorImplCopyWithImpl(
_$ErrorImpl _value, $Res Function(_$ErrorImpl) _then)
: super(_value, _then);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? message = null,
}) {
return _then(_$ErrorImpl(
null == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$ErrorImpl implements _Error {
const _$ErrorImpl(this.message);
@override
final String message;
@override
String toString() {
return 'CategoryReportState.error(message: $message)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ErrorImpl &&
(identical(other.message, message) || other.message == message));
}
@override
int get hashCode => Object.hash(runtimeType, message);
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
__$$ErrorImplCopyWithImpl<_$ErrorImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(CategoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return error(message);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(CategoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return error?.call(message);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(CategoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(message);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return error(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return error?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(this);
}
return orElse();
}
}
abstract class _Error implements CategoryReportState {
const factory _Error(final String message) = _$ErrorImpl;
String get message;
/// Create a copy of CategoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,9 @@
part of 'category_report_bloc.dart';
@freezed
class CategoryReportEvent with _$CategoryReportEvent {
const factory CategoryReportEvent.get({
required DateTime startDate,
required DateTime endDate,
}) = _Get;
}
@@ -0,0 +1,9 @@
part of 'category_report_bloc.dart';
@freezed
class CategoryReportState with _$CategoryReportState {
const factory CategoryReportState.initial() = _Initial;
const factory CategoryReportState.loading() = _Loading;
const factory CategoryReportState.loaded(CategoryAnalyticData data) = _Loaded;
const factory CategoryReportState.error(String message) = _Error;
}
@@ -0,0 +1,29 @@
import 'package:bloc/bloc.dart';
import 'package:enaklo_pos/data/datasources/analytic_remote_datasource.dart';
import 'package:enaklo_pos/data/models/response/inventory_analytic_response_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'inventory_report_event.dart';
part 'inventory_report_state.dart';
part 'inventory_report_bloc.freezed.dart';
class InventoryReportBloc
extends Bloc<InventoryReportEvent, InventoryReportState> {
final AnalyticRemoteDatasource _datasource;
InventoryReportBloc(this._datasource)
: super(InventoryReportState.initial()) {
on<_Get>((event, emit) async {
emit(_Loading());
final result = await _datasource.getInventory(
dateFrom: event.startDate, dateTo: event.endDate);
result.fold(
(f) => emit(_Error(f)),
(r) => emit(
_Loaded(r.data!),
),
);
});
}
}
@@ -0,0 +1,863 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'inventory_report_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$InventoryReportEvent {
DateTime get startDate => throw _privateConstructorUsedError;
DateTime get endDate => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
/// Create a copy of InventoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$InventoryReportEventCopyWith<InventoryReportEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $InventoryReportEventCopyWith<$Res> {
factory $InventoryReportEventCopyWith(InventoryReportEvent value,
$Res Function(InventoryReportEvent) then) =
_$InventoryReportEventCopyWithImpl<$Res, InventoryReportEvent>;
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class _$InventoryReportEventCopyWithImpl<$Res,
$Val extends InventoryReportEvent>
implements $InventoryReportEventCopyWith<$Res> {
_$InventoryReportEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of InventoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_value.copyWith(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
) as $Val);
}
}
/// @nodoc
abstract class _$$GetImplCopyWith<$Res>
implements $InventoryReportEventCopyWith<$Res> {
factory _$$GetImplCopyWith(_$GetImpl value, $Res Function(_$GetImpl) then) =
__$$GetImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class __$$GetImplCopyWithImpl<$Res>
extends _$InventoryReportEventCopyWithImpl<$Res, _$GetImpl>
implements _$$GetImplCopyWith<$Res> {
__$$GetImplCopyWithImpl(_$GetImpl _value, $Res Function(_$GetImpl) _then)
: super(_value, _then);
/// Create a copy of InventoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_$GetImpl(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
));
}
}
/// @nodoc
class _$GetImpl implements _Get {
const _$GetImpl({required this.startDate, required this.endDate});
@override
final DateTime startDate;
@override
final DateTime endDate;
@override
String toString() {
return 'InventoryReportEvent.get(startDate: $startDate, endDate: $endDate)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GetImpl &&
(identical(other.startDate, startDate) ||
other.startDate == startDate) &&
(identical(other.endDate, endDate) || other.endDate == endDate));
}
@override
int get hashCode => Object.hash(runtimeType, startDate, endDate);
/// Create a copy of InventoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
__$$GetImplCopyWithImpl<_$GetImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) {
return get(startDate, endDate);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) {
return get?.call(startDate, endDate);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(startDate, endDate);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) {
return get(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) {
return get?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(this);
}
return orElse();
}
}
abstract class _Get implements InventoryReportEvent {
const factory _Get(
{required final DateTime startDate,
required final DateTime endDate}) = _$GetImpl;
@override
DateTime get startDate;
@override
DateTime get endDate;
/// Create a copy of InventoryReportEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$InventoryReportState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(InventoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(InventoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(InventoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $InventoryReportStateCopyWith<$Res> {
factory $InventoryReportStateCopyWith(InventoryReportState value,
$Res Function(InventoryReportState) then) =
_$InventoryReportStateCopyWithImpl<$Res, InventoryReportState>;
}
/// @nodoc
class _$InventoryReportStateCopyWithImpl<$Res,
$Val extends InventoryReportState>
implements $InventoryReportStateCopyWith<$Res> {
_$InventoryReportStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$InitialImplCopyWith<$Res> {
factory _$$InitialImplCopyWith(
_$InitialImpl value, $Res Function(_$InitialImpl) then) =
__$$InitialImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$InitialImplCopyWithImpl<$Res>
extends _$InventoryReportStateCopyWithImpl<$Res, _$InitialImpl>
implements _$$InitialImplCopyWith<$Res> {
__$$InitialImplCopyWithImpl(
_$InitialImpl _value, $Res Function(_$InitialImpl) _then)
: super(_value, _then);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$InitialImpl implements _Initial {
const _$InitialImpl();
@override
String toString() {
return 'InventoryReportState.initial()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$InitialImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(InventoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(InventoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return initial?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(InventoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return initial?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements InventoryReportState {
const factory _Initial() = _$InitialImpl;
}
/// @nodoc
abstract class _$$LoadingImplCopyWith<$Res> {
factory _$$LoadingImplCopyWith(
_$LoadingImpl value, $Res Function(_$LoadingImpl) then) =
__$$LoadingImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$LoadingImplCopyWithImpl<$Res>
extends _$InventoryReportStateCopyWithImpl<$Res, _$LoadingImpl>
implements _$$LoadingImplCopyWith<$Res> {
__$$LoadingImplCopyWithImpl(
_$LoadingImpl _value, $Res Function(_$LoadingImpl) _then)
: super(_value, _then);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$LoadingImpl implements _Loading {
const _$LoadingImpl();
@override
String toString() {
return 'InventoryReportState.loading()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(InventoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return loading();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(InventoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return loading?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(InventoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loading(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loading?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading(this);
}
return orElse();
}
}
abstract class _Loading implements InventoryReportState {
const factory _Loading() = _$LoadingImpl;
}
/// @nodoc
abstract class _$$LoadedImplCopyWith<$Res> {
factory _$$LoadedImplCopyWith(
_$LoadedImpl value, $Res Function(_$LoadedImpl) then) =
__$$LoadedImplCopyWithImpl<$Res>;
@useResult
$Res call({InventoryAnalyticData data});
}
/// @nodoc
class __$$LoadedImplCopyWithImpl<$Res>
extends _$InventoryReportStateCopyWithImpl<$Res, _$LoadedImpl>
implements _$$LoadedImplCopyWith<$Res> {
__$$LoadedImplCopyWithImpl(
_$LoadedImpl _value, $Res Function(_$LoadedImpl) _then)
: super(_value, _then);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? data = null,
}) {
return _then(_$LoadedImpl(
null == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as InventoryAnalyticData,
));
}
}
/// @nodoc
class _$LoadedImpl implements _Loaded {
const _$LoadedImpl(this.data);
@override
final InventoryAnalyticData data;
@override
String toString() {
return 'InventoryReportState.loaded(data: $data)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoadedImpl &&
(identical(other.data, data) || other.data == data));
}
@override
int get hashCode => Object.hash(runtimeType, data);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
__$$LoadedImplCopyWithImpl<_$LoadedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(InventoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return loaded(data);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(InventoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return loaded?.call(data);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(InventoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(data);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loaded(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loaded?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(this);
}
return orElse();
}
}
abstract class _Loaded implements InventoryReportState {
const factory _Loaded(final InventoryAnalyticData data) = _$LoadedImpl;
InventoryAnalyticData get data;
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$ErrorImplCopyWith<$Res> {
factory _$$ErrorImplCopyWith(
_$ErrorImpl value, $Res Function(_$ErrorImpl) then) =
__$$ErrorImplCopyWithImpl<$Res>;
@useResult
$Res call({String message});
}
/// @nodoc
class __$$ErrorImplCopyWithImpl<$Res>
extends _$InventoryReportStateCopyWithImpl<$Res, _$ErrorImpl>
implements _$$ErrorImplCopyWith<$Res> {
__$$ErrorImplCopyWithImpl(
_$ErrorImpl _value, $Res Function(_$ErrorImpl) _then)
: super(_value, _then);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? message = null,
}) {
return _then(_$ErrorImpl(
null == message
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$ErrorImpl implements _Error {
const _$ErrorImpl(this.message);
@override
final String message;
@override
String toString() {
return 'InventoryReportState.error(message: $message)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ErrorImpl &&
(identical(other.message, message) || other.message == message));
}
@override
int get hashCode => Object.hash(runtimeType, message);
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
__$$ErrorImplCopyWithImpl<_$ErrorImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(InventoryAnalyticData data) loaded,
required TResult Function(String message) error,
}) {
return error(message);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(InventoryAnalyticData data)? loaded,
TResult? Function(String message)? error,
}) {
return error?.call(message);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(InventoryAnalyticData data)? loaded,
TResult Function(String message)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(message);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return error(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return error?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(this);
}
return orElse();
}
}
abstract class _Error implements InventoryReportState {
const factory _Error(final String message) = _$ErrorImpl;
String get message;
/// Create a copy of InventoryReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,9 @@
part of 'inventory_report_bloc.dart';
@freezed
class InventoryReportEvent with _$InventoryReportEvent {
const factory InventoryReportEvent.get({
required DateTime startDate,
required DateTime endDate,
}) = _Get;
}
@@ -0,0 +1,10 @@
part of 'inventory_report_bloc.dart';
@freezed
class InventoryReportState with _$InventoryReportState {
const factory InventoryReportState.initial() = _Initial;
const factory InventoryReportState.loading() = _Loading;
const factory InventoryReportState.loaded(InventoryAnalyticData data) =
_Loaded;
const factory InventoryReportState.error(String message) = _Error;
}
@@ -22,7 +22,7 @@ class PaymentMethodReportBloc
(l) => emit(_Error(l)), (l) => emit(_Error(l)),
(r) => emit( (r) => emit(
_Loaded( _Loaded(
r.data, r.data!,
), ),
), ),
); );
@@ -16,7 +16,7 @@ class ProfitLossBloc extends Bloc<ProfitLossEvent, ProfitLossState> {
dateFrom: event.startDate, dateFrom: event.startDate,
dateTo: event.endDate, dateTo: event.endDate,
); );
result.fold((l) => emit(_Error(l)), (r) => emit(_Success(r.data))); result.fold((l) => emit(_Error(l)), (r) => emit(_Success(r.data!)));
}); });
} }
} }
@@ -0,0 +1,63 @@
import 'package:bloc/bloc.dart';
import 'package:enaklo_pos/data/datasources/analytic_remote_datasource.dart';
import 'package:enaklo_pos/data/datasources/outlet_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/category_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_method_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/product_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/profit_loss_response_model.dart';
import 'package:enaklo_pos/presentation/home/models/outlet_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'report_event.dart';
part 'report_state.dart';
part 'report_bloc.freezed.dart';
class ReportBloc extends Bloc<ReportEvent, ReportState> {
final AnalyticRemoteDatasource _datasource;
ReportBloc(this._datasource) : super(ReportState.initial()) {
on<_Get>((event, emit) async {
emit(_Loading());
final outlet = await OutletLocalDatasource().get();
final category = await _datasource.getCategory(
dateFrom: event.startDate, dateTo: event.endDate);
final product = await _datasource.getProduct(
dateFrom: event.startDate, dateTo: event.endDate);
final paymentMethod = await _datasource.getPaymentMethod(
dateFrom: event.startDate, dateTo: event.endDate);
final profitLoss = await _datasource.getProfitLoss(
dateFrom: event.startDate, dateTo: event.endDate);
if (category.isLeft() ||
product.isLeft() ||
paymentMethod.isLeft() ||
profitLoss.isLeft()) {
emit(_Error());
}
emit(_Loaded(
outlet,
category
.getOrElse(
() => CategoryAnalyticResponseModel(success: false, data: null))
.data,
profitLoss
.getOrElse(
() => ProfitLossResponseModel(success: false, data: null))
.data,
paymentMethod
.getOrElse(() =>
PaymentMethodAnalyticResponseModel(success: false, data: null))
.data,
product
.getOrElse(
() => ProductAnalyticResponseModel(success: false, data: null))
.data,
));
});
}
}
@@ -0,0 +1,975 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'report_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$ReportEvent {
DateTime get startDate => throw _privateConstructorUsedError;
DateTime get endDate => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
/// Create a copy of ReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ReportEventCopyWith<ReportEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ReportEventCopyWith<$Res> {
factory $ReportEventCopyWith(
ReportEvent value, $Res Function(ReportEvent) then) =
_$ReportEventCopyWithImpl<$Res, ReportEvent>;
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class _$ReportEventCopyWithImpl<$Res, $Val extends ReportEvent>
implements $ReportEventCopyWith<$Res> {
_$ReportEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_value.copyWith(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
) as $Val);
}
}
/// @nodoc
abstract class _$$GetImplCopyWith<$Res> implements $ReportEventCopyWith<$Res> {
factory _$$GetImplCopyWith(_$GetImpl value, $Res Function(_$GetImpl) then) =
__$$GetImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({DateTime startDate, DateTime endDate});
}
/// @nodoc
class __$$GetImplCopyWithImpl<$Res>
extends _$ReportEventCopyWithImpl<$Res, _$GetImpl>
implements _$$GetImplCopyWith<$Res> {
__$$GetImplCopyWithImpl(_$GetImpl _value, $Res Function(_$GetImpl) _then)
: super(_value, _then);
/// Create a copy of ReportEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? startDate = null,
Object? endDate = null,
}) {
return _then(_$GetImpl(
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
));
}
}
/// @nodoc
class _$GetImpl implements _Get {
const _$GetImpl({required this.startDate, required this.endDate});
@override
final DateTime startDate;
@override
final DateTime endDate;
@override
String toString() {
return 'ReportEvent.get(startDate: $startDate, endDate: $endDate)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GetImpl &&
(identical(other.startDate, startDate) ||
other.startDate == startDate) &&
(identical(other.endDate, endDate) || other.endDate == endDate));
}
@override
int get hashCode => Object.hash(runtimeType, startDate, endDate);
/// Create a copy of ReportEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
__$$GetImplCopyWithImpl<_$GetImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime startDate, DateTime endDate) get,
}) {
return get(startDate, endDate);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime startDate, DateTime endDate)? get,
}) {
return get?.call(startDate, endDate);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime startDate, DateTime endDate)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(startDate, endDate);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Get value) get,
}) {
return get(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Get value)? get,
}) {
return get?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Get value)? get,
required TResult orElse(),
}) {
if (get != null) {
return get(this);
}
return orElse();
}
}
abstract class _Get implements ReportEvent {
const factory _Get(
{required final DateTime startDate,
required final DateTime endDate}) = _$GetImpl;
@override
DateTime get startDate;
@override
DateTime get endDate;
/// Create a copy of ReportEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GetImplCopyWith<_$GetImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$ReportState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)
loaded,
required TResult Function() error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult? Function()? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult Function()? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ReportStateCopyWith<$Res> {
factory $ReportStateCopyWith(
ReportState value, $Res Function(ReportState) then) =
_$ReportStateCopyWithImpl<$Res, ReportState>;
}
/// @nodoc
class _$ReportStateCopyWithImpl<$Res, $Val extends ReportState>
implements $ReportStateCopyWith<$Res> {
_$ReportStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$InitialImplCopyWith<$Res> {
factory _$$InitialImplCopyWith(
_$InitialImpl value, $Res Function(_$InitialImpl) then) =
__$$InitialImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$InitialImplCopyWithImpl<$Res>
extends _$ReportStateCopyWithImpl<$Res, _$InitialImpl>
implements _$$InitialImplCopyWith<$Res> {
__$$InitialImplCopyWithImpl(
_$InitialImpl _value, $Res Function(_$InitialImpl) _then)
: super(_value, _then);
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$InitialImpl implements _Initial {
const _$InitialImpl();
@override
String toString() {
return 'ReportState.initial()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$InitialImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)
loaded,
required TResult Function() error,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult? Function()? error,
}) {
return initial?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult Function()? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return initial?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements ReportState {
const factory _Initial() = _$InitialImpl;
}
/// @nodoc
abstract class _$$LoadingImplCopyWith<$Res> {
factory _$$LoadingImplCopyWith(
_$LoadingImpl value, $Res Function(_$LoadingImpl) then) =
__$$LoadingImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$LoadingImplCopyWithImpl<$Res>
extends _$ReportStateCopyWithImpl<$Res, _$LoadingImpl>
implements _$$LoadingImplCopyWith<$Res> {
__$$LoadingImplCopyWithImpl(
_$LoadingImpl _value, $Res Function(_$LoadingImpl) _then)
: super(_value, _then);
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$LoadingImpl implements _Loading {
const _$LoadingImpl();
@override
String toString() {
return 'ReportState.loading()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)
loaded,
required TResult Function() error,
}) {
return loading();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult? Function()? error,
}) {
return loading?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult Function()? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loading(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loading?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading(this);
}
return orElse();
}
}
abstract class _Loading implements ReportState {
const factory _Loading() = _$LoadingImpl;
}
/// @nodoc
abstract class _$$LoadedImplCopyWith<$Res> {
factory _$$LoadedImplCopyWith(
_$LoadedImpl value, $Res Function(_$LoadedImpl) then) =
__$$LoadedImplCopyWithImpl<$Res>;
@useResult
$Res call(
{Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData});
}
/// @nodoc
class __$$LoadedImplCopyWithImpl<$Res>
extends _$ReportStateCopyWithImpl<$Res, _$LoadedImpl>
implements _$$LoadedImplCopyWith<$Res> {
__$$LoadedImplCopyWithImpl(
_$LoadedImpl _value, $Res Function(_$LoadedImpl) _then)
: super(_value, _then);
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? outlet = null,
Object? categoryAnalyticData = freezed,
Object? profitLossData = freezed,
Object? paymentMethodAnalyticData = freezed,
Object? productAnalyticData = freezed,
}) {
return _then(_$LoadedImpl(
null == outlet
? _value.outlet
: outlet // ignore: cast_nullable_to_non_nullable
as Outlet,
freezed == categoryAnalyticData
? _value.categoryAnalyticData
: categoryAnalyticData // ignore: cast_nullable_to_non_nullable
as CategoryAnalyticData?,
freezed == profitLossData
? _value.profitLossData
: profitLossData // ignore: cast_nullable_to_non_nullable
as ProfitLossData?,
freezed == paymentMethodAnalyticData
? _value.paymentMethodAnalyticData
: paymentMethodAnalyticData // ignore: cast_nullable_to_non_nullable
as PaymentMethodAnalyticData?,
freezed == productAnalyticData
? _value.productAnalyticData
: productAnalyticData // ignore: cast_nullable_to_non_nullable
as ProductAnalyticData?,
));
}
}
/// @nodoc
class _$LoadedImpl implements _Loaded {
const _$LoadedImpl(
this.outlet,
this.categoryAnalyticData,
this.profitLossData,
this.paymentMethodAnalyticData,
this.productAnalyticData);
@override
final Outlet outlet;
@override
final CategoryAnalyticData? categoryAnalyticData;
@override
final ProfitLossData? profitLossData;
@override
final PaymentMethodAnalyticData? paymentMethodAnalyticData;
@override
final ProductAnalyticData? productAnalyticData;
@override
String toString() {
return 'ReportState.loaded(outlet: $outlet, categoryAnalyticData: $categoryAnalyticData, profitLossData: $profitLossData, paymentMethodAnalyticData: $paymentMethodAnalyticData, productAnalyticData: $productAnalyticData)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoadedImpl &&
(identical(other.outlet, outlet) || other.outlet == outlet) &&
(identical(other.categoryAnalyticData, categoryAnalyticData) ||
other.categoryAnalyticData == categoryAnalyticData) &&
(identical(other.profitLossData, profitLossData) ||
other.profitLossData == profitLossData) &&
(identical(other.paymentMethodAnalyticData,
paymentMethodAnalyticData) ||
other.paymentMethodAnalyticData == paymentMethodAnalyticData) &&
(identical(other.productAnalyticData, productAnalyticData) ||
other.productAnalyticData == productAnalyticData));
}
@override
int get hashCode => Object.hash(runtimeType, outlet, categoryAnalyticData,
profitLossData, paymentMethodAnalyticData, productAnalyticData);
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
__$$LoadedImplCopyWithImpl<_$LoadedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)
loaded,
required TResult Function() error,
}) {
return loaded(outlet, categoryAnalyticData, profitLossData,
paymentMethodAnalyticData, productAnalyticData);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult? Function()? error,
}) {
return loaded?.call(outlet, categoryAnalyticData, profitLossData,
paymentMethodAnalyticData, productAnalyticData);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult Function()? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(outlet, categoryAnalyticData, profitLossData,
paymentMethodAnalyticData, productAnalyticData);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return loaded(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return loaded?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(this);
}
return orElse();
}
}
abstract class _Loaded implements ReportState {
const factory _Loaded(
final Outlet outlet,
final CategoryAnalyticData? categoryAnalyticData,
final ProfitLossData? profitLossData,
final PaymentMethodAnalyticData? paymentMethodAnalyticData,
final ProductAnalyticData? productAnalyticData) = _$LoadedImpl;
Outlet get outlet;
CategoryAnalyticData? get categoryAnalyticData;
ProfitLossData? get profitLossData;
PaymentMethodAnalyticData? get paymentMethodAnalyticData;
ProductAnalyticData? get productAnalyticData;
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoadedImplCopyWith<_$LoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$ErrorImplCopyWith<$Res> {
factory _$$ErrorImplCopyWith(
_$ErrorImpl value, $Res Function(_$ErrorImpl) then) =
__$$ErrorImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$ErrorImplCopyWithImpl<$Res>
extends _$ReportStateCopyWithImpl<$Res, _$ErrorImpl>
implements _$$ErrorImplCopyWith<$Res> {
__$$ErrorImplCopyWithImpl(
_$ErrorImpl _value, $Res Function(_$ErrorImpl) _then)
: super(_value, _then);
/// Create a copy of ReportState
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$ErrorImpl implements _Error {
const _$ErrorImpl();
@override
String toString() {
return 'ReportState.error()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$ErrorImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() loading,
required TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)
loaded,
required TResult Function() error,
}) {
return error();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? initial,
TResult? Function()? loading,
TResult? Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult? Function()? error,
}) {
return error?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? loading,
TResult Function(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData)?
loaded,
TResult Function()? error,
required TResult orElse(),
}) {
if (error != null) {
return error();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_Loading value) loading,
required TResult Function(_Loaded value) loaded,
required TResult Function(_Error value) error,
}) {
return error(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Initial value)? initial,
TResult? Function(_Loading value)? loading,
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Error value)? error,
}) {
return error?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_Loading value)? loading,
TResult Function(_Loaded value)? loaded,
TResult Function(_Error value)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(this);
}
return orElse();
}
}
abstract class _Error implements ReportState {
const factory _Error() = _$ErrorImpl;
}
@@ -0,0 +1,9 @@
part of 'report_bloc.dart';
@freezed
class ReportEvent with _$ReportEvent {
const factory ReportEvent.get({
required DateTime startDate,
required DateTime endDate,
}) = _Get;
}
@@ -0,0 +1,15 @@
part of 'report_bloc.dart';
@freezed
class ReportState with _$ReportState {
const factory ReportState.initial() = _Initial;
const factory ReportState.loading() = _Loading;
const factory ReportState.loaded(
Outlet outlet,
CategoryAnalyticData? categoryAnalyticData,
ProfitLossData? profitLossData,
PaymentMethodAnalyticData? paymentMethodAnalyticData,
ProductAnalyticData? productAnalyticData,
) = _Loaded;
const factory ReportState.error() = _Error;
}
+260 -42
View File
@@ -1,12 +1,20 @@
import 'dart:developer'; import 'dart:developer';
import 'package:enaklo_pos/core/components/date_range_picker.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/core/utils/helper_pdf_service.dart';
import 'package:enaklo_pos/core/utils/permession_handler.dart';
import 'package:enaklo_pos/core/utils/transaction_report.dart';
import 'package:enaklo_pos/presentation/report/blocs/category_report/category_report_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/inventory_report/inventory_report_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/profit_loss/profit_loss_bloc.dart'; import 'package:enaklo_pos/presentation/report/blocs/profit_loss/profit_loss_bloc.dart';
import 'package:enaklo_pos/presentation/report/blocs/report/report_bloc.dart';
import 'package:enaklo_pos/presentation/report/widgets/category_report_widget.dart';
import 'package:enaklo_pos/presentation/report/widgets/dashboard_analytic_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/dashboard_analytic_widget.dart';
import 'package:enaklo_pos/presentation/report/widgets/inventory_report_widget.dart';
import 'package:enaklo_pos/presentation/report/widgets/profit_loss_widget.dart'; import 'package:enaklo_pos/presentation/report/widgets/profit_loss_widget.dart';
import 'package:enaklo_pos/presentation/sales/pages/sales_page.dart'; import 'package:enaklo_pos/presentation/sales/pages/sales_page.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:enaklo_pos/core/components/custom_date_picker.dart';
import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/constants/colors.dart';
import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart';
import 'package:enaklo_pos/core/utils/date_formatter.dart'; import 'package:enaklo_pos/core/utils/date_formatter.dart';
@@ -44,58 +52,180 @@ class _ReportPageState extends State<ReportPage> {
context.read<SummaryBloc>().add( context.read<SummaryBloc>().add(
SummaryEvent.getSummary(fromDate, toDate), SummaryEvent.getSummary(fromDate, toDate),
); );
context.read<ReportBloc>().add(
ReportEvent.get(startDate: fromDate, endDate: toDate),
);
}
onDateChanged(DateTime? startDate, DateTime? endDate) {
setState(() {
fromDate = startDate ?? fromDate;
toDate = endDate ?? toDate;
});
context.read<ReportBloc>().add(
ReportEvent.get(startDate: fromDate, endDate: toDate),
);
if (selectedMenu == 0) {
context.read<SummaryBloc>().add(
SummaryEvent.getSummary(fromDate, toDate),
);
}
if (selectedMenu == 2) {
context.read<ItemSalesReportBloc>().add(
ItemSalesReportEvent.getItemSales(
startDate: fromDate, endDate: toDate),
);
}
if (selectedMenu == 3) {
context.read<ProductSalesBloc>().add(
ProductSalesEvent.getProductSales(
fromDate,
toDate,
),
);
}
if (selectedMenu == 4) {
context.read<PaymentMethodReportBloc>().add(
PaymentMethodReportEvent.getPaymentMethodReport(
startDate: fromDate,
endDate: toDate,
),
);
}
if (selectedMenu == 5) {
context.read<ProfitLossBloc>().add(
ProfitLossEvent.getProfitLoss(
fromDate,
toDate,
),
);
}
if (selectedMenu == 6) {
context.read<InventoryReportBloc>().add(
InventoryReportEvent.get(
startDate: fromDate,
endDate: toDate,
),
);
}
if (selectedMenu == 7) {
context.read<CategoryReportBloc>().add(
CategoryReportEvent.get(
startDate: fromDate,
endDate: toDate,
),
);
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String searchDateFormatted = String searchDateFormatted =
'${fromDate.toFormattedDate2()} to ${toDate.toFormattedDate2()}'; '${fromDate.toFormattedDate2()} - ${toDate.toFormattedDate2()}';
return Scaffold( return Scaffold(
backgroundColor: AppColors.background, backgroundColor: AppColors.background,
body: Column( body: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ReportTitle( ReportTitle(
searchDateFormatted: searchDateFormatted,
actionWidget: [ actionWidget: [
SizedBox( InkWell(
width: 300, onTap: () {
child: CustomDatePicker( DateRangePickerModal.show(
prefix: const Text('From: '), context: context,
initialDate: fromDate, initialEndDate: toDate,
onDateSelected: (selectedDate) { initialStartDate: fromDate,
fromDate = selectedDate; primaryColor: AppColors.primary,
onChanged: onDateChanged,
setState(() {}); );
}, },
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
border: Border.all(
color: AppColors.stroke,
)),
child: Icon(
Icons.calendar_month_outlined,
color: AppColors.primary,
size: 28,
),
), ),
), ),
const SpaceWidth(24.0), const SpaceWidth(12.0),
SizedBox( BlocBuilder<ReportBloc, ReportState>(
width: 300, builder: (context, state) {
child: CustomDatePicker( return state.maybeWhen(
prefix: const Text('To: '), orElse: () => SizedBox.shrink(),
initialDate: toDate, loading: () => SizedBox(
onDateSelected: (selectedDate) { height: 24,
toDate = selectedDate; width: 24,
setState(() {}); child: const CircularProgressIndicator(),
// context.read<TransactionReportBloc>().add( ),
// TransactionReportEvent.getReport( loaded: (outlet, categoryAnalyticData, profitLossData,
// startDate: paymentMethodAnalyticData, productAnalyticData) =>
// DateFormatter.formatDateTime( InkWell(
// fromDate), onTap: () async {
// endDate: DateFormatter.formatDateTime( try {
// toDate)), final status =
// ); await PermessionHelper().checkPermission();
// context.read<ItemSalesReportBloc>().add( if (status) {
// ItemSalesReportEvent.getItemSales( final pdfFile = await TransactionReport.previewPdf(
// startDate: outlet: outlet,
// DateFormatter.formatDateTime( searchDateFormatted: searchDateFormatted,
// fromDate), categoryAnalyticData: categoryAnalyticData,
// endDate: DateFormatter.formatDateTime( profitLossData: profitLossData,
// toDate)), paymentMethodAnalyticData:
// ); paymentMethodAnalyticData,
}, productAnalyticData: productAnalyticData,
), );
log("pdfFile: $pdfFile");
await HelperPdfService.openFile(pdfFile);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Storage permission is required to save PDF'),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
log("Error generating PDF: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to generate PDF: $e'),
backgroundColor: Colors.red,
),
);
}
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 12.0, vertical: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
border: Border.all(
color: AppColors.stroke,
)),
child: Icon(
Icons.download,
color: AppColors.primary,
size: 28,
),
),
),
);
},
), ),
], ],
), ),
@@ -194,12 +324,12 @@ class _ReportPageState extends State<ReportPage> {
isActive: selectedMenu == 4, isActive: selectedMenu == 4,
), ),
ReportMenu( ReportMenu(
label: 'Laporan untung rugi', label: 'Laporan Untung Rugi',
subtitle: 'Laporan untung rugi penjualan.', subtitle: 'Laporan untung rugi penjualan.',
icon: Icons.trending_down, icon: Icons.trending_down,
onPressed: () { onPressed: () {
selectedMenu = 5; selectedMenu = 5;
title = 'Laporan untung rugi'; title = 'Laporan Untung Rugi';
setState(() {}); setState(() {});
context.read<ProfitLossBloc>().add( context.read<ProfitLossBloc>().add(
ProfitLossEvent.getProfitLoss( ProfitLossEvent.getProfitLoss(
@@ -210,6 +340,40 @@ class _ReportPageState extends State<ReportPage> {
}, },
isActive: selectedMenu == 5, isActive: selectedMenu == 5,
), ),
ReportMenu(
label: 'Laporan Inventori',
subtitle: 'Laporan inventori produk',
icon: Icons.archive_outlined,
onPressed: () {
selectedMenu = 6;
title = 'Laporan Inventori';
setState(() {});
context.read<InventoryReportBloc>().add(
InventoryReportEvent.get(
startDate: fromDate,
endDate: toDate,
),
);
},
isActive: selectedMenu == 6,
),
ReportMenu(
label: 'Laporan Kategori',
subtitle: 'Laporan kategori produk',
icon: Icons.category_outlined,
onPressed: () {
selectedMenu = 7;
title = 'Laporan Kategori';
setState(() {});
context.read<CategoryReportBloc>().add(
CategoryReportEvent.get(
startDate: fromDate,
endDate: toDate,
),
);
},
isActive: selectedMenu == 7,
),
], ],
), ),
), ),
@@ -360,7 +524,61 @@ class _ReportPageState extends State<ReportPage> {
); );
}, },
) )
: const SizedBox.shrink()), : selectedMenu == 6
? BlocBuilder<
InventoryReportBloc,
InventoryReportState>(
builder: (context, state) {
return state.maybeWhen(
orElse: () =>
const Center(
child:
CircularProgressIndicator(),
),
error: (message) {
return Text(message);
},
loaded: (data) {
return InventoryReportWidget(
title: title,
searchDateFormatted:
searchDateFormatted,
inventory: data,
);
},
);
},
)
: selectedMenu == 7
? BlocBuilder<
CategoryReportBloc,
CategoryReportState>(
builder:
(context, state) {
return state
.maybeWhen(
orElse: () =>
const Center(
child:
CircularProgressIndicator(),
),
error: (message) {
return Text(
message);
},
loaded: (data) {
return CategoryReportWidget(
title: title,
searchDateFormatted:
searchDateFormatted,
categoryAnalyticData:
data,
);
},
);
},
)
: const SizedBox.shrink()),
], ],
), ),
), ),
@@ -0,0 +1,292 @@
import 'package:enaklo_pos/core/constants/colors.dart';
import 'package:enaklo_pos/data/models/response/category_analytic_response_model.dart';
import 'package:flutter/material.dart';
class CategoryReportWidget extends StatelessWidget {
final String title;
final String searchDateFormatted;
final CategoryAnalyticData categoryAnalyticData;
const CategoryReportWidget({
super.key,
required this.title,
required this.searchDateFormatted,
required this.categoryAnalyticData,
});
String formatCurrency(int amount) {
return 'Rp ${amount.toString().replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
(Match m) => '${m[1]}.',
)}';
}
int getTotalRevenue() {
return categoryAnalyticData.data
.fold(0, (sum, item) => sum + item.totalRevenue);
}
int getTotalQuantity() {
return categoryAnalyticData.data
.fold(0, (sum, item) => sum + item.totalQuantity);
}
int getTotalOrders() {
return categoryAnalyticData.data
.fold(0, (sum, item) => sum + item.orderCount);
}
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: AppColors.background,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Section
Container(
width: double.infinity,
color: AppColors.primary,
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColors.whiteText,
),
),
const SizedBox(height: 8),
Text(
'Periode: $searchDateFormatted',
style: TextStyle(
fontSize: 14,
color: AppColors.whiteText.withOpacity(0.8),
),
),
],
),
),
// Summary Cards Section
Container(
color: AppColors.white,
padding: const EdgeInsets.all(20),
child: Row(
children: [
Expanded(
child: _buildSummaryCard(
'Total Pendapatan',
formatCurrency(getTotalRevenue()),
AppColors.green,
),
),
const SizedBox(width: 16),
Expanded(
child: _buildSummaryCard(
'Total Item Terjual',
'${getTotalQuantity()} pcs',
AppColors.subtitle,
),
),
const SizedBox(width: 16),
Expanded(
child: _buildSummaryCard(
'Total Pesanan',
'${getTotalOrders()}',
AppColors.primary,
),
),
],
),
),
// Categories List Header
Container(
color: AppColors.stroke,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: Row(
children: [
Expanded(
flex: 3,
child: Text(
'Kategori',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.black,
),
),
),
Expanded(
flex: 2,
child: Text(
'Pendapatan',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.black,
),
),
),
Expanded(
flex: 1,
child: Text(
'Qty',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.black,
),
),
),
Expanded(
flex: 1,
child: Text(
'Order',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.black,
),
),
),
],
),
),
// Categories List
Expanded(
child: Container(
color: AppColors.white,
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: categoryAnalyticData.data.length,
itemBuilder: (context, index) {
return _buildCategoryItem(
categoryAnalyticData.data[index], index);
},
),
),
),
],
),
);
}
Widget _buildSummaryCard(String title, String value, Color color) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.light,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.stroke, width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 12,
color: AppColors.subtitle,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
value,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: color,
),
),
],
),
);
}
Widget _buildCategoryItem(CategoryAnalyticItem category, int index) {
final isEven = index % 2 == 0;
return Container(
color: isEven ? AppColors.white : AppColors.light.withOpacity(0.3),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: Row(
children: [
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
category.categoryName,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.black,
),
),
const SizedBox(height: 4),
Text(
'${category.productCount} produk',
style: TextStyle(
fontSize: 12,
color: AppColors.subtitle,
),
),
],
),
),
Expanded(
flex: 2,
child: Column(
children: [
Text(
formatCurrency(category.totalRevenue),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.green,
),
),
],
),
),
Expanded(
flex: 1,
child: Text(
'${category.totalQuantity}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.black,
),
),
),
Expanded(
flex: 1,
child: Text(
'${category.orderCount}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.black,
),
),
),
],
),
);
}
}
@@ -0,0 +1,616 @@
import 'dart:developer';
import 'package:enaklo_pos/core/constants/colors.dart';
import 'package:enaklo_pos/core/extensions/string_ext.dart';
import 'package:enaklo_pos/core/utils/helper_pdf_service.dart';
import 'package:enaklo_pos/core/utils/inventory_report.dart';
import 'package:enaklo_pos/core/utils/permession_handler.dart';
import 'package:enaklo_pos/data/models/response/inventory_analytic_response_model.dart';
import 'package:flutter/material.dart';
class InventoryReportWidget extends StatefulWidget {
final String title;
final String searchDateFormatted;
final InventoryAnalyticData inventory;
const InventoryReportWidget({
super.key,
required this.title,
required this.searchDateFormatted,
required this.inventory,
});
@override
State<InventoryReportWidget> createState() => _InventoryReportWidgetState();
}
class _InventoryReportWidgetState extends State<InventoryReportWidget> {
int _selectedTabIndex = 0;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
border: Border.all(color: AppColors.stroke, width: 1),
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Report Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColors.light,
border: Border(
bottom: BorderSide(color: AppColors.stroke, width: 1),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
),
const SizedBox(height: 4),
Text(
widget.searchDateFormatted,
style: TextStyle(
fontSize: 12,
color: AppColors.greyDark,
),
),
],
),
Row(
children: [
// Download Button
GestureDetector(
onTap: () async {
try {
final status =
await PermessionHelper().checkPermission();
if (status) {
final pdfFile = await InventoryReport.previewPdf(
searchDateFormatted: widget.searchDateFormatted,
inventory: widget.inventory,
);
log("pdfFile: $pdfFile");
await HelperPdfService.openFile(pdfFile);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Storage permission is required to save PDF'),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
log("Error generating PDF: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to generate PDF: $e'),
backgroundColor: Colors.red,
),
);
}
},
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColors.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border:
Border.all(color: AppColors.primary, width: 1),
),
child: Icon(
Icons.download_outlined,
size: 18,
color: AppColors.primary,
),
),
),
const SizedBox(width: 12),
// Status Badge
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: AppColors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: AppColors.green, width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.check_circle,
size: 14,
color: AppColors.green,
),
const SizedBox(width: 6),
Text(
'Aktif',
style: TextStyle(
fontSize: 12,
color: AppColors.green,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
],
),
),
// Summary Section
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.analytics_outlined,
size: 20,
color: AppColors.primary,
),
const SizedBox(width: 8),
Text(
'Ringkasan Inventori',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColors.black,
),
),
],
),
const SizedBox(height: 16),
// Summary Grid
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
childAspectRatio: 2.2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
children: [
_buildSummaryCard(
'Total Produk',
(widget.inventory.summary.totalProducts).toString(),
AppColors.primary,
Icons.inventory_2_outlined,
),
_buildSummaryCard(
'Total Bahan',
widget.inventory.summary.totalIngredients.toString(),
AppColors.subtitle,
Icons.list_alt_outlined,
),
_buildSummaryCard(
'Total Nilai',
widget.inventory.summary.totalValue
.toString()
.currencyFormatRpV2,
AppColors.green,
Icons.monetization_on_outlined,
),
],
),
],
),
),
// Divider
Container(
height: 1,
margin: const EdgeInsets.symmetric(horizontal: 20),
color: AppColors.stroke,
),
// Tabs
Container(
padding: const EdgeInsets.all(20),
child: Row(
children: [
_buildTab('Produk', 0),
const SizedBox(width: 12),
_buildTab('Bahan Baku', 1),
],
),
),
// Content based on selected tab
_selectedTabIndex == 0
? _buildProductsContent()
: _buildIngredientsContent(),
],
),
),
);
}
Widget _buildSummaryCard(
String title, String value, Color color, IconData icon) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.08),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: color.withOpacity(0.2), width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
),
child: Icon(
icon,
size: 16,
color: color,
),
),
const SizedBox(width: 8),
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 10,
color: AppColors.greyDark,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 6),
Text(
value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: color,
),
),
],
),
);
}
Widget _buildTab(String title, int index) {
bool isActive = _selectedTabIndex == index;
return GestureDetector(
onTap: () {
setState(() {
_selectedTabIndex = index;
});
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(
color: isActive ? AppColors.primary : AppColors.white,
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: isActive ? AppColors.primary : AppColors.stroke,
width: 1,
),
),
child: Text(
title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: isActive ? AppColors.whiteText : AppColors.greyDark,
),
),
),
);
}
Widget _buildProductsContent() {
return Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: AppColors.primary, // Purple color
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
child: Table(
columnWidths: const {
0: FlexColumnWidth(2.5), // Produk
1: FlexColumnWidth(2), // Kategori
2: FlexColumnWidth(1), // Stock
3: FlexColumnWidth(2), // Masuk
4: FlexColumnWidth(2), // Keluar
},
children: [
TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Kategori'),
_buildHeaderCell('Stock'),
_buildHeaderCell('Masuk'),
_buildHeaderCell('Keluar'),
],
),
],
),
),
Container(
decoration: BoxDecoration(
color: AppColors.white,
),
child: Table(
columnWidths: {
0: FlexColumnWidth(2.5), // Produk
1: FlexColumnWidth(2), // Kategori
2: FlexColumnWidth(1), // Stock
3: FlexColumnWidth(2), // Masuk
4: FlexColumnWidth(2), // Keluar
},
children: widget.inventory.products
.map((item) => _buildProductDataRow(
item,
widget.inventory.products.indexOf(item) % 2 == 0,
))
.toList(),
),
),
Container(
decoration: BoxDecoration(
color: AppColors.primary, // Purple color
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
),
child: Table(
columnWidths: const {
0: FlexColumnWidth(2.5), // Produk
1: FlexColumnWidth(2), // Kategori
2: FlexColumnWidth(1), // Stock
3: FlexColumnWidth(2), // Masuk
4: FlexColumnWidth(2), // Keluar
},
children: [
TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(''),
_buildTotalCell(
(widget.inventory.products.fold<num>(
0, (sum, item) => sum + (item.quantity))).toString(),
),
_buildTotalCell(
(widget.inventory.products.fold<num>(
0, (sum, item) => sum + (item.totalIn))).toString(),
),
_buildTotalCell(
(widget.inventory.products.fold<num>(
0, (sum, item) => sum + (item.totalOut))).toString(),
),
],
),
],
),
),
],
),
);
}
Widget _buildIngredientsContent() {
return Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: AppColors.primary, // Purple color
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
child: Table(
columnWidths: const {
0: FlexColumnWidth(2.5), // Name
1: FlexColumnWidth(1), // Stock
2: FlexColumnWidth(2), // Masuk
3: FlexColumnWidth(2), // Keluar
},
children: [
TableRow(
children: [
_buildHeaderCell('Nama'),
_buildHeaderCell('Stock'),
_buildHeaderCell('Masuk'),
_buildHeaderCell('Keluar'),
],
),
],
),
),
Container(
decoration: BoxDecoration(
color: AppColors.white,
),
child: Table(
columnWidths: {
0: FlexColumnWidth(2.5), // Name
1: FlexColumnWidth(1), // Stock
2: FlexColumnWidth(2), // Masuk
3: FlexColumnWidth(2), // Keluar
},
children: widget.inventory.ingredients
.map((item) => _buildIngredientsDataRow(
item,
widget.inventory.ingredients.indexOf(item) % 2 == 0,
))
.toList(),
),
),
Container(
decoration: BoxDecoration(
color: AppColors.primary, // Purple color
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8),
bottomRight: Radius.circular(8),
),
),
child: Table(
columnWidths: const {
0: FlexColumnWidth(2.5), // Name
1: FlexColumnWidth(1), // Stock
2: FlexColumnWidth(2), // Masuk
3: FlexColumnWidth(2), // Keluar
},
children: [
TableRow(
children: [
_buildTotalCell('TOTAL'),
_buildTotalCell(
(widget.inventory.ingredients.fold<num>(
0, (sum, item) => sum + (item.quantity))).toString(),
),
_buildTotalCell(
(widget.inventory.ingredients.fold<num>(
0, (sum, item) => sum + (item.totalIn))).toString(),
),
_buildTotalCell(
(widget.inventory.ingredients.fold<num>(
0, (sum, item) => sum + (item.totalOut))).toString(),
),
],
),
],
),
),
],
),
);
}
TableRow _buildProductDataRow(InventoryProductItem product, bool isEven) {
return TableRow(
decoration: BoxDecoration(
color: product.isZeroStock
? Colors.red.shade100
: product.isLowStock
? Colors.yellow.shade100
: isEven
? Colors.grey.shade50
: AppColors.white,
),
children: [
_buildDataCell(product.productName, alignment: Alignment.centerLeft),
_buildDataCell(product.categoryName, alignment: Alignment.centerLeft),
_buildDataCell(product.quantity.toString()),
_buildDataCell(product.totalIn.toString()),
_buildDataCell(product.totalOut.toString()),
],
);
}
TableRow _buildIngredientsDataRow(InventoryIngredientItem item, bool isEven) {
return TableRow(
decoration: BoxDecoration(
color: item.isZeroStock
? Colors.red.shade100
: item.isLowStock
? Colors.yellow.shade100
: isEven
? Colors.grey.shade50
: AppColors.white,
),
children: [
_buildDataCell(item.ingredientName, alignment: Alignment.centerLeft),
_buildDataCell(item.quantity.toString()),
_buildDataCell(item.totalIn.toString()),
_buildDataCell(item.totalOut.toString()),
],
);
}
Widget _buildHeaderCell(String text) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: Text(
text,
style: TextStyle(
color: AppColors.white,
fontWeight: FontWeight.bold,
fontSize: 12,
),
textAlign: TextAlign.center,
),
);
}
Widget _buildDataCell(String text,
{Alignment alignment = Alignment.center, Color? textColor}) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 16),
alignment: alignment,
child: Text(
text,
style: TextStyle(
fontSize: 12,
color: textColor ?? AppColors.black,
fontWeight: FontWeight.normal,
),
textAlign: alignment == Alignment.centerLeft
? TextAlign.left
: TextAlign.center,
),
);
}
Widget _buildTotalCell(String text) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 16),
child: Text(
text,
style: TextStyle(
color: AppColors.white,
fontWeight: FontWeight.bold,
fontSize: 12,
),
textAlign: TextAlign.center,
),
);
}
}
@@ -73,26 +73,28 @@ class ProfitLossWidget extends StatelessWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( children: [
title, Text(
style: TextStyle( title,
fontSize: 18, style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18,
color: Color(0xFF0F172A), fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
), ),
), const SizedBox(height: 6),
const SizedBox(height: 6), Text(
Text( 'Analisis profitabilitas dan margin keuntungan',
'Analisis profitabilitas dan margin keuntungan', style: TextStyle(
style: TextStyle( fontSize: 14,
fontSize: 14, color: Colors.grey[600],
color: Colors.grey[600], ),
), ),
), ],
], ),
), ),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
@@ -628,7 +630,7 @@ class ProfitLossWidget extends StatelessWidget {
); );
} }
Widget _buildProductMetric(String label, int value, Color color) { Widget _buildProductMetric(String label, num value, Color color) {
return Container( return Container(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -722,7 +724,7 @@ class ProfitLossWidget extends StatelessWidget {
sections: breakdownData.asMap().entries.map((entry) { sections: breakdownData.asMap().entries.map((entry) {
final item = entry.value; final item = entry.value;
final grossProfit = data.summary.grossProfit; final grossProfit = data.summary.grossProfit;
final value = item['value'] as int; final value = item['value'] as num;
// Handle division by zero // Handle division by zero
final percentage = final percentage =
@@ -772,7 +774,7 @@ class ProfitLossWidget extends StatelessWidget {
), ),
), ),
Text( Text(
_formatCurrency(item['value'] as int), _formatCurrency(item['value'] as num),
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -873,7 +875,7 @@ class ProfitLossWidget extends StatelessWidget {
Expanded( Expanded(
child: _buildMetricCard( child: _buildMetricCard(
'Keuntungan Rata-rata', 'Keuntungan Rata-rata',
_formatCurrency(data.summary.averageProfit), "${data.summary.averageProfit.round()}%",
'Per pesanan', 'Per pesanan',
Icons.trending_up, Icons.trending_up,
AppColorProfitLoss.success, AppColorProfitLoss.success,
@@ -1154,7 +1156,7 @@ class ProfitLossWidget extends StatelessWidget {
return AppColorProfitLoss.danger; return AppColorProfitLoss.danger;
} }
String _formatCurrency(int amount) { String _formatCurrency(num amount) {
final formatter = NumberFormat.currency( final formatter = NumberFormat.currency(
locale: 'id_ID', locale: 'id_ID',
symbol: 'Rp ', symbol: 'Rp ',
@@ -1163,7 +1165,7 @@ class ProfitLossWidget extends StatelessWidget {
return formatter.format(amount); return formatter.format(amount);
} }
String _formatCurrencyShort(int amount) { String _formatCurrencyShort(num amount) {
if (amount >= 1000000) { if (amount >= 1000000) {
return 'Rp ${(amount / 1000000).round()}M'; return 'Rp ${(amount / 1000000).round()}M';
} else if (amount >= 1000) { } else if (amount >= 1000) {
@@ -1,12 +1,13 @@
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:enaklo_pos/core/extensions/date_time_ext.dart';
import '../../../core/constants/colors.dart'; import '../../../core/constants/colors.dart';
class ReportTitle extends StatelessWidget { class ReportTitle extends StatelessWidget {
final List<Widget>? actionWidget; final List<Widget>? actionWidget;
const ReportTitle({super.key, this.actionWidget}); final String searchDateFormatted;
const ReportTitle(
{super.key, this.actionWidget, required this.searchDateFormatted});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -16,7 +17,7 @@ class ReportTitle extends StatelessWidget {
vertical: 10.0, vertical: 10.0,
), ),
width: double.infinity, width: double.infinity,
height: context.deviceHeight * 0.1, height: context.deviceHeight * 0.13,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: AppColors.white, color: AppColors.white,
border: Border( border: Border(
@@ -41,7 +42,7 @@ class ReportTitle extends StatelessWidget {
), ),
), ),
Text( Text(
DateTime.now().toFormattedDate2(), searchDateFormatted,
style: TextStyle( style: TextStyle(
color: AppColors.grey, color: AppColors.grey,
fontSize: 14, fontSize: 14,
@@ -51,6 +52,8 @@ class ReportTitle extends StatelessWidget {
), ),
if (actionWidget != null) if (actionWidget != null)
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: actionWidget!, children: actionWidget!,
), ),
], ],
+43 -10
View File
@@ -1,6 +1,7 @@
import 'package:enaklo_pos/core/components/buttons.dart'; import 'package:enaklo_pos/core/components/buttons.dart';
import 'package:enaklo_pos/core/components/spaces.dart'; import 'package:enaklo_pos/core/components/spaces.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/core/function/app_function.dart';
import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart';
import 'package:enaklo_pos/presentation/home/bloc/order_form/order_form_bloc.dart'; import 'package:enaklo_pos/presentation/home/bloc/order_form/order_form_bloc.dart';
import 'package:enaklo_pos/presentation/payment/pages/payment_page.dart'; import 'package:enaklo_pos/presentation/payment/pages/payment_page.dart';
@@ -98,8 +99,8 @@ class _SalesPageState extends State<SalesPage> {
}, },
onDateRangeChanged: (start, end) { onDateRangeChanged: (start, end) {
setState(() { setState(() {
startDate = start; startDate = start ?? startDate;
endDate = end; endDate = end ?? endDate;
}); });
context.read<OrderLoaderBloc>().add( context.read<OrderLoaderBloc>().add(
@@ -246,15 +247,47 @@ class _SalesPageState extends State<SalesPage> {
), ),
], ],
if (widget.status == 'completed') if (widget.status == 'completed')
Button.outlined( if (orderDetail?.isRefund == false)
onPressed: () { Button.outlined(
context.push(RefundPage( onPressed: () {
selectedOrder: orderDetail!, context.push(RefundPage(
)); selectedOrder: orderDetail!,
}, ));
label: 'Refund', },
icon: Icon(Icons.autorenew), label: 'Refund',
icon: Icon(Icons.autorenew),
),
SpaceWidth(8),
Button.outlined(
onPressed: () {
if (widget.status == 'completed') {
onPrintRecipt(
context,
order: orderDetail!,
paymentMethod: orderDetail!.payments
?.map((p) => p.paymentMethodName)
.join(', ') ??
"",
nominalBayar: orderDetail?.totalPaid ?? 0,
kembalian: 0,
productQuantity: orderDetail!.orderItems!
.toProductQuantities(),
);
} else {
onPrint(
context,
productQuantity: orderDetail!.orderItems!
.toProductQuantities(),
order: orderDetail!,
);
}
},
label: 'Print',
icon: Icon(
Icons.print,
), ),
),
SpaceWidth(8),
], ],
), ),
Expanded( Expanded(
@@ -1,9 +1,9 @@
import 'package:enaklo_pos/core/components/components.dart'; import 'package:enaklo_pos/core/components/components.dart';
import 'package:enaklo_pos/core/components/date_range_picker.dart';
import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/constants/colors.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart';
import 'package:enaklo_pos/presentation/sales/blocs/order_loader/order_loader_bloc.dart'; import 'package:enaklo_pos/presentation/sales/blocs/order_loader/order_loader_bloc.dart';
import 'package:enaklo_pos/presentation/sales/dialog/filter_dialog.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';
@@ -12,7 +12,7 @@ class SalesTitle extends StatelessWidget {
final DateTime startDate; final DateTime startDate;
final DateTime endDate; final DateTime endDate;
final Function(String) onChanged; final Function(String) onChanged;
final void Function(DateTime start, DateTime end) onDateRangeChanged; final void Function(DateTime? start, DateTime? end) onDateRangeChanged;
const SalesTitle( const SalesTitle(
{super.key, {super.key,
@@ -119,13 +119,12 @@ class SalesTitle extends StatelessWidget {
), ),
SpaceWidth(12), SpaceWidth(12),
GestureDetector( GestureDetector(
onTap: () => showDialog( onTap: () => DateRangePickerModal.show(
context: context, context: context,
builder: (context) => SalesFilterDialog( initialStartDate: startDate,
startDate: startDate, initialEndDate: endDate,
endDate: endDate, primaryColor: AppColors.primary,
onDateRangeChanged: onDateRangeChanged, onChanged: onDateRangeChanged,
),
), ),
child: Container( child: Container(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
@@ -41,7 +41,7 @@ class _SettingPageState extends State<SettingPage> {
vertical: 12.0, vertical: 12.0,
), ),
width: double.infinity, width: double.infinity,
height: context.deviceHeight * 0.1, height: context.deviceHeight * 0.12,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: AppColors.white, color: AppColors.white,
border: Border( border: Border(
@@ -63,7 +63,7 @@ class _SettingsPageState extends State<SettingsPage> {
vertical: 12.0, vertical: 12.0,
), ),
width: double.infinity, width: double.infinity,
height: context.deviceHeight * 0.1, height: context.deviceHeight * 0.12,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: AppColors.white, color: AppColors.white,
border: Border( border: Border(
@@ -22,23 +22,22 @@ class BarPrinterPage extends StatefulWidget {
class _BarPrinterPageState extends State<BarPrinterPage> { class _BarPrinterPageState extends State<BarPrinterPage> {
String selectedPrinter = 'Bluetooth'; String selectedPrinter = 'Bluetooth';
TextEditingController? addressController; TextEditingController addressController = TextEditingController();
TextEditingController? printNameController; TextEditingController printNameController = TextEditingController();
String paper = '58'; String paper = '58';
bool isInitialized = false; bool isInitialized = false;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
addressController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) {
printNameController = TextEditingController(); context.read<GetPrinterBarBloc>().add(GetPrinterBarEvent.get());
context.read<GetPrinterBarBloc>().add(GetPrinterBarEvent.get()); });
} }
@override @override
void dispose() { void dispose() {
addressController!.dispose(); addressController.dispose();
printNameController!.dispose(); printNameController.dispose();
super.dispose(); super.dispose();
} }
@@ -57,8 +56,8 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
}, },
success: (data) { success: (data) {
if (data != null && !isInitialized) { if (data != null && !isInitialized) {
addressController!.text = data.address; addressController.text = data.address;
printNameController!.text = data.name; printNameController.text = data.name;
selectedPrinter = data.type; selectedPrinter = data.type;
paper = data.paper; paper = data.paper;
isInitialized = true; isInitialized = true;
@@ -112,7 +111,7 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
context: context, context: context,
builder: (context) => DialogSearchPrinter( builder: (context) => DialogSearchPrinter(
onSelected: (value) { onSelected: (value) {
addressController!.text = value; addressController.text = value;
setState(() {}); setState(() {});
}, },
), ),
@@ -120,14 +119,14 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
}, },
label: 'Search') label: 'Search')
: CustomTextField( : CustomTextField(
controller: addressController!, controller: addressController,
label: 'Address', label: 'Address',
showLabel: false, showLabel: false,
), ),
SpaceHeight(16), SpaceHeight(16),
// Textfield for name // Textfield for name
CustomTextField( CustomTextField(
controller: printNameController!, controller: printNameController,
label: 'Print Name', label: 'Print Name',
showLabel: false, showLabel: false,
), ),
@@ -160,48 +159,53 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
SpaceHeight(16), SpaceHeight(16),
// button test print // button test print
Button.outlined( Button.outlined(
onPressed: () async { onPressed: () async {
if (addressController!.text.isNotEmpty && printNameController!.text.isNotEmpty) { if (addressController.text.isNotEmpty &&
try { printNameController.text.isNotEmpty) {
// Create a test print model try {
final testPrinter = PrintModel( // Create a test print model
code: 'bar', final testPrinter = PrintModel(
name: printNameController!.text, code: 'bar',
address: addressController!.text, name: printNameController.text,
paper: paper, address: addressController.text,
type: selectedPrinter, paper: paper,
); type: selectedPrinter,
);
// Generate test print data
final testPrintData = await PrintDataoutputs.instance.printBar( // Generate test print data
[], // Empty product list for test final testPrintData =
'Test Table', await PrintDataoutputs.instance.printBar(
'Test Order', [], // Empty product list for test
'Test Cashier', 'Test Table',
int.parse(paper), 'Test Order',
'DINE IN', 'Test Cashier',
); 'Test Customer',
int.parse(paper),
// Print test 'DINE IN',
await PrinterService().printWithPrinter( );
testPrinter,
testPrintData, // Print test
context, await PrinterService().printWithPrinter(
); testPrinter,
} catch (e) { testPrintData,
log("Error test printing: $e"); context,
);
} catch (e) {
log("Error test printing: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error test printing: $e')),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error test printing: $e')), SnackBar(
content: Text(
'Please fill in printer details first')),
); );
} }
} else { },
ScaffoldMessenger.of(context).showSnackBar( label: 'Test Print'),
SnackBar(content: Text('Please fill in printer details first')),
);
}
},
label: 'Test Print'
),
SpaceHeight(8), SpaceHeight(8),
// button save // button save
data == null data == null
@@ -229,8 +233,8 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
onPressed: () { onPressed: () {
final printData = PrintModel( final printData = PrintModel(
code: 'bar', code: 'bar',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -274,8 +278,8 @@ class _BarPrinterPageState extends State<BarPrinterPage> {
final printData = PrintModel( final printData = PrintModel(
id: data.id, id: data.id,
code: 'bar', code: 'bar',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -22,23 +22,22 @@ class CheckerPrinterPage extends StatefulWidget {
class _CheckerPrinterPageState extends State<CheckerPrinterPage> { class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
String selectedPrinter = 'Bluetooth'; String selectedPrinter = 'Bluetooth';
TextEditingController? addressController; TextEditingController addressController = TextEditingController();
TextEditingController? printNameController; TextEditingController printNameController = TextEditingController();
String paper = '58'; String paper = '58';
bool isInitialized = false; bool isInitialized = false;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
addressController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) {
printNameController = TextEditingController(); context.read<GetPrinterCheckerBloc>().add(GetPrinterCheckerEvent.get());
context.read<GetPrinterCheckerBloc>().add(GetPrinterCheckerEvent.get()); });
} }
@override @override
void dispose() { void dispose() {
addressController!.dispose(); addressController.dispose();
printNameController!.dispose(); printNameController.dispose();
isInitialized = false; isInitialized = false;
super.dispose(); super.dispose();
} }
@@ -59,8 +58,8 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
success: (data) { success: (data) {
log("Checker Printer: ${data?.toMap()}"); log("Checker Printer: ${data?.toMap()}");
if (data != null && !isInitialized) { if (data != null && !isInitialized) {
addressController!.text = data.address; addressController.text = data.address;
printNameController!.text = data.name; printNameController.text = data.name;
selectedPrinter = data.type; selectedPrinter = data.type;
paper = data.paper; paper = data.paper;
isInitialized = true; isInitialized = true;
@@ -114,7 +113,7 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
context: context, context: context,
builder: (context) => DialogSearchPrinter( builder: (context) => DialogSearchPrinter(
onSelected: (value) { onSelected: (value) {
addressController!.text = value; addressController.text = value;
setState(() {}); setState(() {});
}, },
), ),
@@ -122,14 +121,14 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
}, },
label: 'Search') label: 'Search')
: CustomTextField( : CustomTextField(
controller: addressController!, controller: addressController,
label: 'Address', label: 'Address',
showLabel: false, showLabel: false,
), ),
SpaceHeight(16), SpaceHeight(16),
// Textfield for name // Textfield for name
CustomTextField( CustomTextField(
controller: printNameController!, controller: printNameController,
label: 'Print Name', label: 'Print Name',
showLabel: false, showLabel: false,
), ),
@@ -162,48 +161,54 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
SpaceHeight(16), SpaceHeight(16),
// button test print // button test print
Button.outlined( Button.outlined(
onPressed: () async { onPressed: () async {
if (addressController!.text.isNotEmpty && printNameController!.text.isNotEmpty) { if (addressController.text.isNotEmpty &&
try { printNameController.text.isNotEmpty) {
// Create a test print model try {
final testPrinter = PrintModel( // Create a test print model
code: 'checker', final testPrinter = PrintModel(
name: printNameController!.text, code: 'checker',
address: addressController!.text, name: printNameController.text,
paper: paper, address: addressController.text,
type: selectedPrinter, paper: paper,
); type: selectedPrinter,
);
// Generate test print data
final testPrintData = await PrintDataoutputs.instance.printChecker( // Generate test print data
[], // Empty product list for test final testPrintData = await PrintDataoutputs
'Test Table', .instance
'Test Order', .printChecker(
'Test Cashier', [], // Empty product list for test
int.parse(paper), 'Test Table',
'DINE IN', 'Test Order',
); 'Test Cashier',
'Test Customer',
// Print test int.parse(paper),
await PrinterService().printWithPrinter( 'DINE IN',
testPrinter, );
testPrintData,
context, // Print test
); await PrinterService().printWithPrinter(
} catch (e) { testPrinter,
log("Error test printing: $e"); testPrintData,
context,
);
} catch (e) {
log("Error test printing: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error test printing: $e')),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error test printing: $e')), SnackBar(
content: Text(
'Please fill in printer details first')),
); );
} }
} else { },
ScaffoldMessenger.of(context).showSnackBar( label: 'Test Print'),
SnackBar(content: Text('Please fill in printer details first')),
);
}
},
label: 'Test Print'
),
SpaceHeight(8), SpaceHeight(8),
// button save // button save
data == null data == null
@@ -231,8 +236,8 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
onPressed: () { onPressed: () {
final printData = PrintModel( final printData = PrintModel(
code: 'checker', code: 'checker',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -276,8 +281,8 @@ class _CheckerPrinterPageState extends State<CheckerPrinterPage> {
final printData = PrintModel( final printData = PrintModel(
id: data.id, id: data.id,
code: 'checker', code: 'checker',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -22,23 +22,22 @@ class KitchenPrinterPage extends StatefulWidget {
class _KitchenPrinterPageState extends State<KitchenPrinterPage> { class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
String selectedPrinter = 'Bluetooth'; String selectedPrinter = 'Bluetooth';
TextEditingController? addressController; TextEditingController addressController = TextEditingController();
TextEditingController? printNameController; TextEditingController printNameController = TextEditingController();
String paper = '58'; String paper = '58';
bool isInitialized = false; bool isInitialized = false;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
addressController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) {
printNameController = TextEditingController(); context.read<GetPrinterKitchenBloc>().add(GetPrinterKitchenEvent.get());
context.read<GetPrinterKitchenBloc>().add(GetPrinterKitchenEvent.get()); });
} }
@override @override
void dispose() { void dispose() {
addressController!.dispose(); addressController.dispose();
printNameController!.dispose(); printNameController.dispose();
super.dispose(); super.dispose();
} }
@@ -57,8 +56,8 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
}, },
success: (data) { success: (data) {
if (data != null && !isInitialized) { if (data != null && !isInitialized) {
addressController!.text = data.address; addressController.text = data.address;
printNameController!.text = data.name; printNameController.text = data.name;
selectedPrinter = data.type; selectedPrinter = data.type;
paper = data.paper; paper = data.paper;
isInitialized = true; isInitialized = true;
@@ -112,7 +111,7 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
context: context, context: context,
builder: (context) => DialogSearchPrinter( builder: (context) => DialogSearchPrinter(
onSelected: (value) { onSelected: (value) {
addressController!.text = value; addressController.text = value;
setState(() {}); setState(() {});
}, },
), ),
@@ -120,14 +119,14 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
}, },
label: 'Search') label: 'Search')
: CustomTextField( : CustomTextField(
controller: addressController!, controller: addressController,
label: 'Address', label: 'Address',
showLabel: false, showLabel: false,
), ),
SpaceHeight(16), SpaceHeight(16),
// Textfield for name // Textfield for name
CustomTextField( CustomTextField(
controller: printNameController!, controller: printNameController,
label: 'Print Name', label: 'Print Name',
showLabel: false, showLabel: false,
), ),
@@ -160,48 +159,54 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
SpaceHeight(16), SpaceHeight(16),
// button test print // button test print
Button.outlined( Button.outlined(
onPressed: () async { onPressed: () async {
if (addressController!.text.isNotEmpty && printNameController!.text.isNotEmpty) { if (addressController.text.isNotEmpty &&
try { printNameController.text.isNotEmpty) {
// Create a test print model try {
final testPrinter = PrintModel( // Create a test print model
code: 'kitchen', final testPrinter = PrintModel(
name: printNameController!.text, code: 'kitchen',
address: addressController!.text, name: printNameController.text,
paper: paper, address: addressController.text,
type: selectedPrinter, paper: paper,
); type: selectedPrinter,
);
// Generate test print data
final testPrintData = await PrintDataoutputs.instance.printKitchen( // Generate test print data
[], // Empty product list for test final testPrintData = await PrintDataoutputs
'Test Table', .instance
'Test Order', .printKitchen(
'Test Cashier', [], // Empty product list for test
int.parse(paper), 'Test Table',
'DINE IN', 'Test Order',
); 'Test Cashier',
'Test Customer',
// Print test int.parse(paper),
await PrinterService().printWithPrinter( 'DINE IN',
testPrinter, );
testPrintData,
context, // Print test
); await PrinterService().printWithPrinter(
} catch (e) { testPrinter,
log("Error test printing: $e"); testPrintData,
context,
);
} catch (e) {
log("Error test printing: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error test printing: $e')),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error test printing: $e')), SnackBar(
content: Text(
'Please fill in printer details first')),
); );
} }
} else { },
ScaffoldMessenger.of(context).showSnackBar( label: 'Test Print'),
SnackBar(content: Text('Please fill in printer details first')),
);
}
},
label: 'Test Print'
),
SpaceHeight(8), SpaceHeight(8),
// button save // button save
data == null data == null
@@ -229,8 +234,8 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
onPressed: () { onPressed: () {
final printData = PrintModel( final printData = PrintModel(
code: 'kitchen', code: 'kitchen',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -274,8 +279,8 @@ class _KitchenPrinterPageState extends State<KitchenPrinterPage> {
final printData = PrintModel( final printData = PrintModel(
id: data.id, id: data.id,
code: 'kitchen', code: 'kitchen',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -23,23 +23,22 @@ class ReceiptPrinterPage extends StatefulWidget {
class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> { class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
String selectedPrinter = 'Bluetooth'; String selectedPrinter = 'Bluetooth';
TextEditingController? addressController; TextEditingController addressController = TextEditingController();
TextEditingController? printNameController; TextEditingController printNameController = TextEditingController();
String paper = '58'; String paper = '58';
bool isInitialized = false; bool isInitialized = false;
@override @override
void initState() { void initState() {
// TODO: implement initState
super.initState(); super.initState();
addressController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) {
printNameController = TextEditingController(); context.read<GetPrinterReceiptBloc>().add(GetPrinterReceiptEvent.get());
context.read<GetPrinterReceiptBloc>().add(GetPrinterReceiptEvent.get()); });
} }
@override @override
void dispose() { void dispose() {
addressController!.dispose(); addressController.dispose();
printNameController!.dispose(); printNameController.dispose();
super.dispose(); super.dispose();
} }
@@ -58,8 +57,8 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
}, },
success: (data) { success: (data) {
if (data != null && !isInitialized) { if (data != null && !isInitialized) {
addressController!.text = data.address; addressController.text = data.address;
printNameController!.text = data.name; printNameController.text = data.name;
selectedPrinter = data.type; selectedPrinter = data.type;
paper = data.paper; paper = data.paper;
isInitialized = true; isInitialized = true;
@@ -113,7 +112,7 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
context: context, context: context,
builder: (context) => DialogSearchPrinter( builder: (context) => DialogSearchPrinter(
onSelected: (value) { onSelected: (value) {
addressController!.text = value; addressController.text = value;
setState(() {}); setState(() {});
}, },
), ),
@@ -121,14 +120,14 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
}, },
label: 'Search') label: 'Search')
: CustomTextField( : CustomTextField(
controller: addressController!, controller: addressController,
label: 'Address', label: 'Address',
showLabel: false, showLabel: false,
), ),
SpaceHeight(16), SpaceHeight(16),
// Textfield for name // Textfield for name
CustomTextField( CustomTextField(
controller: printNameController!, controller: printNameController,
label: 'Print Name', label: 'Print Name',
showLabel: false, showLabel: false,
), ),
@@ -162,8 +161,8 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
// button test print // button test print
Button.outlined( Button.outlined(
onPressed: () async { onPressed: () async {
if (addressController!.text.isNotEmpty && if (addressController.text.isNotEmpty &&
printNameController!.text.isNotEmpty) { printNameController.text.isNotEmpty) {
try { try {
// Get actual tax and service charge settings // Get actual tax and service charge settings
final settingsLocalDatasource = final settingsLocalDatasource =
@@ -177,8 +176,8 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
// Create a test print model // Create a test print model
final testPrinter = PrintModel( final testPrinter = PrintModel(
code: 'receipt', code: 'receipt',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -253,8 +252,8 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
onPressed: () { onPressed: () {
final printData = PrintModel( final printData = PrintModel(
code: 'receipt', code: 'receipt',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -298,8 +297,8 @@ class _ReceiptPrinterPageState extends State<ReceiptPrinterPage> {
final printData = PrintModel( final printData = PrintModel(
id: data.id, id: data.id,
code: 'receipt', code: 'receipt',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -23,7 +23,7 @@ class SettingsTitle extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: context.deviceHeight * 0.1, height: context.deviceHeight * 0.12,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.white, color: AppColors.white,
@@ -23,22 +23,23 @@ class TicketPrinterPage extends StatefulWidget {
class _TicketPrinterPageState extends State<TicketPrinterPage> { class _TicketPrinterPageState extends State<TicketPrinterPage> {
String selectedPrinter = 'Bluetooth'; String selectedPrinter = 'Bluetooth';
TextEditingController? addressController; TextEditingController addressController = TextEditingController();
TextEditingController? printNameController; TextEditingController printNameController = TextEditingController();
String paper = '58'; String paper = '58';
bool isInitialized = false; bool isInitialized = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
addressController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) {
printNameController = TextEditingController(); context.read<GetPrinterTicketBloc>().add(GetPrinterTicketEvent.get());
context.read<GetPrinterTicketBloc>().add(GetPrinterTicketEvent.get()); });
} }
@override @override
void dispose() { void dispose() {
addressController!.dispose(); addressController.dispose();
printNameController!.dispose(); printNameController.dispose();
super.dispose(); super.dispose();
} }
@@ -57,8 +58,8 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
}, },
success: (data) { success: (data) {
if (data != null && !isInitialized) { if (data != null && !isInitialized) {
addressController!.text = data.address; addressController.text = data.address;
printNameController!.text = data.name; printNameController.text = data.name;
selectedPrinter = data.type; selectedPrinter = data.type;
paper = data.paper; paper = data.paper;
isInitialized = true; isInitialized = true;
@@ -112,7 +113,7 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
context: context, context: context,
builder: (context) => DialogSearchPrinter( builder: (context) => DialogSearchPrinter(
onSelected: (value) { onSelected: (value) {
addressController!.text = value; addressController.text = value;
setState(() {}); setState(() {});
}, },
), ),
@@ -120,14 +121,14 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
}, },
label: 'Search') label: 'Search')
: CustomTextField( : CustomTextField(
controller: addressController!, controller: addressController,
label: 'Address', label: 'Address',
showLabel: false, showLabel: false,
), ),
SpaceHeight(16), SpaceHeight(16),
// Textfield for name // Textfield for name
CustomTextField( CustomTextField(
controller: printNameController!, controller: printNameController,
label: 'Print Name', label: 'Print Name',
showLabel: false, showLabel: false,
), ),
@@ -161,14 +162,14 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
// button test print // button test print
Button.outlined( Button.outlined(
onPressed: () async { onPressed: () async {
if (addressController!.text.isNotEmpty && if (addressController.text.isNotEmpty &&
printNameController!.text.isNotEmpty) { printNameController.text.isNotEmpty) {
try { try {
// Create a test print model // Create a test print model
final testPrinter = PrintModel( final testPrinter = PrintModel(
code: 'ticket', code: 'ticket',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -231,8 +232,8 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
onPressed: () { onPressed: () {
final printData = PrintModel( final printData = PrintModel(
code: 'ticket', code: 'ticket',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -276,8 +277,8 @@ class _TicketPrinterPageState extends State<TicketPrinterPage> {
final printData = PrintModel( final printData = PrintModel(
id: data.id, id: data.id,
code: 'ticket', code: 'ticket',
name: printNameController!.text, name: printNameController.text,
address: addressController!.text, address: addressController.text,
paper: paper, paper: paper,
type: selectedPrinter, type: selectedPrinter,
); );
@@ -932,7 +932,7 @@ class _SplitBillPageState extends State<SplitBillPage> {
Order splitOrder = Order( Order splitOrder = Order(
id: widget.order.id, id: widget.order.id,
orderNumber: widget.order.orderNumber, orderNumber: widget.order.orderNumber,
orderItems: getOrderItemPending(), // Keep all items for reference orderItems: [], // Keep all items for reference
subtotal: splitAmount, subtotal: splitAmount,
totalAmount: splitAmount, totalAmount: splitAmount,
taxAmount: 0, // You might want to calculate proportional values taxAmount: 0, // You might want to calculate proportional values
File diff suppressed because it is too large Load Diff
@@ -108,141 +108,144 @@ class _SuccessPaymentPageState extends State<SuccessPaymentPage> {
child: Column( child: Column(
children: [ children: [
// Success Header // Success Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(32.0),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColors.primary.withOpacity(0.1),
AppColors.primary.withOpacity(0.05),
],
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(24),
),
),
child: Column(
children: [
// Success Icon
Container(
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColors.primary,
AppColors.primary.withOpacity(0.8),
],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColors.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: const Icon(
Icons.check_rounded,
size: 48,
color: Colors.white,
),
),
const SizedBox(height: 24),
// Success Title
const Text(
'Pesanan Berhasil!',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'Pesanan telah diterima dan sedang diproses',
style: TextStyle(
fontSize: 14,
color: AppColors.primary,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
],
),
),
// Order Information Section
Expanded( Expanded(
child: Padding( child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildSectionTitle('Informasi Pesanan'), Container(
const SizedBox(height: 24), width: double.infinity,
padding: const EdgeInsets.all(32.0),
// Customer Card decoration: BoxDecoration(
_buildInfoCard( gradient: LinearGradient(
icon: Icons.person_outline_rounded, begin: Alignment.topLeft,
title: 'Nama Pelanggan', end: Alignment.bottomRight,
value: order.metadata?['customer_name'] ?? "-", colors: [
gradient: [ AppColors.primary.withOpacity(0.1),
Colors.blue.withOpacity(0.1), AppColors.primary.withOpacity(0.05),
Colors.purple.withOpacity(0.1), ],
], ),
), borderRadius: const BorderRadius.vertical(
top: Radius.circular(24),
const SizedBox(height: 16), ),
),
// Order Details
Expanded(
child: Column( child: Column(
children: [ children: [
_buildInfoRow( // Success Icon
icon: Icons.receipt_long_outlined, Container(
label: 'No. Pesanan', padding: const EdgeInsets.all(20.0),
value: order.orderNumber ?? "-", decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
AppColors.primary,
AppColors.primary.withOpacity(0.8),
],
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColors.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: const Icon(
Icons.check_rounded,
size: 48,
color: Colors.white,
),
), ),
const SizedBox(height: 12),
_buildInfoRow( const SizedBox(height: 24),
icon: Icons.table_restaurant_outlined,
label: 'No. Meja', // Success Title
value: order.tableNumber ?? "-", const Text(
'Pesanan Berhasil!',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildInfoRow(
icon: Icons.access_time_rounded, Container(
label: 'Waktu', padding: const EdgeInsets.symmetric(
value: (order.createdAt ?? DateTime.now()) horizontal: 16,
.toFormattedDate3(), vertical: 8,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'Pesanan telah diterima dan sedang diproses',
style: TextStyle(
fontSize: 14,
color: AppColors.primary,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
), ),
const SizedBox(height: 12), ],
_buildInfoRow( ),
icon: Icons.check_circle_outline, ),
label: 'Status Pembayaran', // Order Information Section
value: 'Lunas', Padding(
valueColor: Colors.green, padding: const EdgeInsets.all(24.0),
showBadge: true, child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('Informasi Pesanan'),
const SizedBox(height: 24),
// Customer Card
_buildInfoCard(
icon: Icons.person_outline_rounded,
title: 'Nama Pelanggan',
value: order.metadata?['customer_name'] ?? "-",
gradient: [
Colors.blue.withOpacity(0.1),
Colors.purple.withOpacity(0.1),
],
),
const SizedBox(height: 16),
// Order Details
Column(
children: [
_buildInfoRow(
icon: Icons.receipt_long_outlined,
label: 'No. Pesanan',
value: order.orderNumber ?? "-",
),
const SizedBox(height: 12),
_buildInfoRow(
icon: Icons.receipt_long_outlined,
label: 'Metode Pembayaran',
value: widget.paymentMethod,
),
const SizedBox(height: 12),
_buildInfoRow(
icon: Icons.access_time_rounded,
label: 'Waktu',
value: (order.createdAt ?? DateTime.now())
.toFormattedDate3(),
),
const SizedBox(height: 12),
_buildInfoRow(
icon: Icons.check_circle_outline,
label: 'Status Pembayaran',
value: 'Lunas',
valueColor: Colors.green,
showBadge: true,
),
],
), ),
], ],
), ),
@@ -798,6 +801,7 @@ class _SuccessPaymentPageState extends State<SuccessPaymentPage> {
: order.totalAmount ?? 0, : order.totalAmount ?? 0,
kembalian: kembalian:
widget.nominalBayar - (order.totalAmount ?? 0), widget.nominalBayar - (order.totalAmount ?? 0),
productQuantity: widget.productQuantity,
); );
}, },
child: const Row( child: const Row(
+14 -2
View File
@@ -1,7 +1,10 @@
import 'dart:developer';
import 'package:enaklo_pos/core/components/flushbar.dart'; import 'package:enaklo_pos/core/components/flushbar.dart';
import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/constants/colors.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/data/models/response/table_model.dart'; import 'package:enaklo_pos/data/models/response/table_model.dart';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart'; import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart';
import 'package:enaklo_pos/presentation/table/blocs/change_position_table/change_position_table_bloc.dart'; import 'package:enaklo_pos/presentation/table/blocs/change_position_table/change_position_table_bloc.dart';
import 'package:enaklo_pos/presentation/table/blocs/create_table/create_table_bloc.dart'; import 'package:enaklo_pos/presentation/table/blocs/create_table/create_table_bloc.dart';
@@ -32,7 +35,8 @@ TableStatus parseStatus(String? status) {
} }
class TablePage extends StatefulWidget { class TablePage extends StatefulWidget {
const TablePage({super.key}); final List<ProductQuantity>? items;
const TablePage({super.key, this.items});
@override @override
State<TablePage> createState() => _TablePageState(); State<TablePage> createState() => _TablePageState();
@@ -61,6 +65,7 @@ class _TablePageState extends State<TablePage> {
@override @override
void initState() { void initState() {
log("ITEM COUNT: ${widget.items?.length}");
context.read<GetTableBloc>().add(const GetTableEvent.getTables()); context.read<GetTableBloc>().add(const GetTableEvent.getTables());
super.initState(); super.initState();
} }
@@ -74,6 +79,12 @@ class _TablePageState extends State<TablePage> {
appBar: AppBar( appBar: AppBar(
title: const Text("Layout Meja"), title: const Text("Layout Meja"),
actions: [ actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
context.read<GetTableBloc>().add(const GetTableEvent.getTables());
},
),
BlocListener<CreateTableBloc, CreateTableState>( BlocListener<CreateTableBloc, CreateTableState>(
listener: (context, state) { listener: (context, state) {
state.maybeWhen( state.maybeWhen(
@@ -391,8 +402,9 @@ class _TablePageState extends State<TablePage> {
), ),
onPressed: () { onPressed: () {
if (selectedTable?.status == 'available') { if (selectedTable?.status == 'available') {
context.push(DashboardPage( context.pushReplacement(DashboardPage(
table: selectedTable!, table: selectedTable!,
items: widget.items,
)); ));
} else {} } else {}
}, },
@@ -1,5 +1,6 @@
import 'dart:developer'; import 'dart:developer';
import 'package:enaklo_pos/presentation/home/models/product_quantity.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:enaklo_pos/core/components/components.dart'; import 'package:enaklo_pos/core/components/components.dart';
@@ -15,13 +16,15 @@ import 'package:enaklo_pos/presentation/home/bloc/status_table/status_table_bloc
import 'package:enaklo_pos/presentation/home/pages/home_page.dart'; import 'package:enaklo_pos/presentation/home/pages/home_page.dart';
import 'package:enaklo_pos/presentation/table/blocs/get_table/get_table_bloc.dart'; import 'package:enaklo_pos/presentation/table/blocs/get_table/get_table_bloc.dart';
import 'package:enaklo_pos/presentation/table/models/draft_order_model.dart'; import 'package:enaklo_pos/presentation/table/models/draft_order_model.dart';
import 'package:enaklo_pos/presentation/table/pages/payment_table_page.dart'; import 'package:enaklo_pos/presentation/table/pages/payment_table_page.dart.old';
class CardTableWidget extends StatefulWidget { class CardTableWidget extends StatefulWidget {
final TableModel table; final TableModel table;
final List<ProductQuantity> items;
const CardTableWidget({ const CardTableWidget({
super.key, super.key,
required this.table, required this.table,
required this.items,
}); });
@override @override
@@ -89,6 +92,7 @@ class _CardTableWidgetState extends State<CardTableWidget> {
context.push(HomePage( context.push(HomePage(
isTable: true, isTable: true,
table: widget.table, table: widget.table,
items: widget.items,
)); ));
} else { } else {
context.read<CheckoutBloc>().add( context.read<CheckoutBloc>().add(
@@ -3,6 +3,7 @@ import 'package:enaklo_pos/core/components/spaces.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart';
import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart';
import 'package:enaklo_pos/core/function/app_function.dart';
import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart'; import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart';
import 'package:enaklo_pos/presentation/void/painter/pattern_painter.dart'; import 'package:enaklo_pos/presentation/void/painter/pattern_painter.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -632,5 +633,10 @@ class _SuccessVoidPageState extends State<SuccessVoidPage>
); );
} }
void _printVoidReceipt() {} void _printVoidReceipt() {
onPrinVoidRecipt(context,
order: widget.voidedOrder,
productItemVoid: widget.voidedItems ?? [],
totalVoid: widget.voidAmount);
}
} }
+66 -2
View File
@@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "76.0.0" version: "76.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "948f7d74f41dd6f2d563ea9f4c21d7ea764f8e047d2b24138974c19c24d37eb6"
url: "https://pub.dev"
source: hosted
version: "1.3.61"
_macros: _macros:
dependency: transitive dependency: transitive
description: dart description: dart
@@ -454,6 +462,46 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3+3" version: "0.9.3+3"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "967dae9a65f69377beb9f4ab292ea63ce5befa1ce24682cab1b69ca4b7a46927"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: f7ee08febc1c4451588ce58ffcf28edaee857e9a196fee88b85deb889990094a
url: "https://pub.dev"
source: hosted
version: "3.1.0"
firebase_crashlytics:
dependency: "direct main"
description:
name: firebase_crashlytics
sha256: f2e175a967712ee1f616ab8843390891a315428ba497ce3d256d4c46f32db6f8
url: "https://pub.dev"
source: hosted
version: "5.0.1"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
sha256: b49b90af4a1fd8f30b58abd90af88371969bea51b62838a4f4e737c2098b725e
url: "https://pub.dev"
source: hosted
version: "3.8.12"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@@ -1386,6 +1434,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "1.4.1"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: ce02ce65f51db8e29edc9d2225872d927e001bd2b13c2490d176563bbb046fc7
url: "https://pub.dev"
source: hosted
version: "30.2.5"
syncfusion_flutter_datepicker:
dependency: "direct main"
description:
name: syncfusion_flutter_datepicker
sha256: e8df9f4777df15db11929f20cbe98e4249fe08208e7107bcb4ad889aa1ba2bbf
url: "https://pub.dev"
source: hosted
version: "30.2.5"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:
@@ -1571,5 +1635,5 @@ packages:
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.7.0-0 <4.0.0" dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.4" flutter: ">=3.29.0"
+3
View File
@@ -66,6 +66,9 @@ dependencies:
fl_chart: ^1.0.0 fl_chart: ^1.0.0
barcode: ^2.2.9 barcode: ^2.2.9
barcode_image: ^2.0.3 barcode_image: ^2.0.3
syncfusion_flutter_datepicker: ^30.2.5
firebase_core: ^4.1.0
firebase_crashlytics: ^5.0.1
# imin_printer: ^0.6.10 # imin_printer: ^0.6.10
dev_dependencies: dev_dependencies: