Compare commits
55
Commits
93560b85cb
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b0e66706 | ||
|
|
1ff144a1a2 | ||
|
|
eb031d4c2a | ||
|
|
7161f523c2 | ||
|
|
d097df1592 | ||
|
|
e8bbef03b0 | ||
|
|
b228538725 | ||
|
|
2ab20a1150 | ||
|
|
b9fcd79962 | ||
|
|
9a5f0c7415 | ||
|
|
d345294a2f | ||
|
|
beb86f6259 | ||
|
|
ea29c62af1 | ||
|
|
c8a84ffe5f | ||
|
|
539c70be17 | ||
|
|
c45848bcf2 | ||
|
|
6d9377f4ab | ||
|
|
56e720e253 | ||
|
|
c7ed45a374 | ||
|
|
a0610459bf | ||
|
|
842b7a5041 | ||
|
|
dc09aabbe8 | ||
|
|
cdc65f8f8f | ||
|
|
e7260ea0e2 | ||
|
|
b173654a9c | ||
|
|
699ca4cfb7 | ||
|
|
d790262fd4 | ||
|
|
60fec68a92 | ||
|
|
ab2d7d7be5 | ||
|
|
6ac88b92ae | ||
|
|
9e4e2ebbd1 | ||
|
|
3513c63259 | ||
|
|
46dfb7e44e | ||
|
|
a0db13feb4 | ||
|
|
f626b18d31 | ||
|
|
200f996d3e | ||
|
|
a739e1c29e | ||
|
|
4481d24375 | ||
|
|
59d8f06d75 | ||
|
|
e625bd3d2a | ||
|
|
5058f99fe0 | ||
|
|
f7cafeb583 | ||
|
|
37d747c0ba | ||
|
|
e3b9444a08 | ||
|
|
d8a28c084d | ||
|
|
d3974b8eda | ||
|
|
97313371c3 | ||
|
|
6fa45c8ac0 | ||
|
|
b2b2e2b111 | ||
|
|
0a8f8d93bb | ||
|
|
f5256fb33d | ||
|
|
c5673a147c | ||
|
|
af182b6f5a | ||
|
|
d78b6165c2 | ||
|
|
0886e8c912 |
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Dev",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"args": ["--dart-define=ENV=dev"]
|
||||
},
|
||||
{
|
||||
"name": "Prod",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"args": ["--dart-define=ENV=prod"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +1,215 @@
|
||||
# apskel_pos_flutter_v2
|
||||
# Apskel POS Flutter
|
||||
|
||||
A new Flutter project.
|
||||
Aplikasi Point of Sale (POS) berbasis Flutter untuk manajemen kasir restoran. Mendukung manajemen order, produk, meja, pelanggan, pembayaran, printer bluetooth/network, analitik, dan push notification via FCM.
|
||||
|
||||
## Getting Started
|
||||
---
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
## Fitur Utama
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
- **Autentikasi** — Login dengan email & password, logout, session management
|
||||
- **Order Management** — Buat, kelola, dan proses order
|
||||
- **Produk & Kategori** — Manajemen menu dan kategori produk
|
||||
- **Meja** — Manajemen meja restoran
|
||||
- **Pelanggan** — Data pelanggan dan riwayat transaksi
|
||||
- **Checkout & Pembayaran** — Proses checkout dengan berbagai metode pembayaran
|
||||
- **Split Bill** — Pembagian tagihan
|
||||
- **Void & Refund** — Pembatalan dan pengembalian transaksi
|
||||
- **Printer** — Cetak struk via Bluetooth dan Network printer
|
||||
- **Analitik** — Dashboard, laporan penjualan, produk, kategori, payment method, profit/loss, inventory
|
||||
- **Sinkronisasi** — Sinkronisasi data offline/online
|
||||
- **Push Notification (FCM)** — Notifikasi real-time via Firebase Cloud Messaging
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
---
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
## Tech Stack
|
||||
|
||||
| Kategori | Library |
|
||||
|---|---|
|
||||
| State Management | `flutter_bloc` + `bloc` |
|
||||
| Dependency Injection | `get_it` + `injectable` |
|
||||
| Navigation | `auto_route` |
|
||||
| HTTP Client | `dio` |
|
||||
| Local Database | `sqflite` |
|
||||
| Local Storage | `shared_preferences` |
|
||||
| Firebase | `firebase_core`, `firebase_crashlytics`, `firebase_messaging` |
|
||||
| Push Notification | `flutter_local_notifications` |
|
||||
| Device Info | `device_info_plus`, `package_info_plus` |
|
||||
| Code Generation | `freezed`, `json_serializable` |
|
||||
| Printer | `print_bluetooth_thermal`, `flutter_esc_pos_network` |
|
||||
| Chart | `fl_chart` |
|
||||
| Connectivity | `connectivity_plus` |
|
||||
|
||||
---
|
||||
|
||||
## Arsitektur
|
||||
|
||||
Project menggunakan **Clean Architecture** dengan 4 layer:
|
||||
|
||||
```
|
||||
lib/
|
||||
├── application/ # BLoC — state management per fitur
|
||||
├── domain/ # Entity, repository interface, failure
|
||||
├── infrastructure/ # Implementasi repository, DTO, datasource
|
||||
├── presentation/ # UI — pages, components, router
|
||||
└── common/ # Shared utilities, DI modules, service, theme
|
||||
```
|
||||
|
||||
### Struktur per Fitur
|
||||
|
||||
```
|
||||
feature/
|
||||
├── application/
|
||||
│ └── feature_bloc.dart # BLoC
|
||||
├── domain/
|
||||
│ ├── entities/ # Domain model (freezed)
|
||||
│ ├── repositories/ # Interface repository
|
||||
│ └── failures/ # Failure types
|
||||
└── infrastructure/
|
||||
├── datasources/
|
||||
│ ├── remote_data_provider.dart
|
||||
│ └── local_data_provider.dart
|
||||
├── dtos/ # Data Transfer Object (json_serializable)
|
||||
└── repositories/ # Implementasi repository
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup & Menjalankan
|
||||
|
||||
### Prasyarat
|
||||
|
||||
- Flutter SDK `^3.8.1`
|
||||
- Dart SDK `^3.8.1`
|
||||
- Android SDK / Xcode (untuk iOS)
|
||||
- Firebase project yang sudah dikonfigurasi
|
||||
|
||||
### Instalasi
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone <repo-url>
|
||||
cd apskel-pos-flutter-v2
|
||||
|
||||
# Install dependencies
|
||||
flutter pub get
|
||||
|
||||
# Generate kode (freezed, injectable, auto_route, json_serializable)
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
### Menjalankan App
|
||||
|
||||
```bash
|
||||
# Development
|
||||
flutter run
|
||||
|
||||
# Release
|
||||
flutter run --release
|
||||
```
|
||||
|
||||
App otomatis menggunakan environment `dev` saat debug dan `prod` saat release.
|
||||
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
Konfigurasi environment ada di `lib/env.dart`:
|
||||
|
||||
| Environment | Base URL | Database |
|
||||
|---|---|---|
|
||||
| `dev` | `https://api-pos.apskel.id` | `apskel_pos_dev.db` |
|
||||
| `prod` | `https://api-pos.apskel.id` | `apskel_pos_dev.db` |
|
||||
|
||||
Environment dipilih otomatis di `main.dart`:
|
||||
|
||||
```dart
|
||||
await configureDependencies(
|
||||
kReleaseMode ? Environment.prod : Environment.dev,
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
DI menggunakan `get_it` + `injectable`. Semua service, repository, dan BLoC didaftarkan via annotation.
|
||||
|
||||
### Modul DI
|
||||
|
||||
| File | Isi |
|
||||
|---|---|
|
||||
| `di_firebase.dart` | `FirebaseMessaging`, `FlutterLocalNotificationsPlugin`, `DeviceInfoPlugin`, `PackageInfo` |
|
||||
| `di_dio.dart` | `Dio` HTTP client |
|
||||
| `di_shared_preferences.dart` | `SharedPreferences` |
|
||||
| `di_database.dart` | `DatabaseHelper` (SQLite) |
|
||||
| `di_auto_route.dart` | `AppRouter` |
|
||||
| `di_connectivity.dart` | `Connectivity` |
|
||||
|
||||
Setelah menambah atau mengubah class yang menggunakan annotation injectable, jalankan:
|
||||
|
||||
```bash
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Firebase & FCM
|
||||
|
||||
### Setup
|
||||
|
||||
Firebase sudah dikonfigurasi di `android/app/google-services.json`. Inisialisasi dilakukan di `main.dart` sebelum app berjalan.
|
||||
|
||||
### FCM Service
|
||||
|
||||
`FcmService` (`lib/common/service/fcm_service.dart`) menangani:
|
||||
|
||||
- Request permission notifikasi (Android 13+ / iOS)
|
||||
- Ambil dan log FCM token
|
||||
- Foreground notification via `flutter_local_notifications`
|
||||
- Background & terminated message handler
|
||||
- Subscribe/unsubscribe topic
|
||||
|
||||
FCM token dikirim ke server saat login bersama device info.
|
||||
|
||||
### Login Payload
|
||||
|
||||
Saat login, app mengirim data berikut ke API:
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "secret",
|
||||
"fcm_token": "dXj3k9...",
|
||||
"device_id": "abc123",
|
||||
"device_name": "Samsung Galaxy Tab S8",
|
||||
"device_type": "tablet",
|
||||
"platform": "android",
|
||||
"app_version": "1.0.4+9",
|
||||
"os_version": "Android 13 (SDK 33)"
|
||||
}
|
||||
```
|
||||
|
||||
Nilai valid: `device_type` → `mobile | tablet | desktop`, `platform` → `android | ios | web`
|
||||
|
||||
---
|
||||
|
||||
## Printer
|
||||
|
||||
Mendukung dua jenis printer:
|
||||
|
||||
- **Bluetooth** — via `print_bluetooth_thermal`
|
||||
- **Network (LAN)** — via `flutter_esc_pos_network`
|
||||
|
||||
---
|
||||
|
||||
## Orientasi Layar
|
||||
|
||||
App dikunci ke mode **landscape** (kiri & kanan) karena didesain untuk tablet POS.
|
||||
|
||||
---
|
||||
|
||||
## Catatan Development
|
||||
|
||||
- Jangan edit `injection.config.dart` dan file `*.freezed.dart` / `*.g.dart` secara manual — file tersebut di-generate otomatis
|
||||
- Gunakan `log()` dari `dart:developer` untuk logging, bukan `print()`
|
||||
- `print()` dinonaktifkan di release mode
|
||||
|
||||
@@ -4,6 +4,9 @@ linter:
|
||||
rules:
|
||||
sort_pub_dependencies: false
|
||||
prefer_relative_imports: true
|
||||
prefer_const_constructors: true
|
||||
prefer_const_literals_to_create_immutables: true
|
||||
prefer_const_declarations: true
|
||||
|
||||
analyzer:
|
||||
errors:
|
||||
|
||||
@@ -14,6 +14,7 @@ android {
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
@@ -45,6 +46,8 @@ flutter {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
|
||||
|
||||
// Import the Firebase BoM
|
||||
implementation(platform("com.google.firebase:firebase-bom:34.4.0"))
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
<!-- Izin khusus untuk akses foto (media images) di Android 33 ke atas -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<!-- Izin notifikasi untuk Android 13+ -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<application
|
||||
android:label="Apskel POS"
|
||||
android:name="${applicationName}"
|
||||
@@ -41,6 +43,13 @@
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
<!-- FCM: default notification icon dan channel -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_notification" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="high_importance_channel" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 846 B |
Binary file not shown.
|
After Width: | Height: | Size: 431 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@@ -1,3 +1,7 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||
android.builtInKotlin=false
|
||||
# This newDsl flag was added automatically by Flutter migrator
|
||||
android.newDsl=false
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
@@ -33,16 +33,16 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
state.copyWith(
|
||||
failureOption: optionOf(f),
|
||||
status: token
|
||||
? AuthStatus.authenticated()
|
||||
: AuthStatus.unauthenticated(),
|
||||
? const AuthStatus.authenticated()
|
||||
: const AuthStatus.unauthenticated(),
|
||||
),
|
||||
),
|
||||
(user) => emit(
|
||||
state.copyWith(
|
||||
user: user,
|
||||
status: token
|
||||
? AuthStatus.authenticated()
|
||||
: AuthStatus.unauthenticated(),
|
||||
? const AuthStatus.authenticated()
|
||||
: const AuthStatus.unauthenticated(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -5,6 +5,8 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../common/service/device_info_service.dart';
|
||||
import '../../../common/service/fcm_service.dart';
|
||||
import '../../../domain/auth/auth.dart';
|
||||
|
||||
part 'login_form_event.dart';
|
||||
@@ -14,7 +16,14 @@ part 'login_form_bloc.freezed.dart';
|
||||
@injectable
|
||||
class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
|
||||
final IAuthRepository _authRepository;
|
||||
LoginFormBloc(this._authRepository) : super(LoginFormState.initial()) {
|
||||
final FcmService _fcmService;
|
||||
final DeviceInfoService _deviceInfoService;
|
||||
|
||||
LoginFormBloc(
|
||||
this._authRepository,
|
||||
this._fcmService,
|
||||
this._deviceInfoService,
|
||||
) : super(LoginFormState.initial()) {
|
||||
on<LoginFormEvent>(_onLoginFormEvent);
|
||||
}
|
||||
|
||||
@@ -43,9 +52,14 @@ class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
|
||||
);
|
||||
|
||||
if (emailValid && passwordValid) {
|
||||
final fcmToken = await _fcmService.getToken() ?? '';
|
||||
final devicePayload = await _deviceInfoService.getDevicePayload();
|
||||
|
||||
failureOrLogin = await _authRepository.login(
|
||||
email: state.email,
|
||||
password: state.password,
|
||||
fcmToken: fcmToken,
|
||||
devicePayload: devicePayload,
|
||||
);
|
||||
|
||||
emit(
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/auth/auth.dart';
|
||||
|
||||
part 'logout_event.dart';
|
||||
part 'logout_state.dart';
|
||||
part 'logout_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class LogoutBloc extends Bloc<LogoutEvent, LogoutState> {
|
||||
final IAuthRepository _authRepository;
|
||||
LogoutBloc(this._authRepository) : super(LogoutState.initial()) {
|
||||
on<LogoutEvent>(_onLogoutEvent);
|
||||
}
|
||||
|
||||
Future<void> _onLogoutEvent(LogoutEvent event, Emitter<LogoutState> emit) {
|
||||
return event.map(
|
||||
logout: (e) async {
|
||||
Either<AuthFailure, Unit>? failureOrSuccess;
|
||||
emit(
|
||||
state.copyWith(isLoggingOut: true, logoutFailureOrSuccess: none()),
|
||||
);
|
||||
|
||||
failureOrSuccess = await _authRepository.logout();
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoggingOut: false,
|
||||
logoutFailureOrSuccess: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
// 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 'logout_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 _$LogoutEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({required TResult Function() logout}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? logout}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? logout,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Logout value) logout,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Logout value)? logout,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Logout value)? logout,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LogoutEventCopyWith<$Res> {
|
||||
factory $LogoutEventCopyWith(
|
||||
LogoutEvent value,
|
||||
$Res Function(LogoutEvent) then,
|
||||
) = _$LogoutEventCopyWithImpl<$Res, LogoutEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LogoutEventCopyWithImpl<$Res, $Val extends LogoutEvent>
|
||||
implements $LogoutEventCopyWith<$Res> {
|
||||
_$LogoutEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LogoutEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LogoutImplCopyWith<$Res> {
|
||||
factory _$$LogoutImplCopyWith(
|
||||
_$LogoutImpl value,
|
||||
$Res Function(_$LogoutImpl) then,
|
||||
) = __$$LogoutImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LogoutImplCopyWithImpl<$Res>
|
||||
extends _$LogoutEventCopyWithImpl<$Res, _$LogoutImpl>
|
||||
implements _$$LogoutImplCopyWith<$Res> {
|
||||
__$$LogoutImplCopyWithImpl(
|
||||
_$LogoutImpl _value,
|
||||
$Res Function(_$LogoutImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LogoutEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LogoutImpl implements _Logout {
|
||||
const _$LogoutImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LogoutEvent.logout()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$LogoutImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({required TResult Function() logout}) {
|
||||
return logout();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({TResult? Function()? logout}) {
|
||||
return logout?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? logout,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (logout != null) {
|
||||
return logout();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Logout value) logout,
|
||||
}) {
|
||||
return logout(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Logout value)? logout,
|
||||
}) {
|
||||
return logout?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Logout value)? logout,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (logout != null) {
|
||||
return logout(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Logout implements LogoutEvent {
|
||||
const factory _Logout() = _$LogoutImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LogoutState {
|
||||
Option<Either<AuthFailure, Unit>> get logoutFailureOrSuccess =>
|
||||
throw _privateConstructorUsedError;
|
||||
bool get isLoggingOut => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LogoutState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LogoutStateCopyWith<LogoutState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LogoutStateCopyWith<$Res> {
|
||||
factory $LogoutStateCopyWith(
|
||||
LogoutState value,
|
||||
$Res Function(LogoutState) then,
|
||||
) = _$LogoutStateCopyWithImpl<$Res, LogoutState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
Option<Either<AuthFailure, Unit>> logoutFailureOrSuccess,
|
||||
bool isLoggingOut,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LogoutStateCopyWithImpl<$Res, $Val extends LogoutState>
|
||||
implements $LogoutStateCopyWith<$Res> {
|
||||
_$LogoutStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LogoutState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? logoutFailureOrSuccess = null,
|
||||
Object? isLoggingOut = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
logoutFailureOrSuccess: null == logoutFailureOrSuccess
|
||||
? _value.logoutFailureOrSuccess
|
||||
: logoutFailureOrSuccess // ignore: cast_nullable_to_non_nullable
|
||||
as Option<Either<AuthFailure, Unit>>,
|
||||
isLoggingOut: null == isLoggingOut
|
||||
? _value.isLoggingOut
|
||||
: isLoggingOut // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LogoutStateImplCopyWith<$Res>
|
||||
implements $LogoutStateCopyWith<$Res> {
|
||||
factory _$$LogoutStateImplCopyWith(
|
||||
_$LogoutStateImpl value,
|
||||
$Res Function(_$LogoutStateImpl) then,
|
||||
) = __$$LogoutStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
Option<Either<AuthFailure, Unit>> logoutFailureOrSuccess,
|
||||
bool isLoggingOut,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LogoutStateImplCopyWithImpl<$Res>
|
||||
extends _$LogoutStateCopyWithImpl<$Res, _$LogoutStateImpl>
|
||||
implements _$$LogoutStateImplCopyWith<$Res> {
|
||||
__$$LogoutStateImplCopyWithImpl(
|
||||
_$LogoutStateImpl _value,
|
||||
$Res Function(_$LogoutStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LogoutState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? logoutFailureOrSuccess = null,
|
||||
Object? isLoggingOut = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$LogoutStateImpl(
|
||||
logoutFailureOrSuccess: null == logoutFailureOrSuccess
|
||||
? _value.logoutFailureOrSuccess
|
||||
: logoutFailureOrSuccess // ignore: cast_nullable_to_non_nullable
|
||||
as Option<Either<AuthFailure, Unit>>,
|
||||
isLoggingOut: null == isLoggingOut
|
||||
? _value.isLoggingOut
|
||||
: isLoggingOut // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LogoutStateImpl implements _LogoutState {
|
||||
_$LogoutStateImpl({
|
||||
required this.logoutFailureOrSuccess,
|
||||
this.isLoggingOut = false,
|
||||
});
|
||||
|
||||
@override
|
||||
final Option<Either<AuthFailure, Unit>> logoutFailureOrSuccess;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isLoggingOut;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LogoutState(logoutFailureOrSuccess: $logoutFailureOrSuccess, isLoggingOut: $isLoggingOut)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LogoutStateImpl &&
|
||||
(identical(other.logoutFailureOrSuccess, logoutFailureOrSuccess) ||
|
||||
other.logoutFailureOrSuccess == logoutFailureOrSuccess) &&
|
||||
(identical(other.isLoggingOut, isLoggingOut) ||
|
||||
other.isLoggingOut == isLoggingOut));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, logoutFailureOrSuccess, isLoggingOut);
|
||||
|
||||
/// Create a copy of LogoutState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LogoutStateImplCopyWith<_$LogoutStateImpl> get copyWith =>
|
||||
__$$LogoutStateImplCopyWithImpl<_$LogoutStateImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _LogoutState implements LogoutState {
|
||||
factory _LogoutState({
|
||||
required final Option<Either<AuthFailure, Unit>> logoutFailureOrSuccess,
|
||||
final bool isLoggingOut,
|
||||
}) = _$LogoutStateImpl;
|
||||
|
||||
@override
|
||||
Option<Either<AuthFailure, Unit>> get logoutFailureOrSuccess;
|
||||
@override
|
||||
bool get isLoggingOut;
|
||||
|
||||
/// Create a copy of LogoutState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LogoutStateImplCopyWith<_$LogoutStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
part of 'logout_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class LogoutEvent with _$LogoutEvent {
|
||||
const factory LogoutEvent.logout() = _Logout;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
part of 'logout_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class LogoutState with _$LogoutState {
|
||||
factory LogoutState({
|
||||
required Option<Either<AuthFailure, Unit>> logoutFailureOrSuccess,
|
||||
@Default(false) bool isLoggingOut,
|
||||
}) = _LogoutState;
|
||||
|
||||
factory LogoutState.initial() => LogoutState(logoutFailureOrSuccess: none());
|
||||
}
|
||||
@@ -175,7 +175,7 @@ class CategoryLoaderBloc
|
||||
_searchDebounce?.cancel();
|
||||
|
||||
// Debounce search for better UX
|
||||
_searchDebounce = Timer(Duration(milliseconds: 300), () async {
|
||||
_searchDebounce = Timer(const Duration(milliseconds: 300), () async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
_isLoadingMore = false;
|
||||
|
||||
@@ -237,7 +237,7 @@ class CategoryLoaderBloc
|
||||
);
|
||||
|
||||
// After sync error, try to load local data
|
||||
Timer(Duration(seconds: 2), () {
|
||||
Timer(const Duration(seconds: 2), () {
|
||||
add(const CategoryLoaderEvent.getCategories());
|
||||
});
|
||||
},
|
||||
@@ -251,7 +251,7 @@ class CategoryLoaderBloc
|
||||
);
|
||||
|
||||
// After successful sync, load the updated data
|
||||
Timer(Duration(seconds: 1), () {
|
||||
Timer(const Duration(seconds: 1), () {
|
||||
add(const CategoryLoaderEvent.getCategories());
|
||||
});
|
||||
},
|
||||
|
||||
@@ -180,6 +180,9 @@ class CheckoutFormBloc extends Bloc<CheckoutFormEvent, CheckoutFormState> {
|
||||
orderAddedItems: (e) async {
|
||||
emit(state.copyWith(orderAdded: e.order));
|
||||
},
|
||||
customerNameChanged: (e) async {
|
||||
emit(state.copyWith(customerName: e.name,));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ mixin _$CheckoutFormEvent {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
@@ -39,6 +40,7 @@ mixin _$CheckoutFormEvent {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
@@ -50,6 +52,7 @@ mixin _$CheckoutFormEvent {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
@@ -62,6 +65,7 @@ mixin _$CheckoutFormEvent {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
@@ -73,6 +77,7 @@ mixin _$CheckoutFormEvent {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
@@ -84,6 +89,7 @@ mixin _$CheckoutFormEvent {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -195,6 +201,7 @@ class _$StartedImpl implements _Started {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return started(items);
|
||||
}
|
||||
@@ -210,6 +217,7 @@ class _$StartedImpl implements _Started {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return started?.call(items);
|
||||
}
|
||||
@@ -225,6 +233,7 @@ class _$StartedImpl implements _Started {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (started != null) {
|
||||
@@ -244,6 +253,7 @@ class _$StartedImpl implements _Started {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return started(this);
|
||||
}
|
||||
@@ -259,6 +269,7 @@ class _$StartedImpl implements _Started {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return started?.call(this);
|
||||
}
|
||||
@@ -274,6 +285,7 @@ class _$StartedImpl implements _Started {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (started != null) {
|
||||
@@ -408,6 +420,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return addItem(product, variant);
|
||||
}
|
||||
@@ -423,6 +436,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return addItem?.call(product, variant);
|
||||
}
|
||||
@@ -438,6 +452,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (addItem != null) {
|
||||
@@ -457,6 +472,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return addItem(this);
|
||||
}
|
||||
@@ -472,6 +488,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return addItem?.call(this);
|
||||
}
|
||||
@@ -487,6 +504,7 @@ class _$AddItemImpl implements _AddItem {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (addItem != null) {
|
||||
@@ -623,6 +641,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return removeItem(product, variant);
|
||||
}
|
||||
@@ -638,6 +657,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return removeItem?.call(product, variant);
|
||||
}
|
||||
@@ -653,6 +673,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (removeItem != null) {
|
||||
@@ -672,6 +693,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return removeItem(this);
|
||||
}
|
||||
@@ -687,6 +709,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return removeItem?.call(this);
|
||||
}
|
||||
@@ -702,6 +725,7 @@ class _$RemoveItemImpl implements _RemoveItem {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (removeItem != null) {
|
||||
@@ -828,6 +852,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return updateItemNotes(product, notes);
|
||||
}
|
||||
@@ -843,6 +868,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return updateItemNotes?.call(product, notes);
|
||||
}
|
||||
@@ -858,6 +884,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateItemNotes != null) {
|
||||
@@ -877,6 +904,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return updateItemNotes(this);
|
||||
}
|
||||
@@ -892,6 +920,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return updateItemNotes?.call(this);
|
||||
}
|
||||
@@ -907,6 +936,7 @@ class _$UpdateItemNotesImpl implements _UpdateItemNotes {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateItemNotes != null) {
|
||||
@@ -1013,6 +1043,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return updateOrderType(orderType);
|
||||
}
|
||||
@@ -1028,6 +1059,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return updateOrderType?.call(orderType);
|
||||
}
|
||||
@@ -1043,6 +1075,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateOrderType != null) {
|
||||
@@ -1062,6 +1095,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return updateOrderType(this);
|
||||
}
|
||||
@@ -1077,6 +1111,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return updateOrderType?.call(this);
|
||||
}
|
||||
@@ -1092,6 +1127,7 @@ class _$UpdateOrderTypeImpl implements _UpdateOrderType {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateOrderType != null) {
|
||||
@@ -1197,6 +1233,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return updateDelivery(delivery);
|
||||
}
|
||||
@@ -1212,6 +1249,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return updateDelivery?.call(delivery);
|
||||
}
|
||||
@@ -1227,6 +1265,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateDelivery != null) {
|
||||
@@ -1246,6 +1285,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return updateDelivery(this);
|
||||
}
|
||||
@@ -1261,6 +1301,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return updateDelivery?.call(this);
|
||||
}
|
||||
@@ -1276,6 +1317,7 @@ class _$UpdateDeliveryImpl implements _UpdateDelivery {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateDelivery != null) {
|
||||
@@ -1392,6 +1434,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return updateTable(table);
|
||||
}
|
||||
@@ -1407,6 +1450,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return updateTable?.call(table);
|
||||
}
|
||||
@@ -1422,6 +1466,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateTable != null) {
|
||||
@@ -1441,6 +1486,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return updateTable(this);
|
||||
}
|
||||
@@ -1456,6 +1502,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return updateTable?.call(this);
|
||||
}
|
||||
@@ -1471,6 +1518,7 @@ class _$UpdateTableImpl implements _UpdateTable {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateTable != null) {
|
||||
@@ -1590,6 +1638,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return orderAddedItems(order);
|
||||
}
|
||||
@@ -1605,6 +1654,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return orderAddedItems?.call(order);
|
||||
}
|
||||
@@ -1620,6 +1670,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (orderAddedItems != null) {
|
||||
@@ -1639,6 +1690,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return orderAddedItems(this);
|
||||
}
|
||||
@@ -1654,6 +1706,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return orderAddedItems?.call(this);
|
||||
}
|
||||
@@ -1669,6 +1722,7 @@ class _$OrderAddedItemsImpl implements _OrderAddedItems {
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (orderAddedItems != null) {
|
||||
@@ -1690,6 +1744,195 @@ abstract class _OrderAddedItems implements CheckoutFormEvent {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CustomerNameChangedImplCopyWith<$Res> {
|
||||
factory _$$CustomerNameChangedImplCopyWith(
|
||||
_$CustomerNameChangedImpl value,
|
||||
$Res Function(_$CustomerNameChangedImpl) then,
|
||||
) = __$$CustomerNameChangedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String name});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CustomerNameChangedImplCopyWithImpl<$Res>
|
||||
extends _$CheckoutFormEventCopyWithImpl<$Res, _$CustomerNameChangedImpl>
|
||||
implements _$$CustomerNameChangedImplCopyWith<$Res> {
|
||||
__$$CustomerNameChangedImplCopyWithImpl(
|
||||
_$CustomerNameChangedImpl _value,
|
||||
$Res Function(_$CustomerNameChangedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of CheckoutFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? name = null}) {
|
||||
return _then(
|
||||
_$CustomerNameChangedImpl(
|
||||
null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$CustomerNameChangedImpl implements _CustomerNameChanged {
|
||||
const _$CustomerNameChangedImpl(this.name);
|
||||
|
||||
@override
|
||||
final String name;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CheckoutFormEvent.customerNameChanged(name: $name)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$CustomerNameChangedImpl &&
|
||||
(identical(other.name, name) || other.name == name));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, name);
|
||||
|
||||
/// Create a copy of CheckoutFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CustomerNameChangedImplCopyWith<_$CustomerNameChangedImpl> get copyWith =>
|
||||
__$$CustomerNameChangedImplCopyWithImpl<_$CustomerNameChangedImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(List<ProductQuantity> items) started,
|
||||
required TResult Function(Product product, ProductVariant? variant) addItem,
|
||||
required TResult Function(Product product, ProductVariant? variant)
|
||||
removeItem,
|
||||
required TResult Function(Product product, String notes) updateItemNotes,
|
||||
required TResult Function(OrderType orderType) updateOrderType,
|
||||
required TResult Function(Delivery delivery) updateDelivery,
|
||||
required TResult Function(Table? table) updateTable,
|
||||
required TResult Function(Order? order) orderAddedItems,
|
||||
required TResult Function(String name) customerNameChanged,
|
||||
}) {
|
||||
return customerNameChanged(name);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(List<ProductQuantity> items)? started,
|
||||
TResult? Function(Product product, ProductVariant? variant)? addItem,
|
||||
TResult? Function(Product product, ProductVariant? variant)? removeItem,
|
||||
TResult? Function(Product product, String notes)? updateItemNotes,
|
||||
TResult? Function(OrderType orderType)? updateOrderType,
|
||||
TResult? Function(Delivery delivery)? updateDelivery,
|
||||
TResult? Function(Table? table)? updateTable,
|
||||
TResult? Function(Order? order)? orderAddedItems,
|
||||
TResult? Function(String name)? customerNameChanged,
|
||||
}) {
|
||||
return customerNameChanged?.call(name);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(List<ProductQuantity> items)? started,
|
||||
TResult Function(Product product, ProductVariant? variant)? addItem,
|
||||
TResult Function(Product product, ProductVariant? variant)? removeItem,
|
||||
TResult Function(Product product, String notes)? updateItemNotes,
|
||||
TResult Function(OrderType orderType)? updateOrderType,
|
||||
TResult Function(Delivery delivery)? updateDelivery,
|
||||
TResult Function(Table? table)? updateTable,
|
||||
TResult Function(Order? order)? orderAddedItems,
|
||||
TResult Function(String name)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (customerNameChanged != null) {
|
||||
return customerNameChanged(name);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Started value) started,
|
||||
required TResult Function(_AddItem value) addItem,
|
||||
required TResult Function(_RemoveItem value) removeItem,
|
||||
required TResult Function(_UpdateItemNotes value) updateItemNotes,
|
||||
required TResult Function(_UpdateOrderType value) updateOrderType,
|
||||
required TResult Function(_UpdateDelivery value) updateDelivery,
|
||||
required TResult Function(_UpdateTable value) updateTable,
|
||||
required TResult Function(_OrderAddedItems value) orderAddedItems,
|
||||
required TResult Function(_CustomerNameChanged value) customerNameChanged,
|
||||
}) {
|
||||
return customerNameChanged(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Started value)? started,
|
||||
TResult? Function(_AddItem value)? addItem,
|
||||
TResult? Function(_RemoveItem value)? removeItem,
|
||||
TResult? Function(_UpdateItemNotes value)? updateItemNotes,
|
||||
TResult? Function(_UpdateOrderType value)? updateOrderType,
|
||||
TResult? Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult? Function(_UpdateTable value)? updateTable,
|
||||
TResult? Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult? Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
}) {
|
||||
return customerNameChanged?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Started value)? started,
|
||||
TResult Function(_AddItem value)? addItem,
|
||||
TResult Function(_RemoveItem value)? removeItem,
|
||||
TResult Function(_UpdateItemNotes value)? updateItemNotes,
|
||||
TResult Function(_UpdateOrderType value)? updateOrderType,
|
||||
TResult Function(_UpdateDelivery value)? updateDelivery,
|
||||
TResult Function(_UpdateTable value)? updateTable,
|
||||
TResult Function(_OrderAddedItems value)? orderAddedItems,
|
||||
TResult Function(_CustomerNameChanged value)? customerNameChanged,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (customerNameChanged != null) {
|
||||
return customerNameChanged(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _CustomerNameChanged implements CheckoutFormEvent {
|
||||
const factory _CustomerNameChanged(final String name) =
|
||||
_$CustomerNameChangedImpl;
|
||||
|
||||
String get name;
|
||||
|
||||
/// Create a copy of CheckoutFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CustomerNameChangedImplCopyWith<_$CustomerNameChangedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CheckoutFormState {
|
||||
Order? get orderAdded => throw _privateConstructorUsedError;
|
||||
@@ -1702,6 +1945,7 @@ mixin _$CheckoutFormState {
|
||||
int get totalPrice => throw _privateConstructorUsedError;
|
||||
String get draftName => throw _privateConstructorUsedError;
|
||||
OrderType get orderType => throw _privateConstructorUsedError;
|
||||
String get customerName => throw _privateConstructorUsedError;
|
||||
Delivery? get delivery => throw _privateConstructorUsedError;
|
||||
Table? get table => throw _privateConstructorUsedError;
|
||||
bool get isLoading => throw _privateConstructorUsedError;
|
||||
@@ -1731,6 +1975,7 @@ abstract class $CheckoutFormStateCopyWith<$Res> {
|
||||
int totalPrice,
|
||||
String draftName,
|
||||
OrderType orderType,
|
||||
String customerName,
|
||||
Delivery? delivery,
|
||||
Table? table,
|
||||
bool isLoading,
|
||||
@@ -1765,6 +2010,7 @@ class _$CheckoutFormStateCopyWithImpl<$Res, $Val extends CheckoutFormState>
|
||||
Object? totalPrice = null,
|
||||
Object? draftName = null,
|
||||
Object? orderType = null,
|
||||
Object? customerName = null,
|
||||
Object? delivery = freezed,
|
||||
Object? table = freezed,
|
||||
Object? isLoading = null,
|
||||
@@ -1811,6 +2057,10 @@ class _$CheckoutFormStateCopyWithImpl<$Res, $Val extends CheckoutFormState>
|
||||
? _value.orderType
|
||||
: orderType // ignore: cast_nullable_to_non_nullable
|
||||
as OrderType,
|
||||
customerName: null == customerName
|
||||
? _value.customerName
|
||||
: customerName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
delivery: freezed == delivery
|
||||
? _value.delivery
|
||||
: delivery // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1877,6 +2127,7 @@ abstract class _$$CheckoutFormStateImplCopyWith<$Res>
|
||||
int totalPrice,
|
||||
String draftName,
|
||||
OrderType orderType,
|
||||
String customerName,
|
||||
Delivery? delivery,
|
||||
Table? table,
|
||||
bool isLoading,
|
||||
@@ -1912,6 +2163,7 @@ class __$$CheckoutFormStateImplCopyWithImpl<$Res>
|
||||
Object? totalPrice = null,
|
||||
Object? draftName = null,
|
||||
Object? orderType = null,
|
||||
Object? customerName = null,
|
||||
Object? delivery = freezed,
|
||||
Object? table = freezed,
|
||||
Object? isLoading = null,
|
||||
@@ -1958,6 +2210,10 @@ class __$$CheckoutFormStateImplCopyWithImpl<$Res>
|
||||
? _value.orderType
|
||||
: orderType // ignore: cast_nullable_to_non_nullable
|
||||
as OrderType,
|
||||
customerName: null == customerName
|
||||
? _value.customerName
|
||||
: customerName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
delivery: freezed == delivery
|
||||
? _value.delivery
|
||||
: delivery // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1989,6 +2245,7 @@ class _$CheckoutFormStateImpl implements _CheckoutFormState {
|
||||
required this.totalPrice,
|
||||
required this.draftName,
|
||||
required this.orderType,
|
||||
required this.customerName,
|
||||
this.delivery,
|
||||
this.table,
|
||||
this.isLoading = false,
|
||||
@@ -2021,6 +2278,8 @@ class _$CheckoutFormStateImpl implements _CheckoutFormState {
|
||||
@override
|
||||
final OrderType orderType;
|
||||
@override
|
||||
final String customerName;
|
||||
@override
|
||||
final Delivery? delivery;
|
||||
@override
|
||||
final Table? table;
|
||||
@@ -2030,7 +2289,7 @@ class _$CheckoutFormStateImpl implements _CheckoutFormState {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CheckoutFormState(orderAdded: $orderAdded, items: $items, discount: $discount, discountAmount: $discountAmount, tax: $tax, serviceCharge: $serviceCharge, totalQuantity: $totalQuantity, totalPrice: $totalPrice, draftName: $draftName, orderType: $orderType, delivery: $delivery, table: $table, isLoading: $isLoading)';
|
||||
return 'CheckoutFormState(orderAdded: $orderAdded, items: $items, discount: $discount, discountAmount: $discountAmount, tax: $tax, serviceCharge: $serviceCharge, totalQuantity: $totalQuantity, totalPrice: $totalPrice, draftName: $draftName, orderType: $orderType, customerName: $customerName, delivery: $delivery, table: $table, isLoading: $isLoading)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2056,6 +2315,8 @@ class _$CheckoutFormStateImpl implements _CheckoutFormState {
|
||||
other.draftName == draftName) &&
|
||||
(identical(other.orderType, orderType) ||
|
||||
other.orderType == orderType) &&
|
||||
(identical(other.customerName, customerName) ||
|
||||
other.customerName == customerName) &&
|
||||
(identical(other.delivery, delivery) ||
|
||||
other.delivery == delivery) &&
|
||||
(identical(other.table, table) || other.table == table) &&
|
||||
@@ -2076,6 +2337,7 @@ class _$CheckoutFormStateImpl implements _CheckoutFormState {
|
||||
totalPrice,
|
||||
draftName,
|
||||
orderType,
|
||||
customerName,
|
||||
delivery,
|
||||
table,
|
||||
isLoading,
|
||||
@@ -2105,6 +2367,7 @@ abstract class _CheckoutFormState implements CheckoutFormState {
|
||||
required final int totalPrice,
|
||||
required final String draftName,
|
||||
required final OrderType orderType,
|
||||
required final String customerName,
|
||||
final Delivery? delivery,
|
||||
final Table? table,
|
||||
final bool isLoading,
|
||||
@@ -2131,6 +2394,8 @@ abstract class _CheckoutFormState implements CheckoutFormState {
|
||||
@override
|
||||
OrderType get orderType;
|
||||
@override
|
||||
String get customerName;
|
||||
@override
|
||||
Delivery? get delivery;
|
||||
@override
|
||||
Table? get table;
|
||||
|
||||
@@ -30,4 +30,6 @@ class CheckoutFormEvent with _$CheckoutFormEvent {
|
||||
|
||||
const factory CheckoutFormEvent.orderAddedItems(Order? order) =
|
||||
_OrderAddedItems;
|
||||
const factory CheckoutFormEvent.customerNameChanged(String name) =
|
||||
_CustomerNameChanged;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class CheckoutFormState with _$CheckoutFormState {
|
||||
required int totalPrice,
|
||||
required String draftName,
|
||||
required OrderType orderType,
|
||||
required String customerName,
|
||||
Delivery? delivery,
|
||||
Table? table,
|
||||
@Default(false) bool isLoading,
|
||||
@@ -27,6 +28,7 @@ class CheckoutFormState with _$CheckoutFormState {
|
||||
totalQuantity: 0,
|
||||
totalPrice: 0,
|
||||
draftName: '',
|
||||
customerName: '',
|
||||
orderType: OrderType.dineIn,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../../common/types/order_type.dart';
|
||||
import '../../../domain/customer/customer.dart';
|
||||
@@ -123,10 +124,15 @@ class OrderFormBloc extends Bloc<OrderFormEvent, OrderFormState> {
|
||||
addItemOrder: (e) async {
|
||||
Either<OrderFailure, Order> failureOrAddItemOrder;
|
||||
|
||||
// Generate new idempotency key saat user intent (tap Add Items)
|
||||
// Kalau sedang retry, pakai key yang sama
|
||||
final idempotencyKey = state.addItemIdempotencyKey ?? const Uuid().v4();
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isAddingItemOrder: true,
|
||||
failureOrAddItemOrder: none(),
|
||||
addItemIdempotencyKey: idempotencyKey,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -145,12 +151,16 @@ class OrderFormBloc extends Bloc<OrderFormEvent, OrderFormState> {
|
||||
failureOrAddItemOrder = await _repository.addItemOrder(
|
||||
id: e.orderId,
|
||||
request: request,
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isAddingItemOrder: false,
|
||||
failureOrAddItemOrder: optionOf(failureOrAddItemOrder),
|
||||
// Clear key on success, keep on failure for retry
|
||||
addItemIdempotencyKey:
|
||||
failureOrAddItemOrder.isRight() ? null : idempotencyKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1584,6 +1584,11 @@ mixin _$OrderFormState {
|
||||
bool get isCreatingWithPayment => throw _privateConstructorUsedError;
|
||||
bool get isAddingItemOrder => throw _privateConstructorUsedError;
|
||||
|
||||
/// Idempotency key untuk add item order.
|
||||
/// Di-generate saat user tap "Add Items", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? get addItemIdempotencyKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of OrderFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -1608,6 +1613,7 @@ abstract class $OrderFormStateCopyWith<$Res> {
|
||||
bool isCreating,
|
||||
bool isCreatingWithPayment,
|
||||
bool isAddingItemOrder,
|
||||
String? addItemIdempotencyKey,
|
||||
});
|
||||
|
||||
$PaymentMethodCopyWith<$Res>? get paymentMethod;
|
||||
@@ -1638,6 +1644,7 @@ class _$OrderFormStateCopyWithImpl<$Res, $Val extends OrderFormState>
|
||||
Object? isCreating = null,
|
||||
Object? isCreatingWithPayment = null,
|
||||
Object? isAddingItemOrder = null,
|
||||
Object? addItemIdempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -1678,6 +1685,10 @@ class _$OrderFormStateCopyWithImpl<$Res, $Val extends OrderFormState>
|
||||
? _value.isAddingItemOrder
|
||||
: isAddingItemOrder // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
addItemIdempotencyKey: freezed == addItemIdempotencyKey
|
||||
? _value.addItemIdempotencyKey
|
||||
: addItemIdempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -1731,6 +1742,7 @@ abstract class _$$OrderFormStateImplCopyWith<$Res>
|
||||
bool isCreating,
|
||||
bool isCreatingWithPayment,
|
||||
bool isAddingItemOrder,
|
||||
String? addItemIdempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -1762,6 +1774,7 @@ class __$$OrderFormStateImplCopyWithImpl<$Res>
|
||||
Object? isCreating = null,
|
||||
Object? isCreatingWithPayment = null,
|
||||
Object? isAddingItemOrder = null,
|
||||
Object? addItemIdempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$OrderFormStateImpl(
|
||||
@@ -1801,6 +1814,10 @@ class __$$OrderFormStateImplCopyWithImpl<$Res>
|
||||
? _value.isAddingItemOrder
|
||||
: isAddingItemOrder // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
addItemIdempotencyKey: freezed == addItemIdempotencyKey
|
||||
? _value.addItemIdempotencyKey
|
||||
: addItemIdempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1821,6 +1838,7 @@ class _$OrderFormStateImpl
|
||||
this.isCreating = false,
|
||||
this.isCreatingWithPayment = false,
|
||||
this.isAddingItemOrder = false,
|
||||
this.addItemIdempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -1845,9 +1863,15 @@ class _$OrderFormStateImpl
|
||||
@JsonKey()
|
||||
final bool isAddingItemOrder;
|
||||
|
||||
/// Idempotency key untuk add item order.
|
||||
/// Di-generate saat user tap "Add Items", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
final String? addItemIdempotencyKey;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'OrderFormState(paymentMethod: $paymentMethod, customerName: $customerName, customer: $customer, failureOrCreateOrder: $failureOrCreateOrder, failureOrCreateOrderWithPayment: $failureOrCreateOrderWithPayment, failureOrAddItemOrder: $failureOrAddItemOrder, isCreating: $isCreating, isCreatingWithPayment: $isCreatingWithPayment, isAddingItemOrder: $isAddingItemOrder)';
|
||||
return 'OrderFormState(paymentMethod: $paymentMethod, customerName: $customerName, customer: $customer, failureOrCreateOrder: $failureOrCreateOrder, failureOrCreateOrderWithPayment: $failureOrCreateOrderWithPayment, failureOrAddItemOrder: $failureOrAddItemOrder, isCreating: $isCreating, isCreatingWithPayment: $isCreatingWithPayment, isAddingItemOrder: $isAddingItemOrder, addItemIdempotencyKey: $addItemIdempotencyKey)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1868,7 +1892,10 @@ class _$OrderFormStateImpl
|
||||
..add(DiagnosticsProperty('failureOrAddItemOrder', failureOrAddItemOrder))
|
||||
..add(DiagnosticsProperty('isCreating', isCreating))
|
||||
..add(DiagnosticsProperty('isCreatingWithPayment', isCreatingWithPayment))
|
||||
..add(DiagnosticsProperty('isAddingItemOrder', isAddingItemOrder));
|
||||
..add(DiagnosticsProperty('isAddingItemOrder', isAddingItemOrder))
|
||||
..add(
|
||||
DiagnosticsProperty('addItemIdempotencyKey', addItemIdempotencyKey),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1897,7 +1924,9 @@ class _$OrderFormStateImpl
|
||||
(identical(other.isCreatingWithPayment, isCreatingWithPayment) ||
|
||||
other.isCreatingWithPayment == isCreatingWithPayment) &&
|
||||
(identical(other.isAddingItemOrder, isAddingItemOrder) ||
|
||||
other.isAddingItemOrder == isAddingItemOrder));
|
||||
other.isAddingItemOrder == isAddingItemOrder) &&
|
||||
(identical(other.addItemIdempotencyKey, addItemIdempotencyKey) ||
|
||||
other.addItemIdempotencyKey == addItemIdempotencyKey));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1912,6 +1941,7 @@ class _$OrderFormStateImpl
|
||||
isCreating,
|
||||
isCreatingWithPayment,
|
||||
isAddingItemOrder,
|
||||
addItemIdempotencyKey,
|
||||
);
|
||||
|
||||
/// Create a copy of OrderFormState
|
||||
@@ -1938,6 +1968,7 @@ abstract class _OrderFormState implements OrderFormState {
|
||||
final bool isCreating,
|
||||
final bool isCreatingWithPayment,
|
||||
final bool isAddingItemOrder,
|
||||
final String? addItemIdempotencyKey,
|
||||
}) = _$OrderFormStateImpl;
|
||||
|
||||
@override
|
||||
@@ -1959,6 +1990,12 @@ abstract class _OrderFormState implements OrderFormState {
|
||||
@override
|
||||
bool get isAddingItemOrder;
|
||||
|
||||
/// Idempotency key untuk add item order.
|
||||
/// Di-generate saat user tap "Add Items", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
String? get addItemIdempotencyKey;
|
||||
|
||||
/// Create a copy of OrderFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
|
||||
@@ -13,6 +13,10 @@ class OrderFormState with _$OrderFormState {
|
||||
@Default(false) bool isCreating,
|
||||
@Default(false) bool isCreatingWithPayment,
|
||||
@Default(false) bool isAddingItemOrder,
|
||||
/// Idempotency key untuk add item order.
|
||||
/// Di-generate saat user tap "Add Items", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? addItemIdempotencyKey,
|
||||
}) = _OrderFormState;
|
||||
|
||||
factory OrderFormState.initial() => OrderFormState(
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../../common/types/split_type.dart';
|
||||
import '../../../domain/order/order.dart';
|
||||
@@ -38,7 +39,15 @@ class PaymentFormBloc extends Bloc<PaymentFormEvent, PaymentFormState> {
|
||||
submitted: (e) async {
|
||||
Either<OrderFailure, Payment> failureOrPayment;
|
||||
|
||||
emit(state.copyWith(isSubmitting: true, failureOrPayment: none()));
|
||||
// Generate new idempotency key saat user intent (tap Bayar)
|
||||
// Kalau sedang retry (isSubmitting sebelumnya gagal), pakai key yang sama
|
||||
final idempotencyKey = state.idempotencyKey ?? const Uuid().v4();
|
||||
|
||||
emit(state.copyWith(
|
||||
isSubmitting: true,
|
||||
failureOrPayment: none(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
));
|
||||
|
||||
final request = PaymentRequest(
|
||||
orderId: state.order.id,
|
||||
@@ -58,20 +67,32 @@ class PaymentFormBloc extends Bloc<PaymentFormEvent, PaymentFormState> {
|
||||
.toList(),
|
||||
);
|
||||
|
||||
failureOrPayment = await _repository.createPayment(request: request);
|
||||
failureOrPayment = await _repository.createPayment(
|
||||
request: request,
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSubmitting: false,
|
||||
failureOrPayment: optionOf(failureOrPayment),
|
||||
// Clear key on success, keep on failure for retry
|
||||
idempotencyKey: failureOrPayment.isRight() ? null : idempotencyKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
submittedSplitBill: (e) async {
|
||||
Either<OrderFailure, Payment> failureOrPayment;
|
||||
|
||||
// Generate new idempotency key untuk split bill
|
||||
final idempotencyKey = state.splitBillIdempotencyKey ?? const Uuid().v4();
|
||||
|
||||
emit(
|
||||
state.copyWith(isSubmitting: true, failureOrPaymentSplitBill: none()),
|
||||
state.copyWith(
|
||||
isSubmitting: true,
|
||||
failureOrPaymentSplitBill: none(),
|
||||
splitBillIdempotencyKey: idempotencyKey,
|
||||
),
|
||||
);
|
||||
|
||||
final request = PaymentSplitBillRequest(
|
||||
@@ -93,12 +114,18 @@ class PaymentFormBloc extends Bloc<PaymentFormEvent, PaymentFormState> {
|
||||
|
||||
log(request.toString());
|
||||
|
||||
failureOrPayment = await _repository.createSplitBill(request);
|
||||
failureOrPayment = await _repository.createSplitBill(
|
||||
request,
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSubmitting: false,
|
||||
failureOrPaymentSplitBill: optionOf(failureOrPayment),
|
||||
// Clear key on success, keep on failure for retry
|
||||
splitBillIdempotencyKey:
|
||||
failureOrPayment.isRight() ? null : idempotencyKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -813,6 +813,14 @@ mixin _$PaymentFormState {
|
||||
PaymentMethod? get paymentMethod => throw _privateConstructorUsedError;
|
||||
bool get isSubmitting => throw _privateConstructorUsedError;
|
||||
|
||||
/// Idempotency key untuk payment submission.
|
||||
/// Di-generate saat user tap "Bayar", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? get idempotencyKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Idempotency key untuk split bill submission.
|
||||
String? get splitBillIdempotencyKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of PaymentFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -834,6 +842,8 @@ abstract class $PaymentFormStateCopyWith<$Res> {
|
||||
Option<Either<OrderFailure, Payment>> failureOrPaymentSplitBill,
|
||||
PaymentMethod? paymentMethod,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
String? splitBillIdempotencyKey,
|
||||
});
|
||||
|
||||
$OrderCopyWith<$Res> get order;
|
||||
@@ -861,6 +871,8 @@ class _$PaymentFormStateCopyWithImpl<$Res, $Val extends PaymentFormState>
|
||||
Object? failureOrPaymentSplitBill = null,
|
||||
Object? paymentMethod = freezed,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
Object? splitBillIdempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -888,6 +900,14 @@ class _$PaymentFormStateCopyWithImpl<$Res, $Val extends PaymentFormState>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
splitBillIdempotencyKey: freezed == splitBillIdempotencyKey
|
||||
? _value.splitBillIdempotencyKey
|
||||
: splitBillIdempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -934,6 +954,8 @@ abstract class _$$PaymentFormStateImplCopyWith<$Res>
|
||||
Option<Either<OrderFailure, Payment>> failureOrPaymentSplitBill,
|
||||
PaymentMethod? paymentMethod,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
String? splitBillIdempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -962,6 +984,8 @@ class __$$PaymentFormStateImplCopyWithImpl<$Res>
|
||||
Object? failureOrPaymentSplitBill = null,
|
||||
Object? paymentMethod = freezed,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
Object? splitBillIdempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$PaymentFormStateImpl(
|
||||
@@ -989,6 +1013,14 @@ class __$$PaymentFormStateImplCopyWithImpl<$Res>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
splitBillIdempotencyKey: freezed == splitBillIdempotencyKey
|
||||
? _value.splitBillIdempotencyKey
|
||||
: splitBillIdempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1004,6 +1036,8 @@ class _$PaymentFormStateImpl implements _PaymentFormState {
|
||||
required this.failureOrPaymentSplitBill,
|
||||
this.paymentMethod,
|
||||
this.isSubmitting = false,
|
||||
this.idempotencyKey,
|
||||
this.splitBillIdempotencyKey,
|
||||
}) : _pendingItems = pendingItems;
|
||||
|
||||
@override
|
||||
@@ -1026,9 +1060,19 @@ class _$PaymentFormStateImpl implements _PaymentFormState {
|
||||
@JsonKey()
|
||||
final bool isSubmitting;
|
||||
|
||||
/// Idempotency key untuk payment submission.
|
||||
/// Di-generate saat user tap "Bayar", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
final String? idempotencyKey;
|
||||
|
||||
/// Idempotency key untuk split bill submission.
|
||||
@override
|
||||
final String? splitBillIdempotencyKey;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PaymentFormState(order: $order, pendingItems: $pendingItems, failureOrPayment: $failureOrPayment, failureOrPaymentSplitBill: $failureOrPaymentSplitBill, paymentMethod: $paymentMethod, isSubmitting: $isSubmitting)';
|
||||
return 'PaymentFormState(order: $order, pendingItems: $pendingItems, failureOrPayment: $failureOrPayment, failureOrPaymentSplitBill: $failureOrPaymentSplitBill, paymentMethod: $paymentMethod, isSubmitting: $isSubmitting, idempotencyKey: $idempotencyKey, splitBillIdempotencyKey: $splitBillIdempotencyKey)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1051,7 +1095,14 @@ class _$PaymentFormStateImpl implements _PaymentFormState {
|
||||
(identical(other.paymentMethod, paymentMethod) ||
|
||||
other.paymentMethod == paymentMethod) &&
|
||||
(identical(other.isSubmitting, isSubmitting) ||
|
||||
other.isSubmitting == isSubmitting));
|
||||
other.isSubmitting == isSubmitting) &&
|
||||
(identical(other.idempotencyKey, idempotencyKey) ||
|
||||
other.idempotencyKey == idempotencyKey) &&
|
||||
(identical(
|
||||
other.splitBillIdempotencyKey,
|
||||
splitBillIdempotencyKey,
|
||||
) ||
|
||||
other.splitBillIdempotencyKey == splitBillIdempotencyKey));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1063,6 +1114,8 @@ class _$PaymentFormStateImpl implements _PaymentFormState {
|
||||
failureOrPaymentSplitBill,
|
||||
paymentMethod,
|
||||
isSubmitting,
|
||||
idempotencyKey,
|
||||
splitBillIdempotencyKey,
|
||||
);
|
||||
|
||||
/// Create a copy of PaymentFormState
|
||||
@@ -1086,6 +1139,8 @@ abstract class _PaymentFormState implements PaymentFormState {
|
||||
failureOrPaymentSplitBill,
|
||||
final PaymentMethod? paymentMethod,
|
||||
final bool isSubmitting,
|
||||
final String? idempotencyKey,
|
||||
final String? splitBillIdempotencyKey,
|
||||
}) = _$PaymentFormStateImpl;
|
||||
|
||||
@override
|
||||
@@ -1101,6 +1156,16 @@ abstract class _PaymentFormState implements PaymentFormState {
|
||||
@override
|
||||
bool get isSubmitting;
|
||||
|
||||
/// Idempotency key untuk payment submission.
|
||||
/// Di-generate saat user tap "Bayar", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
String? get idempotencyKey;
|
||||
|
||||
/// Idempotency key untuk split bill submission.
|
||||
@override
|
||||
String? get splitBillIdempotencyKey;
|
||||
|
||||
/// Create a copy of PaymentFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
|
||||
@@ -9,6 +9,12 @@ class PaymentFormState with _$PaymentFormState {
|
||||
required Option<Either<OrderFailure, Payment>> failureOrPaymentSplitBill,
|
||||
PaymentMethod? paymentMethod,
|
||||
@Default(false) bool isSubmitting,
|
||||
/// Idempotency key untuk payment submission.
|
||||
/// Di-generate saat user tap "Bayar", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? idempotencyKey,
|
||||
/// Idempotency key untuk split bill submission.
|
||||
String? splitBillIdempotencyKey,
|
||||
}) = _PaymentFormState;
|
||||
|
||||
factory PaymentFormState.initial() => PaymentFormState(
|
||||
|
||||
@@ -39,12 +39,108 @@ class PrintStruckBloc extends Bloc<PrintStruckEvent, PrintStruckState> {
|
||||
),
|
||||
);
|
||||
},
|
||||
saveOrder: (e) async {
|
||||
cashier: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckSaveOrder(
|
||||
failureOrSuccess = await _printerRepository.printStruckCashier(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
payment: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckPayment(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
voided: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckVoid(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
splitBill: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckSplitBill(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
kitchen: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckKitchen(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
bar: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckBar(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isPrinting: false,
|
||||
failureOrPrintStruck: optionOf(failureOrSuccess),
|
||||
),
|
||||
);
|
||||
},
|
||||
checker: (e) async {
|
||||
Either<PrinterFailure, Unit> failureOrSuccess;
|
||||
|
||||
emit(state.copyWith(isPrinting: true, failureOrPrintStruck: none()));
|
||||
|
||||
failureOrSuccess = await _printerRepository.printStruckChecker(
|
||||
order: e.order,
|
||||
);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,5 +3,11 @@ part of 'print_struck_bloc.dart';
|
||||
@freezed
|
||||
class PrintStruckEvent with _$PrintStruckEvent {
|
||||
const factory PrintStruckEvent.order(Order order) = _Order;
|
||||
const factory PrintStruckEvent.saveOrder(Order order) = _SaveOrder;
|
||||
const factory PrintStruckEvent.cashier(Order order) = _Cashier;
|
||||
const factory PrintStruckEvent.payment(Order order) = _Payment;
|
||||
const factory PrintStruckEvent.voided(Order order) = _Voided;
|
||||
const factory PrintStruckEvent.checker(Order order) = _Checker;
|
||||
const factory PrintStruckEvent.kitchen(Order order) = _Kitchen;
|
||||
const factory PrintStruckEvent.bar(Order order) = _Bar;
|
||||
const factory PrintStruckEvent.splitBill(Order order) = _SplitBill;
|
||||
}
|
||||
|
||||
@@ -117,6 +117,13 @@ class PrinterFormBloc extends Bloc<PrinterFormEvent, PrinterFormState> {
|
||||
|
||||
final currentOutlet = await _outletRepository.currentOutlet();
|
||||
|
||||
// Ambil paper size dari DB, fallback ke state.paper jika belum tersimpan
|
||||
final savedPrinter = await _printerRepository.getPrinterByCode(e.code);
|
||||
final paper = savedPrinter.fold(
|
||||
(_) => int.tryParse(state.paper) ?? 58,
|
||||
(p) => int.tryParse(p.paper) ?? 58,
|
||||
);
|
||||
|
||||
List<int> printValue = [];
|
||||
|
||||
if (e.code == "receipt") {
|
||||
@@ -124,29 +131,34 @@ class PrinterFormBloc extends Bloc<PrinterFormEvent, PrinterFormState> {
|
||||
order: Order.mockOrder(),
|
||||
outlet: currentOutlet,
|
||||
cashierName: 'Kasir Test',
|
||||
paper: paper,
|
||||
);
|
||||
} else if (e.code == "checker") {
|
||||
printValue = await PrintUi().printChecker(
|
||||
order: Order.mockOrder(),
|
||||
outlet: currentOutlet,
|
||||
cashierName: 'Kasir Test',
|
||||
paper: paper,
|
||||
);
|
||||
} else if (e.code == 'kitchen') {
|
||||
printValue = await PrintUi().printKitchen(
|
||||
order: Order.mockOrder(),
|
||||
outlet: currentOutlet,
|
||||
cashierName: 'Kasir Test',
|
||||
paper: paper,
|
||||
);
|
||||
} else if (e.code == 'bar') {
|
||||
printValue = await PrintUi().printBar(
|
||||
order: Order.mockOrder(),
|
||||
outlet: currentOutlet,
|
||||
cashierName: 'Kasir Test',
|
||||
paper: paper,
|
||||
);
|
||||
} else if (e.code == 'ticket') {
|
||||
printValue = await PrintUi().printTicket(
|
||||
order: Order.mockOrder(),
|
||||
outlet: currentOutlet,
|
||||
paper: paper,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -154,7 +166,7 @@ class PrinterFormBloc extends Bloc<PrinterFormEvent, PrinterFormState> {
|
||||
code: e.code,
|
||||
name: state.name,
|
||||
address: e.macAccdress,
|
||||
paper: state.paper,
|
||||
paper: paper.toString(),
|
||||
type: state.type,
|
||||
);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(
|
||||
const ProductFailure.dynamicErrorMessage(
|
||||
'Database lokal belum siap. Silakan lakukan sinkronisasi data terlebih dahulu.',
|
||||
),
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../../common/data/refund_data.dart';
|
||||
import '../../../domain/order/order.dart';
|
||||
@@ -34,7 +35,15 @@ class RefundFormBloc extends Bloc<RefundFormEvent, RefundFormState> {
|
||||
submitted: (e) async {
|
||||
Either<OrderFailure, Unit>? failureOrRefund;
|
||||
|
||||
emit(state.copyWith(isSubmitting: true, failureOrRefund: none()));
|
||||
// Generate new idempotency key saat user intent (tap Refund)
|
||||
// Kalau sedang retry, pakai key yang sama
|
||||
final idempotencyKey = state.idempotencyKey ?? const Uuid().v4();
|
||||
|
||||
emit(state.copyWith(
|
||||
isSubmitting: true,
|
||||
failureOrRefund: none(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
));
|
||||
|
||||
failureOrRefund = await _repository.refundOrder(
|
||||
id: state.order.id,
|
||||
@@ -42,12 +51,15 @@ class RefundFormBloc extends Bloc<RefundFormEvent, RefundFormState> {
|
||||
? state.reason
|
||||
: state.refundReason?.value ?? '',
|
||||
refundAmount: state.order.totalAmount,
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSubmitting: false,
|
||||
failureOrRefund: optionOf(failureOrRefund),
|
||||
// Clear key on success, keep on failure for retry
|
||||
idempotencyKey: failureOrRefund.isRight() ? null : idempotencyKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -692,6 +692,11 @@ mixin _$RefundFormState {
|
||||
throw _privateConstructorUsedError;
|
||||
bool get isSubmitting => throw _privateConstructorUsedError;
|
||||
|
||||
/// Idempotency key untuk refund submission.
|
||||
/// Di-generate saat user tap "Refund", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? get idempotencyKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of RefundFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -712,6 +717,7 @@ abstract class $RefundFormStateCopyWith<$Res> {
|
||||
RefundReason? refundReason,
|
||||
Option<Either<OrderFailure, Unit>> failureOrRefund,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
$OrderCopyWith<$Res> get order;
|
||||
@@ -737,6 +743,7 @@ class _$RefundFormStateCopyWithImpl<$Res, $Val extends RefundFormState>
|
||||
Object? refundReason = freezed,
|
||||
Object? failureOrRefund = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -760,6 +767,10 @@ class _$RefundFormStateCopyWithImpl<$Res, $Val extends RefundFormState>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -791,6 +802,7 @@ abstract class _$$RefundFormStateImplCopyWith<$Res>
|
||||
RefundReason? refundReason,
|
||||
Option<Either<OrderFailure, Unit>> failureOrRefund,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -816,6 +828,7 @@ class __$$RefundFormStateImplCopyWithImpl<$Res>
|
||||
Object? refundReason = freezed,
|
||||
Object? failureOrRefund = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$RefundFormStateImpl(
|
||||
@@ -839,6 +852,10 @@ class __$$RefundFormStateImplCopyWithImpl<$Res>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -853,6 +870,7 @@ class _$RefundFormStateImpl implements _RefundFormState {
|
||||
this.refundReason,
|
||||
required this.failureOrRefund,
|
||||
this.isSubmitting = false,
|
||||
this.idempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -867,9 +885,15 @@ class _$RefundFormStateImpl implements _RefundFormState {
|
||||
@JsonKey()
|
||||
final bool isSubmitting;
|
||||
|
||||
/// Idempotency key untuk refund submission.
|
||||
/// Di-generate saat user tap "Refund", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
final String? idempotencyKey;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RefundFormState(order: $order, reason: $reason, refundReason: $refundReason, failureOrRefund: $failureOrRefund, isSubmitting: $isSubmitting)';
|
||||
return 'RefundFormState(order: $order, reason: $reason, refundReason: $refundReason, failureOrRefund: $failureOrRefund, isSubmitting: $isSubmitting, idempotencyKey: $idempotencyKey)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -884,7 +908,9 @@ class _$RefundFormStateImpl implements _RefundFormState {
|
||||
(identical(other.failureOrRefund, failureOrRefund) ||
|
||||
other.failureOrRefund == failureOrRefund) &&
|
||||
(identical(other.isSubmitting, isSubmitting) ||
|
||||
other.isSubmitting == isSubmitting));
|
||||
other.isSubmitting == isSubmitting) &&
|
||||
(identical(other.idempotencyKey, idempotencyKey) ||
|
||||
other.idempotencyKey == idempotencyKey));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -895,6 +921,7 @@ class _$RefundFormStateImpl implements _RefundFormState {
|
||||
refundReason,
|
||||
failureOrRefund,
|
||||
isSubmitting,
|
||||
idempotencyKey,
|
||||
);
|
||||
|
||||
/// Create a copy of RefundFormState
|
||||
@@ -916,6 +943,7 @@ abstract class _RefundFormState implements RefundFormState {
|
||||
final RefundReason? refundReason,
|
||||
required final Option<Either<OrderFailure, Unit>> failureOrRefund,
|
||||
final bool isSubmitting,
|
||||
final String? idempotencyKey,
|
||||
}) = _$RefundFormStateImpl;
|
||||
|
||||
@override
|
||||
@@ -929,6 +957,12 @@ abstract class _RefundFormState implements RefundFormState {
|
||||
@override
|
||||
bool get isSubmitting;
|
||||
|
||||
/// Idempotency key untuk refund submission.
|
||||
/// Di-generate saat user tap "Refund", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
@override
|
||||
String? get idempotencyKey;
|
||||
|
||||
/// Create a copy of RefundFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
|
||||
@@ -8,6 +8,10 @@ class RefundFormState with _$RefundFormState {
|
||||
RefundReason? refundReason,
|
||||
required Option<Either<OrderFailure, Unit>> failureOrRefund,
|
||||
@Default(false) bool isSubmitting,
|
||||
/// Idempotency key untuk refund submission.
|
||||
/// Di-generate saat user tap "Refund", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses.
|
||||
String? idempotencyKey,
|
||||
}) = _RefundFormState;
|
||||
|
||||
factory RefundFormState.initial() => RefundFormState(
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/category/category.dart';
|
||||
import '../../../domain/product/product.dart';
|
||||
|
||||
part 'sync_setting_event.dart';
|
||||
part 'sync_setting_state.dart';
|
||||
part 'sync_setting_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class SyncSettingBloc extends Bloc<SyncSettingEvent, SyncSettingState> {
|
||||
final IProductRepository _productRepository;
|
||||
final ICategoryRepository _categoryRepository;
|
||||
|
||||
SyncSettingBloc(this._productRepository, this._categoryRepository)
|
||||
: super(SyncSettingState.initial()) {
|
||||
on<SyncSettingEvent>(_onSyncSettingEvent);
|
||||
}
|
||||
|
||||
Future<void> _onSyncSettingEvent(
|
||||
SyncSettingEvent event,
|
||||
Emitter<SyncSettingState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
loadStats: (e) => _onLoadStats(emit),
|
||||
syncAllData: (e) => _onSyncAllData(emit),
|
||||
clearAllData: (e) => _onClearAllData(emit),
|
||||
syncProducts: (e) => _onSyncProducts(emit),
|
||||
syncCategories: (e) => _onSyncCategories(emit),
|
||||
clearCategories: (e) => _onClearCategories(emit),
|
||||
clearProducts: (e) => _onClearProducts(emit),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onLoadStats(Emitter<SyncSettingState> emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: true,
|
||||
failureOptionProduct: none(),
|
||||
failureOptionCategory: none(),
|
||||
),
|
||||
);
|
||||
|
||||
final productStats = await _productRepository.getDatabaseStats();
|
||||
final categoryStats = await _categoryRepository.getDatabaseStats();
|
||||
|
||||
productStats.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionProduct: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(data) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
productStats: data,
|
||||
failureOptionProduct: none(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
categoryStats.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionCategory: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(data) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
categoryStats: data,
|
||||
failureOptionCategory: none(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSyncAllData(Emitter<SyncSettingState> emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: true,
|
||||
failureOptionSyncCategory: none(),
|
||||
failureOptionSyncProduct: none(),
|
||||
),
|
||||
);
|
||||
|
||||
// Sync categories first
|
||||
final categoryResult = await _categoryRepository.syncAllCategories();
|
||||
|
||||
bool categorySuccess = false;
|
||||
categoryResult.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(failureOptionSyncCategory: optionOf(left(failure))),
|
||||
);
|
||||
},
|
||||
(success) {
|
||||
categorySuccess = true;
|
||||
emit(
|
||||
state.copyWith(failureOptionSyncCategory: optionOf(right(success))),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Only sync products if categories synced successfully
|
||||
if (categorySuccess) {
|
||||
final productResult = await _productRepository.syncAllProducts();
|
||||
|
||||
productResult.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
failureOptionSyncProduct: optionOf(left(failure)),
|
||||
),
|
||||
);
|
||||
},
|
||||
(success) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
failureOptionSyncProduct: optionOf(right(success)),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
emit(state.copyWith(isSyncing: false));
|
||||
}
|
||||
|
||||
// Reload stats after sync
|
||||
add(const SyncSettingEvent.loadStats());
|
||||
}
|
||||
|
||||
Future<void> _onClearAllData(Emitter<SyncSettingState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
try {
|
||||
// Clear products and categories
|
||||
await _productRepository.clearAllProducts();
|
||||
await _categoryRepository.clearAllCategories();
|
||||
|
||||
// Clear caches
|
||||
_productRepository.clearCache();
|
||||
_categoryRepository.clearCache();
|
||||
|
||||
emit(state.copyWith(isLoading: false));
|
||||
|
||||
// Reload stats after clearing
|
||||
add(const SyncSettingEvent.loadStats());
|
||||
} catch (e) {
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSyncProducts(Emitter<SyncSettingState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, failureOptionSyncProduct: none()));
|
||||
|
||||
final result = await _productRepository.syncAllProducts();
|
||||
|
||||
result.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionSyncProduct: optionOf(left(failure)),
|
||||
),
|
||||
);
|
||||
},
|
||||
(success) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionSyncProduct: optionOf(right(success)),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Reload stats after sync
|
||||
add(const SyncSettingEvent.loadStats());
|
||||
}
|
||||
|
||||
Future<void> _onSyncCategories(Emitter<SyncSettingState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, failureOptionSyncCategory: none()));
|
||||
|
||||
final result = await _categoryRepository.syncAllCategories();
|
||||
|
||||
result.fold(
|
||||
(failure) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionSyncCategory: optionOf(left(failure)),
|
||||
),
|
||||
);
|
||||
},
|
||||
(success) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
failureOptionSyncCategory: optionOf(right(success)),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Reload stats after sync
|
||||
add(const SyncSettingEvent.loadStats());
|
||||
}
|
||||
|
||||
Future<void> _onClearCategories(Emitter<SyncSettingState> emit) async {
|
||||
await _categoryRepository.clearAllCategories();
|
||||
_categoryRepository.clearCache();
|
||||
}
|
||||
|
||||
Future<void> _onClearProducts(Emitter<SyncSettingState> emit) async {
|
||||
await _productRepository.clearAllProducts();
|
||||
_productRepository.clearCache();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
part of 'sync_setting_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class SyncSettingEvent with _$SyncSettingEvent {
|
||||
const factory SyncSettingEvent.loadStats() = _LoadStats;
|
||||
const factory SyncSettingEvent.syncAllData() = _SyncAllData;
|
||||
const factory SyncSettingEvent.clearAllData() = _ClearAllData;
|
||||
const factory SyncSettingEvent.syncProducts() = _SyncProducts;
|
||||
const factory SyncSettingEvent.syncCategories() = _SyncCategories;
|
||||
const factory SyncSettingEvent.clearCategories() = _ClearCategories;
|
||||
const factory SyncSettingEvent.clearProducts() = _ClearProducts;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
part of 'sync_setting_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class SyncSettingState with _$SyncSettingState {
|
||||
factory SyncSettingState({
|
||||
required Map<String, dynamic> productStats,
|
||||
required Map<String, dynamic> categoryStats,
|
||||
required Option<CategoryFailure> failureOptionCategory,
|
||||
required Option<ProductFailure> failureOptionProduct,
|
||||
required Option<Either<ProductFailure, String>> failureOptionSyncProduct,
|
||||
required Option<Either<CategoryFailure, String>> failureOptionSyncCategory,
|
||||
@Default(false) bool isSyncing,
|
||||
@Default(false) bool isLoading,
|
||||
}) = _SyncSettingState;
|
||||
|
||||
factory SyncSettingState.initial() => SyncSettingState(
|
||||
productStats: {},
|
||||
categoryStats: {},
|
||||
failureOptionCategory: none(),
|
||||
failureOptionProduct: none(),
|
||||
failureOptionSyncProduct: none(),
|
||||
failureOptionSyncCategory: none(),
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../../common/types/void_type.dart';
|
||||
import '../../../domain/order/order.dart';
|
||||
@@ -49,9 +51,10 @@ class VoidFormBloc extends Bloc<VoidFormEvent, VoidFormState> {
|
||||
// Recalculate total price
|
||||
int newTotal = 0;
|
||||
for (var entry in newQuantities.entries) {
|
||||
final item = state.pendingItems.firstWhere(
|
||||
final item = state.pendingItems.firstWhereOrNull(
|
||||
(item) => item.id == entry.key,
|
||||
);
|
||||
if (item == null) continue;
|
||||
newTotal += item.unitPrice.toInt() * entry.value;
|
||||
}
|
||||
|
||||
@@ -71,16 +74,20 @@ class VoidFormBloc extends Bloc<VoidFormEvent, VoidFormState> {
|
||||
|
||||
if (state.voidType.isItem) {
|
||||
state.selectedItemQuantities.forEach((itemId, voidQty) {
|
||||
final originalItem = state.order.orderItems.firstWhere(
|
||||
final originalItem = state.order.orderItems.firstWhereOrNull(
|
||||
(item) => item.id == itemId,
|
||||
);
|
||||
|
||||
if (originalItem == null) return;
|
||||
|
||||
voidItems.add(
|
||||
OrderItem(
|
||||
id: originalItem.id,
|
||||
orderId: originalItem.orderId,
|
||||
productId: originalItem.productId,
|
||||
productName: originalItem.productName,
|
||||
categoryId: originalItem.categoryId,
|
||||
categoryName: originalItem.status,
|
||||
productVariantId: originalItem.productVariantId,
|
||||
productVariantName: originalItem.productVariantName,
|
||||
quantity: voidQty,
|
||||
@@ -93,18 +100,28 @@ class VoidFormBloc extends Bloc<VoidFormEvent, VoidFormState> {
|
||||
updatedAt: originalItem.updatedAt,
|
||||
printerType: originalItem.printerType,
|
||||
paidQuantity: originalItem.paidQuantity,
|
||||
printToChecker: originalItem.printToChecker,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
emit(state.copyWith(isSubmitting: true, failureOrVoid: none()));
|
||||
// Generate new idempotency key saat user intent (tap Void)
|
||||
// Kalau sedang retry, pakai key yang sama
|
||||
final idempotencyKey = state.idempotencyKey ?? const Uuid().v4();
|
||||
|
||||
emit(state.copyWith(
|
||||
isSubmitting: true,
|
||||
failureOrVoid: none(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
));
|
||||
|
||||
failureOrVoid = await _repository.voidOrder(
|
||||
orderId: state.order.id,
|
||||
reason: state.voidReason ?? '',
|
||||
orderItems: voidItems,
|
||||
type: state.voidType.toStringType(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
emit(
|
||||
@@ -112,6 +129,8 @@ class VoidFormBloc extends Bloc<VoidFormEvent, VoidFormState> {
|
||||
isSubmitting: false,
|
||||
failureOrVoid: optionOf(failureOrVoid),
|
||||
voidItems: state.voidType.isItem ? voidItems : state.pendingItems,
|
||||
// Clear key on success, keep on failure for retry
|
||||
idempotencyKey: failureOrVoid.isRight() ? null : idempotencyKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1256,6 +1256,11 @@ mixin _$VoidFormState {
|
||||
throw _privateConstructorUsedError;
|
||||
bool get isSubmitting => throw _privateConstructorUsedError;
|
||||
|
||||
/// Idempotency key untuk void submission.
|
||||
/// Di-generate saat user tap "Void", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses atau clearState.
|
||||
String? get idempotencyKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of VoidFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -1280,6 +1285,7 @@ abstract class $VoidFormStateCopyWith<$Res> {
|
||||
int totalPriceVoid,
|
||||
Option<Either<OrderFailure, Unit>> failureOrVoid,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
$OrderCopyWith<$Res> get order;
|
||||
@@ -1309,6 +1315,7 @@ class _$VoidFormStateCopyWithImpl<$Res, $Val extends VoidFormState>
|
||||
Object? totalPriceVoid = null,
|
||||
Object? failureOrVoid = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -1348,6 +1355,10 @@ class _$VoidFormStateCopyWithImpl<$Res, $Val extends VoidFormState>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -1383,6 +1394,7 @@ abstract class _$$VoidFormStateImplCopyWith<$Res>
|
||||
int totalPriceVoid,
|
||||
Option<Either<OrderFailure, Unit>> failureOrVoid,
|
||||
bool isSubmitting,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -1412,6 +1424,7 @@ class __$$VoidFormStateImplCopyWithImpl<$Res>
|
||||
Object? totalPriceVoid = null,
|
||||
Object? failureOrVoid = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? idempotencyKey = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$VoidFormStateImpl(
|
||||
@@ -1451,6 +1464,10 @@ class __$$VoidFormStateImplCopyWithImpl<$Res>
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
idempotencyKey: freezed == idempotencyKey
|
||||
? _value.idempotencyKey
|
||||
: idempotencyKey // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1469,6 +1486,7 @@ class _$VoidFormStateImpl implements _VoidFormState {
|
||||
required this.totalPriceVoid,
|
||||
required this.failureOrVoid,
|
||||
this.isSubmitting = false,
|
||||
this.idempotencyKey,
|
||||
}) : _pendingItems = pendingItems,
|
||||
_voidItems = voidItems,
|
||||
_selectedItemQuantities = selectedItemQuantities;
|
||||
@@ -1512,9 +1530,15 @@ class _$VoidFormStateImpl implements _VoidFormState {
|
||||
@JsonKey()
|
||||
final bool isSubmitting;
|
||||
|
||||
/// Idempotency key untuk void submission.
|
||||
/// Di-generate saat user tap "Void", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses atau clearState.
|
||||
@override
|
||||
final String? idempotencyKey;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VoidFormState(order: $order, pendingItems: $pendingItems, voidItems: $voidItems, voidType: $voidType, selectedItemQuantities: $selectedItemQuantities, voidReason: $voidReason, totalPriceVoid: $totalPriceVoid, failureOrVoid: $failureOrVoid, isSubmitting: $isSubmitting)';
|
||||
return 'VoidFormState(order: $order, pendingItems: $pendingItems, voidItems: $voidItems, voidType: $voidType, selectedItemQuantities: $selectedItemQuantities, voidReason: $voidReason, totalPriceVoid: $totalPriceVoid, failureOrVoid: $failureOrVoid, isSubmitting: $isSubmitting, idempotencyKey: $idempotencyKey)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1544,7 +1568,9 @@ class _$VoidFormStateImpl implements _VoidFormState {
|
||||
(identical(other.failureOrVoid, failureOrVoid) ||
|
||||
other.failureOrVoid == failureOrVoid) &&
|
||||
(identical(other.isSubmitting, isSubmitting) ||
|
||||
other.isSubmitting == isSubmitting));
|
||||
other.isSubmitting == isSubmitting) &&
|
||||
(identical(other.idempotencyKey, idempotencyKey) ||
|
||||
other.idempotencyKey == idempotencyKey));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1559,6 +1585,7 @@ class _$VoidFormStateImpl implements _VoidFormState {
|
||||
totalPriceVoid,
|
||||
failureOrVoid,
|
||||
isSubmitting,
|
||||
idempotencyKey,
|
||||
);
|
||||
|
||||
/// Create a copy of VoidFormState
|
||||
@@ -1581,6 +1608,7 @@ abstract class _VoidFormState implements VoidFormState {
|
||||
required final int totalPriceVoid,
|
||||
required final Option<Either<OrderFailure, Unit>> failureOrVoid,
|
||||
final bool isSubmitting,
|
||||
final String? idempotencyKey,
|
||||
}) = _$VoidFormStateImpl;
|
||||
|
||||
@override
|
||||
@@ -1602,6 +1630,12 @@ abstract class _VoidFormState implements VoidFormState {
|
||||
@override
|
||||
bool get isSubmitting;
|
||||
|
||||
/// Idempotency key untuk void submission.
|
||||
/// Di-generate saat user tap "Void", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses atau clearState.
|
||||
@override
|
||||
String? get idempotencyKey;
|
||||
|
||||
/// Create a copy of VoidFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
|
||||
@@ -12,6 +12,10 @@ class VoidFormState with _$VoidFormState {
|
||||
required int totalPriceVoid,
|
||||
required Option<Either<OrderFailure, Unit>> failureOrVoid,
|
||||
@Default(false) bool isSubmitting,
|
||||
/// Idempotency key untuk void submission.
|
||||
/// Di-generate saat user tap "Void", dipakai ulang saat retry,
|
||||
/// di-clear setelah sukses atau clearState.
|
||||
String? idempotencyKey,
|
||||
}) = _VoidFormState;
|
||||
|
||||
factory VoidFormState.initial() => VoidFormState(
|
||||
|
||||
@@ -16,6 +16,7 @@ import 'interceptors/bad_network_interceptor.dart';
|
||||
import 'interceptors/bad_request_interceptor.dart';
|
||||
import 'interceptors/connection_timeout_interceptor.dart';
|
||||
import 'interceptors/crashlytic_interceptor.dart';
|
||||
import 'interceptors/idempotency_interceptor.dart';
|
||||
import 'interceptors/internal_server_interceptor.dart';
|
||||
import 'interceptors/not_found_interceptor.dart';
|
||||
import 'interceptors/unauthorized_interceptor.dart';
|
||||
@@ -30,6 +31,7 @@ class ApiClient {
|
||||
_dio.options.connectTimeout = const Duration(seconds: 20);
|
||||
_dio.options.validateStatus = (status) =>
|
||||
status != null && status >= 200 && status < 500;
|
||||
_dio.interceptors.add(IdempotencyInterceptor(_dio));
|
||||
_dio.interceptors.add(BadNetworkErrorInterceptor());
|
||||
_dio.interceptors.add(BadRequestErrorInterceptor());
|
||||
_dio.interceptors.add(InternalServerErrorInterceptor());
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||
class CrashlyticsInterceptor extends Interceptor {
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
// Log semua error ke Crashlytics
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
err,
|
||||
err.stackTrace,
|
||||
@@ -46,6 +45,32 @@ class CrashlyticsInterceptor extends Interceptor {
|
||||
'Status Code: ${err.response?.statusCode ?? 'N/A'}',
|
||||
'Error Type: ${err.type.name}',
|
||||
'Message: ${err.message ?? 'No message'}',
|
||||
// Tambahan
|
||||
'Request Data: ${_sanitizeData(err.requestOptions.data)}',
|
||||
'Response Body: ${err.response?.data ?? 'No response'}',
|
||||
'Headers: ${err.requestOptions.headers.entries.where((e) => e.key.toLowerCase() != 'authorization').toList()}',
|
||||
];
|
||||
}
|
||||
|
||||
/// Hindari log data sensitif
|
||||
dynamic _sanitizeData(dynamic data) {
|
||||
if (data == null) return 'No data';
|
||||
if (data is Map) {
|
||||
final sanitized = Map.from(data);
|
||||
const sensitiveKeys = [
|
||||
'password',
|
||||
'token',
|
||||
'secret',
|
||||
'pin',
|
||||
'card_number',
|
||||
];
|
||||
for (final key in sensitiveKeys) {
|
||||
if (sanitized.containsKey(key)) {
|
||||
sanitized[key] = '***';
|
||||
}
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
/// Interceptor yang secara otomatis menambahkan header X-Idempotency-Key
|
||||
/// untuk endpoint-endpoint kritis yang memerlukan idempotency.
|
||||
///
|
||||
/// Key sebaiknya di-generate di level BLoC/Cubit saat user trigger action,
|
||||
/// lalu dikirim via headers. Interceptor ini hanya berfungsi sebagai fallback
|
||||
/// jika key belum di-set.
|
||||
///
|
||||
/// Jika response 409 dengan error code `request_in_progress`, interceptor
|
||||
/// akan retry setelah delay 1-2 detik.
|
||||
class IdempotencyInterceptor extends Interceptor {
|
||||
static const _headerKey = 'X-Idempotency-Key';
|
||||
static const _replayHeader = 'X-Idempotent-Replay';
|
||||
|
||||
// Endpoints that require idempotency keys (exact match)
|
||||
static const _idempotentPaths = [
|
||||
'/api/v1/payments',
|
||||
'/api/v1/orders/void',
|
||||
];
|
||||
|
||||
// Endpoints that require idempotency keys (pattern match)
|
||||
static final _idempotentPathPatterns = [
|
||||
RegExp(r'/api/v1/orders/.+/add-items$'),
|
||||
RegExp(r'/api/v1/orders/.+/refund$'),
|
||||
RegExp(r'/api/v1/payments/.+/refund$'),
|
||||
];
|
||||
|
||||
static const _maxRetries = 3;
|
||||
static const _retryDelay = Duration(seconds: 2);
|
||||
|
||||
final Dio _dio;
|
||||
|
||||
IdempotencyInterceptor(this._dio);
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
if (options.method == 'POST' && _requiresIdempotencyKey(options.path)) {
|
||||
// Gunakan key yang sudah di-set dari BLoC, atau generate baru sebagai fallback
|
||||
options.headers[_headerKey] ??= const Uuid().v4();
|
||||
}
|
||||
handler.next(options);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) {
|
||||
// Log jika response adalah replay dari request sebelumnya
|
||||
final isReplay = response.headers.value(_replayHeader);
|
||||
if (isReplay == 'true') {
|
||||
// Response ini adalah hasil dari request pertama yang sudah diproses.
|
||||
// Treat as success — tidak perlu perlakuan khusus.
|
||||
}
|
||||
handler.next(response);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) async {
|
||||
final response = err.response;
|
||||
final options = err.requestOptions;
|
||||
|
||||
if (response == null) {
|
||||
handler.next(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle 409 Conflict with request_in_progress
|
||||
if (response.statusCode == 409 &&
|
||||
_isRequestInProgress(response.data) &&
|
||||
_requiresIdempotencyKey(options.path)) {
|
||||
final retryCount = options.extra['_idempotency_retry_count'] ?? 0;
|
||||
|
||||
if (retryCount < _maxRetries) {
|
||||
await Future.delayed(_retryDelay);
|
||||
|
||||
options.extra['_idempotency_retry_count'] = retryCount + 1;
|
||||
|
||||
try {
|
||||
final retryResponse = await _dio.fetch(options);
|
||||
handler.resolve(retryResponse);
|
||||
} on DioException catch (e) {
|
||||
handler.next(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
handler.next(err);
|
||||
}
|
||||
|
||||
bool _requiresIdempotencyKey(String path) {
|
||||
if (_idempotentPaths.any((p) => path.endsWith(p))) return true;
|
||||
if (_idempotentPathPatterns.any((r) => r.hasMatch(path))) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isRequestInProgress(dynamic data) {
|
||||
if (data is Map<String, dynamic>) {
|
||||
final errorCode = data['error_code'] ?? data['code'] ?? '';
|
||||
return errorCode == 'request_in_progress';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import '../../env.dart';
|
||||
import '../../injection.dart';
|
||||
|
||||
class AppConstant {
|
||||
static const String appName = "Apskel POS";
|
||||
static const String dbName = "apskel_pos.db";
|
||||
static String dbName = getIt<Env>().dbName;
|
||||
static const int cacheExpire = 10; // in minutes
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class DatabaseHelper {
|
||||
|
||||
return await openDatabase(
|
||||
path,
|
||||
version: 2, // Updated version for categories table
|
||||
version: 2,
|
||||
onCreate: _onCreate,
|
||||
onUpgrade: _onUpgrade,
|
||||
);
|
||||
@@ -38,6 +38,7 @@ class DatabaseHelper {
|
||||
business_type TEXT,
|
||||
image_url TEXT,
|
||||
printer_type TEXT,
|
||||
print_to_checker INTEGER DEFAULT 0,
|
||||
metadata TEXT,
|
||||
is_active INTEGER,
|
||||
created_at TEXT,
|
||||
@@ -68,6 +69,7 @@ class DatabaseHelper {
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
business_type TEXT,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
metadata TEXT,
|
||||
is_active INTEGER DEFAULT 1,
|
||||
created_at TEXT,
|
||||
@@ -109,7 +111,7 @@ class DatabaseHelper {
|
||||
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
|
||||
if (oldVersion < 2) {
|
||||
await db.execute(
|
||||
'ALTER TABLE categories ADD COLUMN "order" INTEGER DEFAULT 0',
|
||||
'ALTER TABLE products ADD COLUMN print_to_checker INTEGER DEFAULT 0',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
@module
|
||||
abstract class FirebaseDi {
|
||||
@lazySingleton
|
||||
FirebaseMessaging get messaging => FirebaseMessaging.instance;
|
||||
|
||||
@lazySingleton
|
||||
FlutterLocalNotificationsPlugin get localNotifications =>
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
@lazySingleton
|
||||
DeviceInfoPlugin get deviceInfo => DeviceInfoPlugin();
|
||||
|
||||
@preResolve
|
||||
Future<PackageInfo> get packageInfo => PackageInfo.fromPlatform();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
@lazySingleton
|
||||
class DeviceInfoService {
|
||||
DeviceInfoService(this._deviceInfo, this._packageInfo);
|
||||
|
||||
final DeviceInfoPlugin _deviceInfo;
|
||||
final PackageInfo _packageInfo;
|
||||
|
||||
String get appVersion => '${_packageInfo.version}+${_packageInfo.buildNumber}';
|
||||
|
||||
Future<Map<String, String>> getDevicePayload() async {
|
||||
final info = await _getDeviceInfo();
|
||||
return {
|
||||
'device_id': info['device_id'] ?? '',
|
||||
'device_name': info['device_name'] ?? '',
|
||||
'device_type': info['device_type'] ?? 'mobile',
|
||||
'platform': _getPlatform(),
|
||||
'app_version': appVersion,
|
||||
'os_version': info['os_version'] ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
String _getPlatform() {
|
||||
if (Platform.isAndroid) return 'android';
|
||||
if (Platform.isIOS) return 'ios';
|
||||
return 'web';
|
||||
}
|
||||
|
||||
Future<Map<String, String>> _getDeviceInfo() async {
|
||||
if (Platform.isAndroid) {
|
||||
final android = await _deviceInfo.androidInfo;
|
||||
return {
|
||||
'device_id': android.id,
|
||||
'device_name': '${android.manufacturer} ${android.model}',
|
||||
'device_type': _resolveDeviceType(android.model),
|
||||
'os_version': 'Android ${android.version.release} (SDK ${android.version.sdkInt})',
|
||||
};
|
||||
} else if (Platform.isIOS) {
|
||||
final ios = await _deviceInfo.iosInfo;
|
||||
return {
|
||||
'device_id': ios.identifierForVendor ?? '',
|
||||
'device_name': ios.name,
|
||||
'device_type': _resolveDeviceType(ios.model),
|
||||
'os_version': '${ios.systemName} ${ios.systemVersion}',
|
||||
};
|
||||
}
|
||||
return {'device_type': 'desktop'};
|
||||
}
|
||||
|
||||
/// Deteksi device_type berdasarkan nama model
|
||||
/// Nilai valid: mobile | tablet | desktop
|
||||
String _resolveDeviceType(String model) {
|
||||
final lower = model.toLowerCase();
|
||||
if (lower.contains('tablet') || lower.contains('tab') || lower.contains('ipad')) {
|
||||
return 'tablet';
|
||||
}
|
||||
return 'mobile';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
/// Background message handler — harus top-level function
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
log('[FCM] Background message: ${message.messageId}');
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class FcmService {
|
||||
FcmService(this._messaging, this._localNotifications);
|
||||
|
||||
final FirebaseMessaging _messaging;
|
||||
final FlutterLocalNotificationsPlugin _localNotifications;
|
||||
|
||||
/// Inisialisasi FCM: minta permission, set handler, ambil token
|
||||
Future<void> initialize() async {
|
||||
// Setup local notifications
|
||||
await _setupLocalNotifications();
|
||||
|
||||
// Register background handler
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
|
||||
// Minta permission notifikasi (iOS & Android 13+)
|
||||
final settings = await _messaging.requestPermission(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
provisional: false,
|
||||
);
|
||||
|
||||
log('[FCM] Permission status: ${settings.authorizationStatus}');
|
||||
|
||||
if (settings.authorizationStatus == AuthorizationStatus.authorized ||
|
||||
settings.authorizationStatus == AuthorizationStatus.provisional) {
|
||||
await _setupTokenHandling();
|
||||
_setupForegroundHandler();
|
||||
_setupOpenedAppHandler();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setupLocalNotifications() async {
|
||||
const androidSettings = AndroidInitializationSettings('@drawable/ic_notification');
|
||||
const iosSettings = DarwinInitializationSettings(
|
||||
requestAlertPermission: true,
|
||||
requestBadgePermission: true,
|
||||
requestSoundPermission: true,
|
||||
);
|
||||
|
||||
const initSettings = InitializationSettings(
|
||||
android: androidSettings,
|
||||
iOS: iosSettings,
|
||||
);
|
||||
|
||||
await _localNotifications.initialize(
|
||||
initSettings,
|
||||
onDidReceiveNotificationResponse: _onNotificationTapped,
|
||||
);
|
||||
|
||||
// Android notification channel
|
||||
const channel = AndroidNotificationChannel(
|
||||
'high_importance_channel',
|
||||
'High Importance Notifications',
|
||||
description: 'This channel is used for important notifications.',
|
||||
importance: Importance.high,
|
||||
playSound: true,
|
||||
);
|
||||
|
||||
await _localNotifications
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
void _onNotificationTapped(NotificationResponse response) {
|
||||
log('[FCM] Notification tapped: ${response.payload}');
|
||||
// TODO: handle navigation berdasarkan payload
|
||||
}
|
||||
|
||||
Future<void> _setupTokenHandling() async {
|
||||
final token = await getToken();
|
||||
log('========================================');
|
||||
log('[FCM] TOKEN: $token');
|
||||
log('========================================');
|
||||
// TODO: kirim token ke server jika diperlukan
|
||||
|
||||
_messaging.onTokenRefresh.listen((newToken) {
|
||||
log('========================================');
|
||||
log('[FCM] TOKEN REFRESHED: $newToken');
|
||||
log('========================================');
|
||||
// TODO: kirim token baru ke server jika diperlukan
|
||||
});
|
||||
}
|
||||
|
||||
void _setupForegroundHandler() {
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
log('[FCM] Foreground message: ${message.messageId}');
|
||||
log('[FCM] Title: ${message.notification?.title}');
|
||||
log('[FCM] Body: ${message.notification?.body}');
|
||||
log('[FCM] Data: ${message.data}');
|
||||
|
||||
// Tampilkan notifikasi lokal saat app di foreground
|
||||
final notification = message.notification;
|
||||
if (notification != null) {
|
||||
_showLocalNotification(
|
||||
id: message.hashCode,
|
||||
title: notification.title ?? '',
|
||||
body: notification.body ?? '',
|
||||
payload: message.data.toString(),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _setupOpenedAppHandler() {
|
||||
// App dibuka dari notifikasi saat terminated
|
||||
_messaging.getInitialMessage().then((RemoteMessage? message) {
|
||||
if (message != null) {
|
||||
log('[FCM] App opened from terminated via: ${message.messageId}');
|
||||
_handleMessageNavigation(message);
|
||||
}
|
||||
});
|
||||
|
||||
// App dibuka dari notifikasi saat background
|
||||
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||
log('[FCM] App opened from background via: ${message.messageId}');
|
||||
_handleMessageNavigation(message);
|
||||
});
|
||||
}
|
||||
|
||||
void _handleMessageNavigation(RemoteMessage message) {
|
||||
// TODO: tambahkan logika navigasi berdasarkan message.data
|
||||
log('[FCM] Handle navigation for: ${message.data}');
|
||||
}
|
||||
|
||||
Future<void> _showLocalNotification({
|
||||
required int id,
|
||||
required String title,
|
||||
required String body,
|
||||
String? payload,
|
||||
}) async {
|
||||
const androidDetails = AndroidNotificationDetails(
|
||||
'high_importance_channel',
|
||||
'High Importance Notifications',
|
||||
channelDescription: 'This channel is used for important notifications.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
showWhen: true,
|
||||
playSound: true,
|
||||
enableVibration: true,
|
||||
enableLights: true,
|
||||
fullScreenIntent: true,
|
||||
icon: 'ic_notification',
|
||||
);
|
||||
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentSound: true,
|
||||
);
|
||||
|
||||
const details = NotificationDetails(
|
||||
android: androidDetails,
|
||||
iOS: iosDetails,
|
||||
);
|
||||
|
||||
await _localNotifications.show(id, title, body, details, payload: payload);
|
||||
log('[FCM] Local notification shown: $title');
|
||||
}
|
||||
|
||||
/// Ambil FCM token perangkat
|
||||
Future<String?> getToken() async {
|
||||
try {
|
||||
return await _messaging.getToken();
|
||||
} catch (e) {
|
||||
log('[FCM] Failed to get token: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribe ke topic tertentu
|
||||
Future<void> subscribeToTopic(String topic) async {
|
||||
await _messaging.subscribeToTopic(topic);
|
||||
log('[FCM] Subscribed to topic: $topic');
|
||||
}
|
||||
|
||||
/// Unsubscribe dari topic tertentu
|
||||
Future<void> unsubscribeFromTopic(String topic) async {
|
||||
await _messaging.unsubscribeFromTopic(topic);
|
||||
log('[FCM] Unsubscribed from topic: $topic');
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
part of 'theme.dart';
|
||||
|
||||
class AppStyle {
|
||||
static TextStyle xs = TextStyle(color: AppColor.black, fontSize: 11);
|
||||
static TextStyle xs = const TextStyle(color: AppColor.black, fontSize: 11);
|
||||
|
||||
static TextStyle sm = TextStyle(color: AppColor.black, fontSize: 12);
|
||||
static TextStyle sm = const TextStyle(color: AppColor.black, fontSize: 12);
|
||||
|
||||
static TextStyle md = TextStyle(color: AppColor.black, fontSize: 14);
|
||||
static TextStyle md = const TextStyle(color: AppColor.black, fontSize: 14);
|
||||
|
||||
static TextStyle lg = TextStyle(color: AppColor.black, fontSize: 16);
|
||||
static TextStyle lg = const TextStyle(color: AppColor.black, fontSize: 16);
|
||||
|
||||
static TextStyle xl = TextStyle(color: AppColor.black, fontSize: 18);
|
||||
static TextStyle xl = const TextStyle(color: AppColor.black, fontSize: 18);
|
||||
|
||||
static TextStyle xxl = TextStyle(color: AppColor.black, fontSize: 20);
|
||||
static TextStyle xxl = const TextStyle(color: AppColor.black, fontSize: 20);
|
||||
|
||||
static TextStyle h6 = TextStyle(color: AppColor.black, fontSize: 22);
|
||||
static TextStyle h6 = const TextStyle(color: AppColor.black, fontSize: 22);
|
||||
|
||||
static TextStyle h5 = TextStyle(color: AppColor.black, fontSize: 24);
|
||||
static TextStyle h5 = const TextStyle(color: AppColor.black, fontSize: 24);
|
||||
|
||||
static TextStyle h4 = TextStyle(color: AppColor.black, fontSize: 26);
|
||||
static TextStyle h4 = const TextStyle(color: AppColor.black, fontSize: 26);
|
||||
|
||||
static TextStyle h3 = TextStyle(color: AppColor.black, fontSize: 28);
|
||||
static TextStyle h3 = const TextStyle(color: AppColor.black, fontSize: 28);
|
||||
|
||||
static TextStyle h2 = TextStyle(color: AppColor.black, fontSize: 30);
|
||||
static TextStyle h2 = const TextStyle(color: AppColor.black, fontSize: 30);
|
||||
|
||||
static TextStyle h1 = TextStyle(color: AppColor.black, fontSize: 32);
|
||||
static TextStyle h1 = const TextStyle(color: AppColor.black, fontSize: 32);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
part of 'theme.dart';
|
||||
|
||||
class AppValue {
|
||||
// TODO: define value
|
||||
}
|
||||
class AppValue {}
|
||||
|
||||
@@ -11,7 +11,7 @@ class ThemeApp {
|
||||
useMaterial3: true,
|
||||
primaryColor: AppColor.primary,
|
||||
scaffoldBackgroundColor: AppColor.white,
|
||||
appBarTheme: AppBarTheme(
|
||||
appBarTheme: const AppBarTheme(
|
||||
color: AppColor.white,
|
||||
elevation: 0,
|
||||
titleTextStyle: TextStyle(
|
||||
@@ -19,7 +19,7 @@ class ThemeApp {
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
iconTheme: const IconThemeData(color: AppColor.primary),
|
||||
iconTheme: IconThemeData(color: AppColor.primary),
|
||||
),
|
||||
fontFamily: FontFamily.quicksand,
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: AppColor.primary),
|
||||
@@ -28,19 +28,19 @@ class ThemeApp {
|
||||
hintStyle: const TextStyle(color: AppColor.textSecondary),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.borderDark),
|
||||
borderSide: const BorderSide(color: AppColor.borderDark),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.primary),
|
||||
borderSide: const BorderSide(color: AppColor.primary),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.borderDark),
|
||||
borderSide: const BorderSide(color: AppColor.borderDark),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderSide: BorderSide(color: AppColor.error),
|
||||
borderSide: const BorderSide(color: AppColor.error),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
class ApiPath {
|
||||
static const String login = '/api/v1/auth/login';
|
||||
static const String logout = '/api/v1/auth/logout';
|
||||
static const String outlets = '/api/v1/outlets';
|
||||
static const String categories = '/api/v1/categories';
|
||||
static const String products = '/api/v1/products';
|
||||
|
||||
@@ -89,6 +89,7 @@ class ProductAnalyticCategoryItem with _$ProductAnalyticCategoryItem {
|
||||
required int totalRevenue,
|
||||
}) = _ProductAnalyticCategoryItem;
|
||||
|
||||
// ignore: prefer_const_constructors
|
||||
factory ProductAnalyticCategoryItem.empty() => ProductAnalyticCategoryItem(
|
||||
categoryName: '',
|
||||
productCount: 0,
|
||||
|
||||
@@ -4,7 +4,10 @@ abstract class IAuthRepository {
|
||||
Future<Either<AuthFailure, Login>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required Map<String, String> devicePayload,
|
||||
required String fcmToken,
|
||||
});
|
||||
Future<Either<AuthFailure, Unit>> logout();
|
||||
Future<bool> hasToken();
|
||||
Future<Either<AuthFailure, User>> currentUser();
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ class ListCustomer with _$ListCustomer {
|
||||
required int totalPages,
|
||||
}) = _ListCustomer;
|
||||
|
||||
factory ListCustomer.empty() => ListCustomer(
|
||||
customers: const [],
|
||||
factory ListCustomer.empty() => const ListCustomer(
|
||||
customers: [],
|
||||
totalCount: 0,
|
||||
page: 0,
|
||||
limit: 0,
|
||||
|
||||
@@ -10,7 +10,7 @@ class AddItemOrderRequest with _$AddItemOrderRequest {
|
||||
required String notes,
|
||||
}) = _AddItemOrderRequest;
|
||||
|
||||
factory AddItemOrderRequest.empty() => AddItemOrderRequest(
|
||||
factory AddItemOrderRequest.empty() => const AddItemOrderRequest(
|
||||
productId: '',
|
||||
productVariantId: '',
|
||||
quantity: 0,
|
||||
|
||||
@@ -10,12 +10,19 @@ class ListOrder with _$ListOrder {
|
||||
required int totalPages,
|
||||
}) = _ListOrder;
|
||||
|
||||
factory ListOrder.empty() =>
|
||||
ListOrder(orders: [], totalCount: 0, page: 0, limit: 0, totalPages: 0);
|
||||
factory ListOrder.empty() => const ListOrder(
|
||||
orders: [],
|
||||
totalCount: 0,
|
||||
page: 0,
|
||||
limit: 0,
|
||||
totalPages: 0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class Order with _$Order {
|
||||
const Order._();
|
||||
|
||||
const factory Order({
|
||||
required String id,
|
||||
required String orderNumber,
|
||||
@@ -118,7 +125,10 @@ class Order with _$Order {
|
||||
createdAt: DateTime.now().subtract(const Duration(hours: 1)),
|
||||
updatedAt: DateTime.now(),
|
||||
printerType: 'Barista',
|
||||
printToChecker: false,
|
||||
paidQuantity: 2,
|
||||
categoryId: 'CAT-001',
|
||||
categoryName: 'Minuman',
|
||||
),
|
||||
OrderItem(
|
||||
id: 'ITEM-002',
|
||||
@@ -136,7 +146,31 @@ class Order with _$Order {
|
||||
createdAt: DateTime.now().subtract(const Duration(hours: 1)),
|
||||
updatedAt: DateTime.now(),
|
||||
printerType: 'Kitchen',
|
||||
printToChecker: false,
|
||||
paidQuantity: 1,
|
||||
categoryId: 'CAT-002',
|
||||
categoryName: 'Makanan',
|
||||
),
|
||||
OrderItem(
|
||||
id: 'ITEM-003',
|
||||
orderId: 'ORD-001',
|
||||
productId: 'PROD-003',
|
||||
productName: 'Pasta',
|
||||
productVariantId: 'VAR-002',
|
||||
productVariantName: '',
|
||||
quantity: 1,
|
||||
unitPrice: 50000,
|
||||
totalPrice: 50000,
|
||||
modifiers: [],
|
||||
notes: '',
|
||||
status: 'Served',
|
||||
createdAt: DateTime.now().subtract(const Duration(hours: 1)),
|
||||
updatedAt: DateTime.now(),
|
||||
printerType: 'Kitchen',
|
||||
printToChecker: false,
|
||||
paidQuantity: 1,
|
||||
categoryId: 'CAT-002',
|
||||
categoryName: 'Makanan',
|
||||
),
|
||||
],
|
||||
payments: [
|
||||
@@ -161,6 +195,24 @@ class Order with _$Order {
|
||||
paymentCount: 1,
|
||||
splitType: 'Single',
|
||||
);
|
||||
|
||||
// For Add Item Order
|
||||
factory Order.fromLastOrder(Order order, List<ProductQuantity> products) =>
|
||||
order.copyWith(
|
||||
orderItems: products
|
||||
.map((e) => OrderItem.fromProductQuantity(e))
|
||||
.toList(),
|
||||
totalAmount: products
|
||||
.map((e) => e.product.price.toInt() * e.quantity)
|
||||
.reduce((value, element) => value + element),
|
||||
subtotal: products
|
||||
.map((e) => e.product.price.toInt() * e.quantity)
|
||||
.reduce((value, element) => value + element),
|
||||
metadata: order.metadata,
|
||||
);
|
||||
|
||||
List<OrderItem> get orderItemNotCancelled =>
|
||||
orderItems.where((item) => item.status != 'cancelled').toList();
|
||||
}
|
||||
|
||||
@freezed
|
||||
@@ -181,7 +233,10 @@ class OrderItem with _$OrderItem {
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required String printerType,
|
||||
required bool printToChecker,
|
||||
required int paidQuantity,
|
||||
required String categoryId,
|
||||
required String categoryName,
|
||||
}) = _OrderItem;
|
||||
|
||||
factory OrderItem.empty() => OrderItem(
|
||||
@@ -200,6 +255,33 @@ class OrderItem with _$OrderItem {
|
||||
createdAt: DateTime(1970),
|
||||
updatedAt: DateTime(1970),
|
||||
printerType: '',
|
||||
printToChecker: false,
|
||||
paidQuantity: 0,
|
||||
categoryId: '',
|
||||
categoryName: '',
|
||||
);
|
||||
|
||||
factory OrderItem.fromProductQuantity(ProductQuantity productQuantity) =>
|
||||
OrderItem(
|
||||
id: '',
|
||||
orderId: '',
|
||||
productId: productQuantity.product.id,
|
||||
productName: productQuantity.product.name,
|
||||
productVariantId: productQuantity.variant?.id ?? '',
|
||||
productVariantName: productQuantity.variant?.name ?? '',
|
||||
quantity: productQuantity.quantity,
|
||||
unitPrice: productQuantity.product.price.toInt(),
|
||||
totalPrice: (productQuantity.product.price * productQuantity.quantity)
|
||||
.toInt(),
|
||||
modifiers: [],
|
||||
notes: productQuantity.notes,
|
||||
status: 'pending',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
printerType: productQuantity.product.printerType,
|
||||
printToChecker: productQuantity.product.printToChecker,
|
||||
paidQuantity: 0,
|
||||
categoryId: '',
|
||||
categoryName: '',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../../common/api/api_failure.dart';
|
||||
import '../../common/types/split_type.dart';
|
||||
import '../product/product.dart';
|
||||
|
||||
part 'order.freezed.dart';
|
||||
|
||||
|
||||
@@ -681,7 +681,7 @@ class __$$OrderImplCopyWithImpl<$Res>
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$OrderImpl implements _Order {
|
||||
class _$OrderImpl extends _Order {
|
||||
const _$OrderImpl({
|
||||
required this.id,
|
||||
required this.orderNumber,
|
||||
@@ -712,7 +712,8 @@ class _$OrderImpl implements _Order {
|
||||
required this.splitType,
|
||||
}) : _metadata = metadata,
|
||||
_orderItems = orderItems,
|
||||
_payments = payments;
|
||||
_payments = payments,
|
||||
super._();
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@@ -889,7 +890,7 @@ class _$OrderImpl implements _Order {
|
||||
__$$OrderImplCopyWithImpl<_$OrderImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _Order implements Order {
|
||||
abstract class _Order extends Order {
|
||||
const factory _Order({
|
||||
required final String id,
|
||||
required final String orderNumber,
|
||||
@@ -919,6 +920,7 @@ abstract class _Order implements Order {
|
||||
required final int paymentCount,
|
||||
required final String splitType,
|
||||
}) = _$OrderImpl;
|
||||
const _Order._() : super._();
|
||||
|
||||
@override
|
||||
String get id;
|
||||
@@ -1000,7 +1002,10 @@ mixin _$OrderItem {
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
String get printerType => throw _privateConstructorUsedError;
|
||||
bool get printToChecker => throw _privateConstructorUsedError;
|
||||
int get paidQuantity => throw _privateConstructorUsedError;
|
||||
String get categoryId => throw _privateConstructorUsedError;
|
||||
String get categoryName => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of OrderItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1030,7 +1035,10 @@ abstract class $OrderItemCopyWith<$Res> {
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
String printerType,
|
||||
bool printToChecker,
|
||||
int paidQuantity,
|
||||
String categoryId,
|
||||
String categoryName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1064,7 +1072,10 @@ class _$OrderItemCopyWithImpl<$Res, $Val extends OrderItem>
|
||||
Object? createdAt = null,
|
||||
Object? updatedAt = null,
|
||||
Object? printerType = null,
|
||||
Object? printToChecker = null,
|
||||
Object? paidQuantity = null,
|
||||
Object? categoryId = null,
|
||||
Object? categoryName = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -1128,10 +1139,22 @@ class _$OrderItemCopyWithImpl<$Res, $Val extends OrderItem>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
printToChecker: null == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
paidQuantity: null == paidQuantity
|
||||
? _value.paidQuantity
|
||||
: paidQuantity // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
categoryId: null == categoryId
|
||||
? _value.categoryId
|
||||
: categoryId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
categoryName: null == categoryName
|
||||
? _value.categoryName
|
||||
: categoryName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -1163,7 +1186,10 @@ abstract class _$$OrderItemImplCopyWith<$Res>
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
String printerType,
|
||||
bool printToChecker,
|
||||
int paidQuantity,
|
||||
String categoryId,
|
||||
String categoryName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1196,7 +1222,10 @@ class __$$OrderItemImplCopyWithImpl<$Res>
|
||||
Object? createdAt = null,
|
||||
Object? updatedAt = null,
|
||||
Object? printerType = null,
|
||||
Object? printToChecker = null,
|
||||
Object? paidQuantity = null,
|
||||
Object? categoryId = null,
|
||||
Object? categoryName = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$OrderItemImpl(
|
||||
@@ -1260,10 +1289,22 @@ class __$$OrderItemImplCopyWithImpl<$Res>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
printToChecker: null == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
paidQuantity: null == paidQuantity
|
||||
? _value.paidQuantity
|
||||
: paidQuantity // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
categoryId: null == categoryId
|
||||
? _value.categoryId
|
||||
: categoryId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
categoryName: null == categoryName
|
||||
? _value.categoryName
|
||||
: categoryName // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1288,7 +1329,10 @@ class _$OrderItemImpl implements _OrderItem {
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.printerType,
|
||||
required this.printToChecker,
|
||||
required this.paidQuantity,
|
||||
required this.categoryId,
|
||||
required this.categoryName,
|
||||
}) : _modifiers = modifiers;
|
||||
|
||||
@override
|
||||
@@ -1328,11 +1372,17 @@ class _$OrderItemImpl implements _OrderItem {
|
||||
@override
|
||||
final String printerType;
|
||||
@override
|
||||
final bool printToChecker;
|
||||
@override
|
||||
final int paidQuantity;
|
||||
@override
|
||||
final String categoryId;
|
||||
@override
|
||||
final String categoryName;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OrderItem(id: $id, orderId: $orderId, productId: $productId, productName: $productName, productVariantId: $productVariantId, productVariantName: $productVariantName, quantity: $quantity, unitPrice: $unitPrice, totalPrice: $totalPrice, modifiers: $modifiers, notes: $notes, status: $status, createdAt: $createdAt, updatedAt: $updatedAt, printerType: $printerType, paidQuantity: $paidQuantity)';
|
||||
return 'OrderItem(id: $id, orderId: $orderId, productId: $productId, productName: $productName, productVariantId: $productVariantId, productVariantName: $productVariantName, quantity: $quantity, unitPrice: $unitPrice, totalPrice: $totalPrice, modifiers: $modifiers, notes: $notes, status: $status, createdAt: $createdAt, updatedAt: $updatedAt, printerType: $printerType, printToChecker: $printToChecker, paidQuantity: $paidQuantity, categoryId: $categoryId, categoryName: $categoryName)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1368,12 +1418,18 @@ class _$OrderItemImpl implements _OrderItem {
|
||||
other.updatedAt == updatedAt) &&
|
||||
(identical(other.printerType, printerType) ||
|
||||
other.printerType == printerType) &&
|
||||
(identical(other.printToChecker, printToChecker) ||
|
||||
other.printToChecker == printToChecker) &&
|
||||
(identical(other.paidQuantity, paidQuantity) ||
|
||||
other.paidQuantity == paidQuantity));
|
||||
other.paidQuantity == paidQuantity) &&
|
||||
(identical(other.categoryId, categoryId) ||
|
||||
other.categoryId == categoryId) &&
|
||||
(identical(other.categoryName, categoryName) ||
|
||||
other.categoryName == categoryName));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
int get hashCode => Object.hashAll([
|
||||
runtimeType,
|
||||
id,
|
||||
orderId,
|
||||
@@ -1390,8 +1446,11 @@ class _$OrderItemImpl implements _OrderItem {
|
||||
createdAt,
|
||||
updatedAt,
|
||||
printerType,
|
||||
printToChecker,
|
||||
paidQuantity,
|
||||
);
|
||||
categoryId,
|
||||
categoryName,
|
||||
]);
|
||||
|
||||
/// Create a copy of OrderItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1419,7 +1478,10 @@ abstract class _OrderItem implements OrderItem {
|
||||
required final DateTime createdAt,
|
||||
required final DateTime updatedAt,
|
||||
required final String printerType,
|
||||
required final bool printToChecker,
|
||||
required final int paidQuantity,
|
||||
required final String categoryId,
|
||||
required final String categoryName,
|
||||
}) = _$OrderItemImpl;
|
||||
|
||||
@override
|
||||
@@ -1453,7 +1515,13 @@ abstract class _OrderItem implements OrderItem {
|
||||
@override
|
||||
String get printerType;
|
||||
@override
|
||||
bool get printToChecker;
|
||||
@override
|
||||
int get paidQuantity;
|
||||
@override
|
||||
String get categoryId;
|
||||
@override
|
||||
String get categoryName;
|
||||
|
||||
/// Create a copy of OrderItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -24,10 +24,12 @@ abstract class IOrderRepository {
|
||||
Future<Either<OrderFailure, Order>> addItemOrder({
|
||||
required String id,
|
||||
required List<AddItemOrderRequest> request,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
Future<Either<OrderFailure, Payment>> createPayment({
|
||||
required PaymentRequest request,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
Future<Either<OrderFailure, Unit>> voidOrder({
|
||||
@@ -35,15 +37,18 @@ abstract class IOrderRepository {
|
||||
required String reason,
|
||||
String type = "ITEM", // TYPE: ALL, ITEM
|
||||
required List<OrderItem> orderItems,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
Future<Either<OrderFailure, Payment>> createSplitBill(
|
||||
PaymentSplitBillRequest request,
|
||||
);
|
||||
PaymentSplitBillRequest request, {
|
||||
String? idempotencyKey,
|
||||
});
|
||||
|
||||
Future<Either<OrderFailure, Unit>> refundOrder({
|
||||
required String id,
|
||||
required String reason,
|
||||
required int refundAmount,
|
||||
String? idempotencyKey,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class ListPaymentMethod with _$ListPaymentMethod {
|
||||
required int totalPages,
|
||||
}) = _ListPaymentMethod;
|
||||
|
||||
factory ListPaymentMethod.empty() => ListPaymentMethod(
|
||||
factory ListPaymentMethod.empty() => const ListPaymentMethod(
|
||||
paymentMethods: [],
|
||||
totalCount: 0,
|
||||
page: 0,
|
||||
|
||||
@@ -19,4 +19,21 @@ abstract class IPrinterRepository {
|
||||
Future<Either<PrinterFailure, Unit>> printStruckSaveOrder({
|
||||
required Order order,
|
||||
});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckCashier({
|
||||
required Order order,
|
||||
});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckPayment({
|
||||
required Order order,
|
||||
});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckChecker({
|
||||
required Order order,
|
||||
});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckKitchen({
|
||||
required Order order,
|
||||
});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckBar({required Order order});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckVoid({required Order order});
|
||||
Future<Either<PrinterFailure, Unit>> printStruckSplitBill({
|
||||
required Order order,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ class Product with _$Product {
|
||||
required String businessType,
|
||||
required String imageUrl,
|
||||
required String printerType,
|
||||
required bool printToChecker,
|
||||
required Map<String, dynamic> metadata,
|
||||
required bool isActive,
|
||||
required String createdAt,
|
||||
@@ -52,6 +53,7 @@ class Product with _$Product {
|
||||
businessType: '',
|
||||
imageUrl: '',
|
||||
printerType: '',
|
||||
printToChecker: false,
|
||||
metadata: {},
|
||||
isActive: false,
|
||||
createdAt: '',
|
||||
|
||||
@@ -279,6 +279,7 @@ mixin _$Product {
|
||||
String get businessType => throw _privateConstructorUsedError;
|
||||
String get imageUrl => throw _privateConstructorUsedError;
|
||||
String get printerType => throw _privateConstructorUsedError;
|
||||
bool get printToChecker => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> get metadata => throw _privateConstructorUsedError;
|
||||
bool get isActive => throw _privateConstructorUsedError;
|
||||
String get createdAt => throw _privateConstructorUsedError;
|
||||
@@ -308,6 +309,7 @@ abstract class $ProductCopyWith<$Res> {
|
||||
String businessType,
|
||||
String imageUrl,
|
||||
String printerType,
|
||||
bool printToChecker,
|
||||
Map<String, dynamic> metadata,
|
||||
bool isActive,
|
||||
String createdAt,
|
||||
@@ -342,6 +344,7 @@ class _$ProductCopyWithImpl<$Res, $Val extends Product>
|
||||
Object? businessType = null,
|
||||
Object? imageUrl = null,
|
||||
Object? printerType = null,
|
||||
Object? printToChecker = null,
|
||||
Object? metadata = null,
|
||||
Object? isActive = null,
|
||||
Object? createdAt = null,
|
||||
@@ -394,6 +397,10 @@ class _$ProductCopyWithImpl<$Res, $Val extends Product>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
printToChecker: null == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
metadata: null == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
@@ -440,6 +447,7 @@ abstract class _$$ProductImplCopyWith<$Res> implements $ProductCopyWith<$Res> {
|
||||
String businessType,
|
||||
String imageUrl,
|
||||
String printerType,
|
||||
bool printToChecker,
|
||||
Map<String, dynamic> metadata,
|
||||
bool isActive,
|
||||
String createdAt,
|
||||
@@ -473,6 +481,7 @@ class __$$ProductImplCopyWithImpl<$Res>
|
||||
Object? businessType = null,
|
||||
Object? imageUrl = null,
|
||||
Object? printerType = null,
|
||||
Object? printToChecker = null,
|
||||
Object? metadata = null,
|
||||
Object? isActive = null,
|
||||
Object? createdAt = null,
|
||||
@@ -525,6 +534,10 @@ class __$$ProductImplCopyWithImpl<$Res>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
printToChecker: null == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
metadata: null == metadata
|
||||
? _value._metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
@@ -565,6 +578,7 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
required this.businessType,
|
||||
required this.imageUrl,
|
||||
required this.printerType,
|
||||
required this.printToChecker,
|
||||
required final Map<String, dynamic> metadata,
|
||||
required this.isActive,
|
||||
required this.createdAt,
|
||||
@@ -595,6 +609,8 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
final String imageUrl;
|
||||
@override
|
||||
final String printerType;
|
||||
@override
|
||||
final bool printToChecker;
|
||||
final Map<String, dynamic> _metadata;
|
||||
@override
|
||||
Map<String, dynamic> get metadata {
|
||||
@@ -619,7 +635,7 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'Product(id: $id, organizationId: $organizationId, categoryId: $categoryId, sku: $sku, name: $name, description: $description, price: $price, cost: $cost, businessType: $businessType, imageUrl: $imageUrl, printerType: $printerType, metadata: $metadata, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, variants: $variants)';
|
||||
return 'Product(id: $id, organizationId: $organizationId, categoryId: $categoryId, sku: $sku, name: $name, description: $description, price: $price, cost: $cost, businessType: $businessType, imageUrl: $imageUrl, printerType: $printerType, printToChecker: $printToChecker, metadata: $metadata, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, variants: $variants)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -638,6 +654,7 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
..add(DiagnosticsProperty('businessType', businessType))
|
||||
..add(DiagnosticsProperty('imageUrl', imageUrl))
|
||||
..add(DiagnosticsProperty('printerType', printerType))
|
||||
..add(DiagnosticsProperty('printToChecker', printToChecker))
|
||||
..add(DiagnosticsProperty('metadata', metadata))
|
||||
..add(DiagnosticsProperty('isActive', isActive))
|
||||
..add(DiagnosticsProperty('createdAt', createdAt))
|
||||
@@ -667,6 +684,8 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
other.imageUrl == imageUrl) &&
|
||||
(identical(other.printerType, printerType) ||
|
||||
other.printerType == printerType) &&
|
||||
(identical(other.printToChecker, printToChecker) ||
|
||||
other.printToChecker == printToChecker) &&
|
||||
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
|
||||
(identical(other.isActive, isActive) ||
|
||||
other.isActive == isActive) &&
|
||||
@@ -691,6 +710,7 @@ class _$ProductImpl with DiagnosticableTreeMixin implements _Product {
|
||||
businessType,
|
||||
imageUrl,
|
||||
printerType,
|
||||
printToChecker,
|
||||
const DeepCollectionEquality().hash(_metadata),
|
||||
isActive,
|
||||
createdAt,
|
||||
@@ -720,6 +740,7 @@ abstract class _Product implements Product {
|
||||
required final String businessType,
|
||||
required final String imageUrl,
|
||||
required final String printerType,
|
||||
required final bool printToChecker,
|
||||
required final Map<String, dynamic> metadata,
|
||||
required final bool isActive,
|
||||
required final String createdAt,
|
||||
@@ -750,6 +771,8 @@ abstract class _Product implements Product {
|
||||
@override
|
||||
String get printerType;
|
||||
@override
|
||||
bool get printToChecker;
|
||||
@override
|
||||
Map<String, dynamic> get metadata;
|
||||
@override
|
||||
bool get isActive;
|
||||
|
||||
@@ -10,8 +10,13 @@ class ListTable with _$ListTable {
|
||||
required int totalPages,
|
||||
}) = _ListTable;
|
||||
|
||||
factory ListTable.empty() =>
|
||||
ListTable(tables: [], totalCount: 0, page: 0, limit: 0, totalPages: 0);
|
||||
factory ListTable.empty() => const ListTable(
|
||||
tables: [],
|
||||
totalCount: 0,
|
||||
page: 0,
|
||||
limit: 0,
|
||||
totalPages: 0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
+9
-2
@@ -2,6 +2,7 @@ import 'package:injectable/injectable.dart';
|
||||
|
||||
abstract class Env {
|
||||
String get baseUrl;
|
||||
String get dbName;
|
||||
// add getter here...
|
||||
}
|
||||
|
||||
@@ -9,12 +10,18 @@ abstract class Env {
|
||||
@dev
|
||||
class DevEnv implements Env {
|
||||
@override
|
||||
String get baseUrl => 'https://api-pos.apskel.id'; // example value
|
||||
String get baseUrl => 'http://194.233.78.1:4001';
|
||||
|
||||
@override
|
||||
String get dbName => "apskel_pos_staging.db";
|
||||
}
|
||||
|
||||
@Injectable(as: Env)
|
||||
@prod
|
||||
class ProdEnv implements Env {
|
||||
@override
|
||||
String get baseUrl => 'https://api-pos.apskel.id';
|
||||
String get baseUrl => 'https://enaklo-pos-api.altru.id';
|
||||
|
||||
@override
|
||||
String get dbName => "apskel_pos_prod.db";
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final dashboard = DashboardAnalyticDto.fromJson(
|
||||
@@ -65,7 +65,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final sales = SalesAnalyticDto.fromJson(
|
||||
@@ -94,7 +94,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final products = ProductAnalyticDto.fromJson(
|
||||
@@ -123,7 +123,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final paymentMethods = PaymentMethodAnalyticDto.fromJson(
|
||||
@@ -152,7 +152,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final profitLoss = ProfitLossAnalyticDto.fromJson(
|
||||
@@ -181,7 +181,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final categories = CategoryAnalyticDto.fromJson(
|
||||
@@ -211,7 +211,7 @@ class AnalyticRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
return DC.error(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final inventory = InventoryAnalyticDto.fromJson(
|
||||
|
||||
@@ -53,6 +53,7 @@ class AuthLocalDataProvider {
|
||||
try {
|
||||
await _sharedPreferences.remove(LocalStorageKey.token);
|
||||
await _sharedPreferences.remove(LocalStorageKey.user);
|
||||
await _sharedPreferences.remove(LocalStorageKey.outlet);
|
||||
} catch (e) {
|
||||
log('deleteAllAuthError', name: _logName, error: e);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:data_channel/data_channel.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../common/api/api_client.dart';
|
||||
import '../../../common/api/api_failure.dart';
|
||||
import '../../../common/function/app_function.dart';
|
||||
import '../../../common/url/api_path.dart';
|
||||
import '../../../domain/auth/auth.dart';
|
||||
import '../auth_dtos.dart';
|
||||
@@ -19,16 +21,23 @@ class AuthRemoteDataProvider {
|
||||
Future<DC<AuthFailure, LoginDto>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required Map<String, String> devicePayload,
|
||||
required String fcmToken,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
ApiPath.login,
|
||||
data: {'email': email, 'password': password},
|
||||
data: {
|
||||
'email': email,
|
||||
'password': password,
|
||||
'fcm_token': fcmToken,
|
||||
...devicePayload,
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data['code'] == 401) {
|
||||
return DC.error(
|
||||
AuthFailure.serverError(
|
||||
const AuthFailure.serverError(
|
||||
ApiFailure.unauthorized('Incorrect email or password'),
|
||||
),
|
||||
);
|
||||
@@ -41,4 +50,22 @@ class AuthRemoteDataProvider {
|
||||
return DC.error(AuthFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<AuthFailure, Unit>> logout() async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
ApiPath.logout,
|
||||
headers: getAuthorizationHeader(),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(const AuthFailure.unexpectedError());
|
||||
}
|
||||
|
||||
return DC.data(unit);
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('logout', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(AuthFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
|
||||
part of '../auth_dtos.dart';
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -19,11 +19,15 @@ class AuthRepository implements IAuthRepository {
|
||||
Future<Either<AuthFailure, Login>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required Map<String, String> devicePayload,
|
||||
required String fcmToken,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.login(
|
||||
email: email,
|
||||
password: password,
|
||||
devicePayload: devicePayload,
|
||||
fcmToken: fcmToken,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
@@ -57,4 +61,21 @@ class AuthRepository implements IAuthRepository {
|
||||
Future<bool> hasToken() async {
|
||||
return await _localDataProvider.hasToken();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<AuthFailure, Unit>> logout() async {
|
||||
try {
|
||||
final result = await _dataProvider.logout();
|
||||
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
}
|
||||
|
||||
await _localDataProvider.deleteAllAuth();
|
||||
return right(unit);
|
||||
} catch (e, s) {
|
||||
log('logoutError', name: _logName, error: e, stackTrace: s);
|
||||
return left(const AuthFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ class CategoryLocalDataProvider {
|
||||
CategoryLocalDataProvider(this._databaseHelper);
|
||||
|
||||
final Map<String, List<CategoryDto>> _queryCache = {};
|
||||
final Duration _cacheExpiry = Duration(minutes: AppConstant.cacheExpire);
|
||||
final Duration _cacheExpiry = const Duration(
|
||||
minutes: AppConstant.cacheExpire,
|
||||
);
|
||||
final Map<String, DateTime> _cacheTimestamps = {};
|
||||
|
||||
Future<DC<CategoryFailure, void>> saveCategoriesBatch(
|
||||
@@ -203,7 +205,7 @@ class CategoryLocalDataProvider {
|
||||
|
||||
if (maps.isEmpty) {
|
||||
log('❌ Category not found: $id', name: _logName);
|
||||
return DC.error(CategoryFailure.empty());
|
||||
return DC.error(const CategoryFailure.empty());
|
||||
}
|
||||
|
||||
final category = CategoryDto.fromMap(maps.first);
|
||||
|
||||
@@ -29,7 +29,7 @@ class CategoryRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(CategoryFailure.empty());
|
||||
return DC.error(const CategoryFailure.empty());
|
||||
}
|
||||
|
||||
final categories = ListCategoryDto.fromJson(
|
||||
|
||||
@@ -63,7 +63,7 @@ class CategoryDto with _$CategoryDto {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'business_type': businessType,
|
||||
'order': order,
|
||||
'sort_order': order,
|
||||
'metadata': metadata != null ? jsonEncode(metadata) : null,
|
||||
'created_at': createdAt,
|
||||
'updated_at': updatedAt,
|
||||
|
||||
@@ -29,7 +29,7 @@ class CustomerRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(CustomerFailure.unexpectedError());
|
||||
return DC.error(const CustomerFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final customers = ListCustomerDto.fromJson(
|
||||
|
||||
@@ -18,6 +18,15 @@ class OrderRemoteDataProvider {
|
||||
final _logName = 'OrderRemoteDataProvider';
|
||||
OrderRemoteDataProvider(this._apiClient);
|
||||
|
||||
/// Helper untuk merge auth header dengan idempotency key
|
||||
Map<String, dynamic> _buildHeaders({String? idempotencyKey}) {
|
||||
final headers = getAuthorizationHeader();
|
||||
if (idempotencyKey != null) {
|
||||
headers['X-Idempotency-Key'] = idempotencyKey;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
Future<DC<OrderFailure, ListOrderDto>> fetchOrders({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
@@ -46,7 +55,7 @@ class OrderRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final orders = ListOrderDto.fromJson(
|
||||
@@ -68,7 +77,7 @@ class OrderRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final order = OrderDto.fromJson(
|
||||
@@ -93,7 +102,7 @@ class OrderRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final order = OrderDto.fromJson(
|
||||
@@ -119,7 +128,7 @@ class OrderRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
} else {
|
||||
final order = OrderDto.fromJson(
|
||||
response.data['data'] as Map<String, dynamic>,
|
||||
@@ -151,17 +160,18 @@ class OrderRemoteDataProvider {
|
||||
}
|
||||
|
||||
Future<DC<OrderFailure, PaymentDto>> storePayment(
|
||||
PaymentRequestDto request,
|
||||
) async {
|
||||
PaymentRequestDto request, {
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
ApiPath.payments,
|
||||
data: request.toJson(),
|
||||
headers: getAuthorizationHeader(),
|
||||
headers: _buildHeaders(idempotencyKey: idempotencyKey),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final payment = PaymentDto.fromJson(
|
||||
@@ -178,6 +188,7 @@ class OrderRemoteDataProvider {
|
||||
Future<DC<OrderFailure, OrderDto>> addItemOrder({
|
||||
required String id,
|
||||
required List<AddItemOrderRequestDto> request,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
@@ -186,15 +197,15 @@ class OrderRemoteDataProvider {
|
||||
'notes': '',
|
||||
'order_items': request.map((e) => e.toRequest()).toList(),
|
||||
},
|
||||
headers: getAuthorizationHeader(),
|
||||
headers: _buildHeaders(idempotencyKey: idempotencyKey),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final order = OrderDto.fromJson(
|
||||
response.data['data'] as Map<String, dynamic>,
|
||||
response.data['data']['updated_order'] as Map<String, dynamic>,
|
||||
);
|
||||
|
||||
return DC.data(order);
|
||||
@@ -209,6 +220,7 @@ class OrderRemoteDataProvider {
|
||||
required String reason,
|
||||
String type = "ITEM", // TYPE: ALL, ITEM
|
||||
required List<OrderItemDto> orderItems,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
@@ -223,11 +235,11 @@ class OrderRemoteDataProvider {
|
||||
)
|
||||
.toList(),
|
||||
},
|
||||
headers: getAuthorizationHeader(),
|
||||
headers: _buildHeaders(idempotencyKey: idempotencyKey),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
return DC.data(unit);
|
||||
@@ -238,18 +250,19 @@ class OrderRemoteDataProvider {
|
||||
}
|
||||
|
||||
Future<DC<OrderFailure, PaymentDto>> createSplitBill(
|
||||
PaymentSplitBillRequestDto request,
|
||||
) async {
|
||||
PaymentSplitBillRequestDto request, {
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
log(request.toRequest().toString());
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
"${ApiPath.orders}/split-bill",
|
||||
data: request.toRequest(),
|
||||
headers: getAuthorizationHeader(),
|
||||
headers: _buildHeaders(idempotencyKey: idempotencyKey),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final payment = PaymentDto.fromJson(
|
||||
@@ -267,16 +280,17 @@ class OrderRemoteDataProvider {
|
||||
required String id,
|
||||
required String reason,
|
||||
required int refundAmount,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
'${ApiPath.orders}/$id/refund',
|
||||
data: {'refund_amount': refundAmount, 'reason': reason},
|
||||
headers: getAuthorizationHeader(),
|
||||
headers: _buildHeaders(idempotencyKey: idempotencyKey),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(OrderFailure.unexpectedError());
|
||||
return DC.error(const OrderFailure.unexpectedError());
|
||||
}
|
||||
|
||||
return DC.data(unit);
|
||||
|
||||
@@ -114,7 +114,10 @@ class OrderItemDto with _$OrderItemDto {
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "paid_quantity") int? paidQuantity,
|
||||
@JsonKey(name: "category_id") String? categoryId,
|
||||
@JsonKey(name: "category_name") String? categoryName,
|
||||
}) = _OrderItemDto;
|
||||
|
||||
factory OrderItemDto.fromJson(Map<String, dynamic> json) =>
|
||||
@@ -137,7 +140,10 @@ class OrderItemDto with _$OrderItemDto {
|
||||
createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970),
|
||||
updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970),
|
||||
printerType: printerType ?? '',
|
||||
printToChecker: printToChecker ?? false,
|
||||
paidQuantity: paidQuantity ?? 0,
|
||||
categoryId: categoryId ?? '',
|
||||
categoryName: categoryName ?? '',
|
||||
);
|
||||
|
||||
factory OrderItemDto.fromDomain(OrderItem orderItem) => OrderItemDto(
|
||||
@@ -156,6 +162,9 @@ class OrderItemDto with _$OrderItemDto {
|
||||
createdAt: orderItem.createdAt.toIso8601String(),
|
||||
updatedAt: orderItem.updatedAt.toIso8601String(),
|
||||
printerType: orderItem.printerType,
|
||||
printToChecker: orderItem.printToChecker,
|
||||
paidQuantity: orderItem.paidQuantity,
|
||||
categoryId: orderItem.categoryId,
|
||||
categoryName: orderItem.categoryName,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1169,8 +1169,14 @@ mixin _$OrderItemDto {
|
||||
String? get updatedAt => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "printer_type")
|
||||
String? get printerType => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "print_to_checker")
|
||||
bool? get printToChecker => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "paid_quantity")
|
||||
int? get paidQuantity => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "category_id")
|
||||
String? get categoryId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "category_name")
|
||||
String? get categoryName => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OrderItemDto to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -1205,7 +1211,10 @@ abstract class $OrderItemDtoCopyWith<$Res> {
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "paid_quantity") int? paidQuantity,
|
||||
@JsonKey(name: "category_id") String? categoryId,
|
||||
@JsonKey(name: "category_name") String? categoryName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1239,7 +1248,10 @@ class _$OrderItemDtoCopyWithImpl<$Res, $Val extends OrderItemDto>
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
Object? printerType = freezed,
|
||||
Object? printToChecker = freezed,
|
||||
Object? paidQuantity = freezed,
|
||||
Object? categoryId = freezed,
|
||||
Object? categoryName = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
@@ -1303,10 +1315,22 @@ class _$OrderItemDtoCopyWithImpl<$Res, $Val extends OrderItemDto>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
printToChecker: freezed == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
paidQuantity: freezed == paidQuantity
|
||||
? _value.paidQuantity
|
||||
: paidQuantity // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
categoryId: freezed == categoryId
|
||||
? _value.categoryId
|
||||
: categoryId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
categoryName: freezed == categoryName
|
||||
? _value.categoryName
|
||||
: categoryName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
@@ -1338,7 +1362,10 @@ abstract class _$$OrderItemDtoImplCopyWith<$Res>
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "paid_quantity") int? paidQuantity,
|
||||
@JsonKey(name: "category_id") String? categoryId,
|
||||
@JsonKey(name: "category_name") String? categoryName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1371,7 +1398,10 @@ class __$$OrderItemDtoImplCopyWithImpl<$Res>
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
Object? printerType = freezed,
|
||||
Object? printToChecker = freezed,
|
||||
Object? paidQuantity = freezed,
|
||||
Object? categoryId = freezed,
|
||||
Object? categoryName = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$OrderItemDtoImpl(
|
||||
@@ -1435,10 +1465,22 @@ class __$$OrderItemDtoImplCopyWithImpl<$Res>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
printToChecker: freezed == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
paidQuantity: freezed == paidQuantity
|
||||
? _value.paidQuantity
|
||||
: paidQuantity // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
categoryId: freezed == categoryId
|
||||
? _value.categoryId
|
||||
: categoryId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
categoryName: freezed == categoryName
|
||||
? _value.categoryName
|
||||
: categoryName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1463,7 +1505,10 @@ class _$OrderItemDtoImpl extends _OrderItemDto {
|
||||
@JsonKey(name: "created_at") this.createdAt,
|
||||
@JsonKey(name: "updated_at") this.updatedAt,
|
||||
@JsonKey(name: "printer_type") this.printerType,
|
||||
@JsonKey(name: "print_to_checker") this.printToChecker,
|
||||
@JsonKey(name: "paid_quantity") this.paidQuantity,
|
||||
@JsonKey(name: "category_id") this.categoryId,
|
||||
@JsonKey(name: "category_name") this.categoryName,
|
||||
}) : _modifiers = modifiers,
|
||||
super._();
|
||||
|
||||
@@ -1524,12 +1569,21 @@ class _$OrderItemDtoImpl extends _OrderItemDto {
|
||||
@JsonKey(name: "printer_type")
|
||||
final String? printerType;
|
||||
@override
|
||||
@JsonKey(name: "print_to_checker")
|
||||
final bool? printToChecker;
|
||||
@override
|
||||
@JsonKey(name: "paid_quantity")
|
||||
final int? paidQuantity;
|
||||
@override
|
||||
@JsonKey(name: "category_id")
|
||||
final String? categoryId;
|
||||
@override
|
||||
@JsonKey(name: "category_name")
|
||||
final String? categoryName;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OrderItemDto(id: $id, orderId: $orderId, productId: $productId, productName: $productName, productVariantId: $productVariantId, productVariantName: $productVariantName, quantity: $quantity, unitPrice: $unitPrice, totalPrice: $totalPrice, modifiers: $modifiers, notes: $notes, status: $status, createdAt: $createdAt, updatedAt: $updatedAt, printerType: $printerType, paidQuantity: $paidQuantity)';
|
||||
return 'OrderItemDto(id: $id, orderId: $orderId, productId: $productId, productName: $productName, productVariantId: $productVariantId, productVariantName: $productVariantName, quantity: $quantity, unitPrice: $unitPrice, totalPrice: $totalPrice, modifiers: $modifiers, notes: $notes, status: $status, createdAt: $createdAt, updatedAt: $updatedAt, printerType: $printerType, printToChecker: $printToChecker, paidQuantity: $paidQuantity, categoryId: $categoryId, categoryName: $categoryName)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1565,13 +1619,19 @@ class _$OrderItemDtoImpl extends _OrderItemDto {
|
||||
other.updatedAt == updatedAt) &&
|
||||
(identical(other.printerType, printerType) ||
|
||||
other.printerType == printerType) &&
|
||||
(identical(other.printToChecker, printToChecker) ||
|
||||
other.printToChecker == printToChecker) &&
|
||||
(identical(other.paidQuantity, paidQuantity) ||
|
||||
other.paidQuantity == paidQuantity));
|
||||
other.paidQuantity == paidQuantity) &&
|
||||
(identical(other.categoryId, categoryId) ||
|
||||
other.categoryId == categoryId) &&
|
||||
(identical(other.categoryName, categoryName) ||
|
||||
other.categoryName == categoryName));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
int get hashCode => Object.hashAll([
|
||||
runtimeType,
|
||||
id,
|
||||
orderId,
|
||||
@@ -1588,8 +1648,11 @@ class _$OrderItemDtoImpl extends _OrderItemDto {
|
||||
createdAt,
|
||||
updatedAt,
|
||||
printerType,
|
||||
printToChecker,
|
||||
paidQuantity,
|
||||
);
|
||||
categoryId,
|
||||
categoryName,
|
||||
]);
|
||||
|
||||
/// Create a copy of OrderItemDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1622,7 +1685,10 @@ abstract class _OrderItemDto extends OrderItemDto {
|
||||
@JsonKey(name: "created_at") final String? createdAt,
|
||||
@JsonKey(name: "updated_at") final String? updatedAt,
|
||||
@JsonKey(name: "printer_type") final String? printerType,
|
||||
@JsonKey(name: "print_to_checker") final bool? printToChecker,
|
||||
@JsonKey(name: "paid_quantity") final int? paidQuantity,
|
||||
@JsonKey(name: "category_id") final String? categoryId,
|
||||
@JsonKey(name: "category_name") final String? categoryName,
|
||||
}) = _$OrderItemDtoImpl;
|
||||
const _OrderItemDto._() : super._();
|
||||
|
||||
@@ -1675,8 +1741,17 @@ abstract class _OrderItemDto extends OrderItemDto {
|
||||
@JsonKey(name: "printer_type")
|
||||
String? get printerType;
|
||||
@override
|
||||
@JsonKey(name: "print_to_checker")
|
||||
bool? get printToChecker;
|
||||
@override
|
||||
@JsonKey(name: "paid_quantity")
|
||||
int? get paidQuantity;
|
||||
@override
|
||||
@JsonKey(name: "category_id")
|
||||
String? get categoryId;
|
||||
@override
|
||||
@JsonKey(name: "category_name")
|
||||
String? get categoryName;
|
||||
|
||||
/// Create a copy of OrderItemDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -109,7 +109,10 @@ _$OrderItemDtoImpl _$$OrderItemDtoImplFromJson(Map<String, dynamic> json) =>
|
||||
createdAt: json['created_at'] as String?,
|
||||
updatedAt: json['updated_at'] as String?,
|
||||
printerType: json['printer_type'] as String?,
|
||||
printToChecker: json['print_to_checker'] as bool?,
|
||||
paidQuantity: (json['paid_quantity'] as num?)?.toInt(),
|
||||
categoryId: json['category_id'] as String?,
|
||||
categoryName: json['category_name'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$OrderItemDtoImplToJson(_$OrderItemDtoImpl instance) =>
|
||||
@@ -129,7 +132,10 @@ Map<String, dynamic> _$$OrderItemDtoImplToJson(_$OrderItemDtoImpl instance) =>
|
||||
'created_at': instance.createdAt,
|
||||
'updated_at': instance.updatedAt,
|
||||
'printer_type': instance.printerType,
|
||||
'print_to_checker': instance.printToChecker,
|
||||
'paid_quantity': instance.paidQuantity,
|
||||
'category_id': instance.categoryId,
|
||||
'category_name': instance.categoryName,
|
||||
};
|
||||
|
||||
_$OrderRequestDtoImpl _$$OrderRequestDtoImplFromJson(
|
||||
|
||||
@@ -110,6 +110,7 @@ class OrderRepository implements IOrderRepository {
|
||||
Future<Either<OrderFailure, Order>> addItemOrder({
|
||||
required String id,
|
||||
required List<AddItemOrderRequest> request,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.addItemOrder(
|
||||
@@ -117,6 +118,7 @@ class OrderRepository implements IOrderRepository {
|
||||
request: request
|
||||
.map((e) => AddItemOrderRequestDto.fromDomain(e))
|
||||
.toList(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
@@ -134,10 +136,12 @@ class OrderRepository implements IOrderRepository {
|
||||
@override
|
||||
Future<Either<OrderFailure, Payment>> createPayment({
|
||||
required PaymentRequest request,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.storePayment(
|
||||
PaymentRequestDto.fromDomain(request),
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
@@ -158,6 +162,7 @@ class OrderRepository implements IOrderRepository {
|
||||
required String reason,
|
||||
String type = "ITEM",
|
||||
required List<OrderItem> orderItems,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.voidOrder(
|
||||
@@ -165,6 +170,7 @@ class OrderRepository implements IOrderRepository {
|
||||
reason: reason,
|
||||
type: type,
|
||||
orderItems: orderItems.map((e) => OrderItemDto.fromDomain(e)).toList(),
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
@@ -180,11 +186,13 @@ class OrderRepository implements IOrderRepository {
|
||||
|
||||
@override
|
||||
Future<Either<OrderFailure, Payment>> createSplitBill(
|
||||
PaymentSplitBillRequest request,
|
||||
) async {
|
||||
PaymentSplitBillRequest request, {
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.createSplitBill(
|
||||
PaymentSplitBillRequestDto.fromDomain(request),
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
@@ -204,12 +212,14 @@ class OrderRepository implements IOrderRepository {
|
||||
required String id,
|
||||
required String reason,
|
||||
required int refundAmount,
|
||||
String? idempotencyKey,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.refundPayment(
|
||||
id: id,
|
||||
reason: reason,
|
||||
refundAmount: refundAmount,
|
||||
idempotencyKey: idempotencyKey,
|
||||
);
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
|
||||
@@ -29,7 +29,7 @@ class OutletRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(OutletFailure.empty());
|
||||
return DC.error(const OutletFailure.empty());
|
||||
}
|
||||
|
||||
final outlets = (response.data['data']['outlets'] as List)
|
||||
@@ -51,7 +51,7 @@ class OutletRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(OutletFailure.empty());
|
||||
return DC.error(const OutletFailure.empty());
|
||||
}
|
||||
|
||||
final outlet = OutletDto.fromJson(
|
||||
|
||||
@@ -29,7 +29,7 @@ class PaymentMethodRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(PaymentMethodFailure.unexpectedError());
|
||||
return DC.error(const PaymentMethodFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final paymentMethods = ListPaymentMethodDto.fromJson(
|
||||
|
||||
@@ -26,7 +26,7 @@ class PrinterLocalDataProvider {
|
||||
|
||||
if (printerExist.hasData) {
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Printer Telah Terdaftar'),
|
||||
const PrinterFailure.dynamicErrorMessage('Printer Telah Terdaftar'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class PrinterLocalDataProvider {
|
||||
log('Error creating printer', name: _logName, error: e);
|
||||
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Error creating printer'),
|
||||
const PrinterFailure.dynamicErrorMessage('Error creating printer'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class PrinterLocalDataProvider {
|
||||
|
||||
if (updatedRows == 0) {
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage('Printer not found'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class PrinterLocalDataProvider {
|
||||
log('Error updating printer', name: _logName, error: e);
|
||||
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Error updating printer'),
|
||||
const PrinterFailure.dynamicErrorMessage('Error updating printer'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class PrinterLocalDataProvider {
|
||||
|
||||
if (deletedRows == 0) {
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage('Printer not found'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class PrinterLocalDataProvider {
|
||||
log('Error deleting printer', name: _logName, error: e);
|
||||
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Error deleting printer'),
|
||||
const PrinterFailure.dynamicErrorMessage('Error deleting printer'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class PrinterLocalDataProvider {
|
||||
|
||||
if (result.isEmpty) {
|
||||
log('Printer with code $code not found');
|
||||
return DC.error(PrinterFailure.empty());
|
||||
return DC.error(const PrinterFailure.empty());
|
||||
}
|
||||
|
||||
final printer = PrinterDto.fromJson(result.first);
|
||||
@@ -133,7 +133,7 @@ class PrinterLocalDataProvider {
|
||||
log('findPrinterByCode', name: _logName, error: e);
|
||||
|
||||
return DC.error(
|
||||
PrinterFailure.dynamicErrorMessage('Error getting printer'),
|
||||
const PrinterFailure.dynamicErrorMessage('Error getting printer'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,19 @@ class PrinterDto with _$PrinterDto {
|
||||
@JsonKey(name: 'updated_at') required DateTime updatedAt,
|
||||
}) = _PrinterDto;
|
||||
|
||||
factory PrinterDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$PrinterDtoFromJson(json);
|
||||
factory PrinterDto.fromJson(Map<String, dynamic> json) => _$PrinterDtoFromJson(
|
||||
// Normalize paper field: SQLite bisa return int atau String
|
||||
{
|
||||
...json,
|
||||
'paper': json['paper']?.toString() ?? '58',
|
||||
'created_at': json['created_at'] is DateTime
|
||||
? (json['created_at'] as DateTime).toIso8601String()
|
||||
: json['created_at'],
|
||||
'updated_at': json['updated_at'] is DateTime
|
||||
? (json['updated_at'] as DateTime).toIso8601String()
|
||||
: json['updated_at'],
|
||||
},
|
||||
);
|
||||
|
||||
// Optional mapper to domain
|
||||
Printer toDomain() => Printer(
|
||||
|
||||
@@ -5,7 +5,9 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||
import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../domain/order/order.dart';
|
||||
import '../../../domain/outlet/outlet.dart';
|
||||
import '../../../domain/printer/printer.dart';
|
||||
@@ -28,6 +30,14 @@ class PrinterRepository implements IPrinterRepository {
|
||||
this._authLocalDataProvider,
|
||||
);
|
||||
|
||||
final Map<String, Lock> _locks = {};
|
||||
final Lock _globalPrintLock = Lock();
|
||||
String? _connectedMac;
|
||||
|
||||
Lock _getLock(String address) {
|
||||
return _locks.putIfAbsent(address, () => Lock());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, bool>> connectBluetooth(
|
||||
String macAddress,
|
||||
@@ -78,7 +88,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
);
|
||||
log("Error connecting to Bluetooth printer", name: _logName, error: e);
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Error connecting to Bluetooth printer',
|
||||
),
|
||||
);
|
||||
@@ -94,7 +104,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
} catch (e) {
|
||||
log("Error disconnecting Bluetooth printer", error: e, name: _logName);
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Error disconnecting Bluetooth printer',
|
||||
),
|
||||
);
|
||||
@@ -113,7 +123,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
} catch (e) {
|
||||
log("Error getting paired Bluetooth devices", name: _logName, error: e);
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Error getting paired Bluetooth devices',
|
||||
),
|
||||
);
|
||||
@@ -129,7 +139,9 @@ class PrinterRepository implements IPrinterRepository {
|
||||
} catch (e) {
|
||||
log("Error checking Bluetooth status", name: _logName, error: e);
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage('Error checking Bluetooth status'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Error checking Bluetooth status',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -213,47 +225,67 @@ class PrinterRepository implements IPrinterRepository {
|
||||
Printer printer,
|
||||
List<int> printData,
|
||||
) async {
|
||||
try {
|
||||
log(printer.toString());
|
||||
if (printer.type == 'Bluetooth') {
|
||||
final connected = await connectBluetooth(printer.address);
|
||||
return await _getLock(printer.address).synchronized(() async {
|
||||
try {
|
||||
bool isConnected = await PrintBluetoothThermal.connectionStatus;
|
||||
|
||||
connected.fold(
|
||||
(f) {
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage(
|
||||
'Printer cannot connect to bluetooth, Please connect in printer setting!',
|
||||
),
|
||||
// Hanya reconnect jika memang perlu
|
||||
if (!isConnected || _connectedMac != printer.address) {
|
||||
// Disconnect hanya jika terhubung ke printer LAIN
|
||||
if (isConnected && _connectedMac != printer.address) {
|
||||
await PrintBluetoothThermal.disconnect;
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: 300),
|
||||
); // dari 1500ms
|
||||
}
|
||||
|
||||
bool connected = await PrintBluetoothThermal.connect(
|
||||
macPrinterAddress: printer.address,
|
||||
);
|
||||
},
|
||||
(connect) async {
|
||||
if (!connect) {
|
||||
|
||||
if (!connected) {
|
||||
_connectedMac = null;
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Failed to connect to Bluetooth printer',
|
||||
null,
|
||||
reason: 'Failed to connect to Bluetooth print',
|
||||
information: [
|
||||
'function: printStruct(Printer printer, List<int> printValue,)',
|
||||
'function: printStruct(Printer printer, List<int> printData)',
|
||||
'Printer: ${printer.name}',
|
||||
'macAddress: ${printer.address}',
|
||||
'in: $_logName',
|
||||
],
|
||||
);
|
||||
|
||||
return left(
|
||||
PrinterFailure.dynamicErrorMessage(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Printer cannot connect to bluetooth, Please connect in printer setting!',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool printResult = await _printBluetooth(printData);
|
||||
_connectedMac = printer.address;
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: 300),
|
||||
); // dari 1000ms
|
||||
}
|
||||
|
||||
log(
|
||||
'Printer connected to bluetooth: ${printer.name}, ${printer.address}',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
bool printResult = await _writeBytesChunked(printData);
|
||||
|
||||
// Hapus delay 1000ms setelah print — tidak perlu untuk hasil cetak
|
||||
log("Print result ${printer.name}: $printResult");
|
||||
|
||||
if (!printResult) {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Failed to print to ${printer.name}',
|
||||
null,
|
||||
information: [
|
||||
'function: await printBluetooth(printData);',
|
||||
'function: await _writeBytesChunked(printData)',
|
||||
'print: $printData',
|
||||
'in: $_logName',
|
||||
],
|
||||
@@ -266,9 +298,25 @@ class PrinterRepository implements IPrinterRepository {
|
||||
}
|
||||
|
||||
return right(printResult);
|
||||
},
|
||||
} catch (e, stackTrace) {
|
||||
_connectedMac = null;
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
e,
|
||||
stackTrace,
|
||||
reason: 'Error printing ${printer.name}',
|
||||
information: [
|
||||
'Printer: ${printer.name}',
|
||||
'MAC: ${printer.address}',
|
||||
],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Error printing struct'),
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Network printer tetap sama
|
||||
try {
|
||||
bool printResult = await _printNetwork(printer.address, printData);
|
||||
|
||||
if (!printResult) {
|
||||
@@ -277,7 +325,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
null,
|
||||
reason: 'Failed to connect to Network Printer',
|
||||
information: [
|
||||
'function: await printNetwork(printer.address, printData);',
|
||||
'function: await _printNetwork(printer.address, printData)',
|
||||
'Printer: ${printer.name}',
|
||||
'ipAddress: ${printer.address}',
|
||||
'print: $printData',
|
||||
@@ -285,63 +333,72 @@ class PrinterRepository implements IPrinterRepository {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return right(printResult);
|
||||
}
|
||||
|
||||
return right(false);
|
||||
} catch (e) {
|
||||
log("Error printing struct", name: _logName, error: e);
|
||||
return left(PrinterFailure.dynamicErrorMessage('Error printing struct'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _printBluetooth(List<int> printData) async {
|
||||
try {
|
||||
bool isConnected = await PrintBluetoothThermal.connectionStatus;
|
||||
|
||||
if (!isConnected) {
|
||||
log("Not connected to Bluetooth printer", name: _logName);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool printResult = await PrintBluetoothThermal.writeBytes(printData);
|
||||
if (printResult) {
|
||||
log("Successfully printed via Bluetooth", name: _logName);
|
||||
} else {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Failed to print via Bluetooth',
|
||||
null,
|
||||
reason: 'Failed to print via Bluetooth',
|
||||
information: [
|
||||
'function: printBluetooth(List<int> printData)',
|
||||
'printData: $printData',
|
||||
'in: $_logName',
|
||||
],
|
||||
);
|
||||
log("Failed to print via Bluetooth", name: _logName);
|
||||
}
|
||||
|
||||
return printResult;
|
||||
} catch (e, stackTrace) {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
e,
|
||||
stackTrace,
|
||||
reason: 'Error printing via Bluetooth',
|
||||
information: [
|
||||
'function: printBluetooth(List<int> printData)',
|
||||
'Printer: Bluetooth printer',
|
||||
'printData: $printData',
|
||||
'in: $_logName',
|
||||
],
|
||||
reason: 'Error printing ${printer.name}',
|
||||
information: ['Printer: ${printer.name}', 'IP: ${printer.address}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Error printing struct'),
|
||||
);
|
||||
log("Error printing via Bluetooth: $e", name: _logName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Future<bool> _printBluetooth(List<int> printData) async {
|
||||
// try {
|
||||
// bool isConnected = await PrintBluetoothThermal.connectionStatus;
|
||||
|
||||
// if (!isConnected) {
|
||||
// log("Not connected to Bluetooth printer", name: _logName);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// bool printResult = await PrintBluetoothThermal.writeBytes(printData);
|
||||
// if (printResult) {
|
||||
// log("Successfully printed via Bluetooth", name: _logName);
|
||||
// } else {
|
||||
// FirebaseCrashlytics.instance.recordError(
|
||||
// 'Failed to print via Bluetooth',
|
||||
// null,
|
||||
// reason: 'Failed to print via Bluetooth',
|
||||
// information: [
|
||||
// 'function: printBluetooth(List<int> printData)',
|
||||
// 'printData: $printData',
|
||||
// 'in: $_logName',
|
||||
// ],
|
||||
// );
|
||||
// log("Failed to print via Bluetooth", name: _logName);
|
||||
// }
|
||||
|
||||
// return printResult;
|
||||
// } catch (e, stackTrace) {
|
||||
// FirebaseCrashlytics.instance.recordError(
|
||||
// e,
|
||||
// stackTrace,
|
||||
// reason: 'Error printing via Bluetooth',
|
||||
// information: [
|
||||
// 'function: printBluetooth(List<int> printData)',
|
||||
// 'Printer: Bluetooth printer',
|
||||
// 'printData: $printData',
|
||||
// 'in: $_logName',
|
||||
// ],
|
||||
// );
|
||||
// log("Error printing via Bluetooth: $e", name: _logName);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<bool> _printNetwork(String ipAddress, List<int> printData) async {
|
||||
try {
|
||||
final printer = PrinterNetworkManager(ipAddress);
|
||||
final printer = PrinterNetworkManager(
|
||||
ipAddress,
|
||||
port: 9100,
|
||||
timeout: const Duration(seconds: 15),
|
||||
);
|
||||
PosPrintResult connect = await printer.connect();
|
||||
|
||||
if (connect == PosPrintResult.success) {
|
||||
@@ -402,27 +459,63 @@ class PrinterRepository implements IPrinterRepository {
|
||||
Future<Either<PrinterFailure, Unit>> printStruckOrder({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
try {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
|
||||
// Struck for customer
|
||||
if (order.totalPaid > 0) {
|
||||
_printReceipt(order: order, outlet: outlet, cashieName: user.name);
|
||||
final result = await _printReceipt(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (result.isLeft()) return result; // Jika gagal, return error
|
||||
}
|
||||
|
||||
// Struck for cashier
|
||||
_printCashier(order: order, outlet: outlet, cashieName: user.name);
|
||||
// Struck for kitchen
|
||||
_printKitchen(order: order, outlet: outlet, cashieName: user.name);
|
||||
final cashierResult = await _printCashier(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (cashierResult.isLeft()) return cashierResult;
|
||||
|
||||
// Struck for checker
|
||||
_printChecker(order: order, outlet: outlet, cashieName: user.name);
|
||||
final checkerResult = await _printChecker(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (checkerResult.isLeft()) return checkerResult;
|
||||
|
||||
// Struck for bar if exist product bar
|
||||
final itemsKitchen = order.orderItems.where(
|
||||
(item) => item.printerType == 'kitchen',
|
||||
);
|
||||
|
||||
if (itemsKitchen.isNotEmpty) {
|
||||
final kitchenResult = await _printKitchen(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (kitchenResult.isLeft()) return kitchenResult;
|
||||
}
|
||||
|
||||
// Struck for bar if exist product bar
|
||||
final itemsBar = order.orderItems.where(
|
||||
(item) => item.printerType == 'bar',
|
||||
);
|
||||
|
||||
if (itemsBar.isNotEmpty) {
|
||||
_printBar(order: order, outlet: outlet, cashieName: user.name);
|
||||
final barResult = await _printBar(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (barResult.isLeft()) return barResult;
|
||||
}
|
||||
|
||||
return right(unit);
|
||||
@@ -439,29 +532,61 @@ class PrinterRepository implements IPrinterRepository {
|
||||
const PrinterFailure.dynamicErrorMessage('Error printing order'),
|
||||
);
|
||||
}
|
||||
}); // end _globalPrintLock.synchronized
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckSaveOrder({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
try {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
|
||||
// Struck for cashier
|
||||
_printCashier(order: order, outlet: outlet, cashieName: user.name);
|
||||
// Struck for kitchen
|
||||
_printKitchen(order: order, outlet: outlet, cashieName: user.name);
|
||||
final cashierResult = await _printCashier(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (cashierResult.isLeft()) return cashierResult;
|
||||
|
||||
// Struck for checker
|
||||
_printChecker(order: order, outlet: outlet, cashieName: user.name);
|
||||
final checkerResult = await _printChecker(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (checkerResult.isLeft()) return checkerResult;
|
||||
|
||||
// Struck for kitchen
|
||||
// Struck for bar if exist product bar
|
||||
final itemsKitchen = order.orderItems.where(
|
||||
(item) => item.printerType == 'kitchen',
|
||||
);
|
||||
|
||||
if (itemsKitchen.isNotEmpty) {
|
||||
final kitchenResult = await _printKitchen(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (kitchenResult.isLeft()) return kitchenResult;
|
||||
}
|
||||
|
||||
// Struck for bar if exist product bar
|
||||
final itemsBar = order.orderItems.where(
|
||||
(item) => item.printerType == 'bar',
|
||||
);
|
||||
|
||||
if (itemsBar.isNotEmpty) {
|
||||
_printBar(order: order, outlet: outlet, cashieName: user.name);
|
||||
final barResult = await _printBar(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
if (barResult.isLeft()) return barResult;
|
||||
}
|
||||
|
||||
return right(unit);
|
||||
@@ -478,6 +603,55 @@ class PrinterRepository implements IPrinterRepository {
|
||||
const PrinterFailure.dynamicErrorMessage('Error printing save order'),
|
||||
);
|
||||
}
|
||||
}); // end _globalPrintLock.synchronized
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckCashier({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printCashier(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckVoid({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printVoid(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckSplitBill({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printSplitBill(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashieName: user.name,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckPayment({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printReceipt(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<PrinterFailure, Unit>> _printReceipt({
|
||||
@@ -497,11 +671,14 @@ class PrinterRepository implements IPrinterRepository {
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
await printStruct(printer, printValue);
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printed receipt', name: _logName);
|
||||
log('Printer Size: ', name: printer.paper);
|
||||
|
||||
return right(unit);
|
||||
} catch (e, stackTrace) {
|
||||
@@ -520,6 +697,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log('Receipt printer not found', name: _logName);
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Receipt printer not found',
|
||||
null,
|
||||
@@ -528,7 +706,9 @@ class PrinterRepository implements IPrinterRepository {
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Receipt printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Receipt printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -550,9 +730,11 @@ class PrinterRepository implements IPrinterRepository {
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
await printStruct(printer, printValue);
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printing cashier', name: _logName);
|
||||
|
||||
@@ -581,7 +763,9 @@ class PrinterRepository implements IPrinterRepository {
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Cashier printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Receipt printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -597,15 +781,25 @@ class PrinterRepository implements IPrinterRepository {
|
||||
);
|
||||
if (kitchenPrinter.hasData) {
|
||||
try {
|
||||
final productKitchen = order.orderItems
|
||||
.where((item) => item.printerType == 'kitchen')
|
||||
.toList();
|
||||
|
||||
if (productKitchen.isNotEmpty) {
|
||||
final printer = kitchenPrinter.data!.toDomain();
|
||||
|
||||
final printValue = await PrintUi().printKitchen(
|
||||
order: order,
|
||||
order: order.copyWith(orderItems: productKitchen),
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
await printStruct(printer, printValue);
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
} else {
|
||||
log('Product with printer type bar not found', name: _logName);
|
||||
}
|
||||
|
||||
log('Finished printed kitchen', name: _logName);
|
||||
|
||||
@@ -634,7 +828,9 @@ class PrinterRepository implements IPrinterRepository {
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Kitchen printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Kitchen printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -656,9 +852,11 @@ class PrinterRepository implements IPrinterRepository {
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
await printStruct(printer, printValue);
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printed checker', name: _logName);
|
||||
|
||||
@@ -679,6 +877,7 @@ class PrinterRepository implements IPrinterRepository {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log('Checker printer not found', name: _logName);
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Checker printer not found',
|
||||
null,
|
||||
@@ -687,7 +886,9 @@ class PrinterRepository implements IPrinterRepository {
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Checker printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Checker printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -709,12 +910,14 @@ class PrinterRepository implements IPrinterRepository {
|
||||
final printer = barPrinter.data!.toDomain();
|
||||
|
||||
final printValue = await PrintUi().printBar(
|
||||
order: order,
|
||||
order: order.copyWith(orderItems: productBar),
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
await printStruct(printer, printValue);
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printed bar', name: _logName);
|
||||
} else {
|
||||
@@ -744,8 +947,163 @@ class PrinterRepository implements IPrinterRepository {
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Bar printer not found'),
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Bar printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<PrinterFailure, Unit>> _printVoid({
|
||||
required Order order,
|
||||
required Outlet outlet,
|
||||
required String cashieName,
|
||||
}) async {
|
||||
log('Starting to print void', name: _logName);
|
||||
final voidPrinter = await _localDataProvider.findPrinterByCode('receipt');
|
||||
if (voidPrinter.hasData) {
|
||||
try {
|
||||
final printer = voidPrinter.data!.toDomain();
|
||||
|
||||
final printValue = await PrintUi().printVoid(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printed void', name: _logName);
|
||||
|
||||
return right(unit);
|
||||
} catch (e, stackTrace) {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Print Struck Void Error: $e',
|
||||
stackTrace,
|
||||
reason:
|
||||
'Print struck void error / Printer not setting in printer page',
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
log("Error printing void", name: _logName, error: e);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage('Error printing void order'),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Void printer not found',
|
||||
null,
|
||||
reason: 'Void printer not found / Printer not setting in printer page',
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Receipt printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<PrinterFailure, Unit>> _printSplitBill({
|
||||
required Order order,
|
||||
required Outlet outlet,
|
||||
required String cashieName,
|
||||
}) async {
|
||||
log('Starting to print splitBill', name: _logName);
|
||||
final splitBillPrinter = await _localDataProvider.findPrinterByCode(
|
||||
'receipt',
|
||||
);
|
||||
if (splitBillPrinter.hasData) {
|
||||
try {
|
||||
final printer = splitBillPrinter.data!.toDomain();
|
||||
|
||||
final printValue = await PrintUi().printSplit(
|
||||
order: order,
|
||||
outlet: outlet,
|
||||
cashierName: cashieName,
|
||||
paper: printer.paper.toIntegerFromText,
|
||||
);
|
||||
|
||||
final printResult = await printStruct(printer, printValue);
|
||||
if (printResult.isLeft()) return printResult.map((_) => unit);
|
||||
|
||||
log('Finished printed splitBill', name: _logName);
|
||||
|
||||
return right(unit);
|
||||
} catch (e, stackTrace) {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'Print Struck SplitBill Error: $e',
|
||||
stackTrace,
|
||||
reason:
|
||||
'Print struck splitBill error / Printer not setting in printer page',
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
log("Error printing splitBill", name: _logName, error: e);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Error printing splitBill order',
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
FirebaseCrashlytics.instance.recordError(
|
||||
'SplitBill printer not found',
|
||||
null,
|
||||
reason:
|
||||
'SplitBill printer not found / Printer not setting in printer page',
|
||||
information: ['Order ID: ${order.id}'],
|
||||
);
|
||||
return left(
|
||||
const PrinterFailure.dynamicErrorMessage(
|
||||
'Receipt printer belum terhubung, Silahkan hubungkan printer di pengaturan.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _writeBytesChunked(List<int> data, {int chunkSize = 512}) async {
|
||||
for (int i = 0; i < data.length; i += chunkSize) {
|
||||
final end = (i + chunkSize > data.length) ? data.length : i + chunkSize;
|
||||
final chunk = data.sublist(i, end);
|
||||
bool result = await PrintBluetoothThermal.writeBytes(chunk);
|
||||
if (!result) return false;
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckBar({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printBar(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckChecker({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printChecker(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<PrinterFailure, Unit>> printStruckKitchen({
|
||||
required Order order,
|
||||
}) async {
|
||||
return await _globalPrintLock.synchronized(() async {
|
||||
final outlet = await _outletLocalDatasource.currentOutlet();
|
||||
final user = await _authLocalDataProvider.currentUser();
|
||||
return _printKitchen(order: order, outlet: outlet, cashieName: user.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ class ProductLocalDataProvider {
|
||||
final _logName = 'ProductLocalDataProvider';
|
||||
|
||||
final Map<String, List<ProductDto>> _queryCache = {};
|
||||
final Duration _cacheExpiry = Duration(minutes: AppConstant.cacheExpire);
|
||||
final Duration _cacheExpiry = const Duration(
|
||||
minutes: AppConstant.cacheExpire,
|
||||
);
|
||||
final Map<String, DateTime> _cacheTimestamps = {};
|
||||
|
||||
ProductLocalDataProvider(this._databaseHelper);
|
||||
@@ -281,7 +283,7 @@ class ProductLocalDataProvider {
|
||||
|
||||
if (maps.isEmpty) {
|
||||
log('❌ Product not found: $id', name: _logName);
|
||||
return DC.error(ProductFailure.empty());
|
||||
return DC.error(const ProductFailure.empty());
|
||||
}
|
||||
|
||||
final variants = await _getProductVariants(db, id);
|
||||
|
||||
@@ -41,7 +41,7 @@ class ProductRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(ProductFailure.empty());
|
||||
return DC.error(const ProductFailure.empty());
|
||||
}
|
||||
|
||||
final categories = ListProductDto.fromJson(
|
||||
|
||||
@@ -40,6 +40,7 @@ class ProductDto with _$ProductDto {
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "image_url") String? imageUrl,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "is_active") bool? isActive,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@@ -63,6 +64,7 @@ class ProductDto with _$ProductDto {
|
||||
businessType: businessType ?? '',
|
||||
imageUrl: imageUrl ?? '',
|
||||
printerType: printerType ?? '',
|
||||
printToChecker: printToChecker ?? false,
|
||||
metadata: metadata ?? {},
|
||||
isActive: isActive ?? false,
|
||||
createdAt: createdAt ?? '',
|
||||
@@ -82,6 +84,7 @@ class ProductDto with _$ProductDto {
|
||||
'business_type': businessType,
|
||||
'image_url': imageUrl,
|
||||
'printer_type': printerType,
|
||||
'print_to_checker': printToChecker == true ? 1 : 0,
|
||||
'metadata': metadata != null ? jsonEncode(metadata) : null,
|
||||
'is_active': isActive == true ? 1 : 0,
|
||||
'created_at': createdAt,
|
||||
@@ -103,6 +106,9 @@ class ProductDto with _$ProductDto {
|
||||
businessType: map['business_type'] as String?,
|
||||
imageUrl: map['image_url'] as String?,
|
||||
printerType: map['printer_type'] as String?,
|
||||
printToChecker: map['print_to_checker'] != null
|
||||
? (map['print_to_checker'] as int) == 1
|
||||
: null,
|
||||
metadata: map['metadata'] != null
|
||||
? jsonDecode(map['metadata'] as String) as Map<String, dynamic>
|
||||
: null,
|
||||
@@ -125,6 +131,7 @@ class ProductDto with _$ProductDto {
|
||||
businessType: product.businessType,
|
||||
imageUrl: product.imageUrl,
|
||||
printerType: product.printerType,
|
||||
printToChecker: product.printToChecker,
|
||||
metadata: product.metadata,
|
||||
isActive: product.isActive,
|
||||
createdAt: product.createdAt,
|
||||
|
||||
@@ -321,6 +321,8 @@ mixin _$ProductDto {
|
||||
String? get imageUrl => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "printer_type")
|
||||
String? get printerType => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "print_to_checker")
|
||||
bool? get printToChecker => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "metadata")
|
||||
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "is_active")
|
||||
@@ -361,6 +363,7 @@ abstract class $ProductDtoCopyWith<$Res> {
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "image_url") String? imageUrl,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "is_active") bool? isActive,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@@ -395,6 +398,7 @@ class _$ProductDtoCopyWithImpl<$Res, $Val extends ProductDto>
|
||||
Object? businessType = freezed,
|
||||
Object? imageUrl = freezed,
|
||||
Object? printerType = freezed,
|
||||
Object? printToChecker = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? isActive = freezed,
|
||||
Object? createdAt = freezed,
|
||||
@@ -447,6 +451,10 @@ class _$ProductDtoCopyWithImpl<$Res, $Val extends ProductDto>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
printToChecker: freezed == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
metadata: freezed == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
@@ -494,6 +502,7 @@ abstract class _$$ProductDtoImplCopyWith<$Res>
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "image_url") String? imageUrl,
|
||||
@JsonKey(name: "printer_type") String? printerType,
|
||||
@JsonKey(name: "print_to_checker") bool? printToChecker,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "is_active") bool? isActive,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@@ -527,6 +536,7 @@ class __$$ProductDtoImplCopyWithImpl<$Res>
|
||||
Object? businessType = freezed,
|
||||
Object? imageUrl = freezed,
|
||||
Object? printerType = freezed,
|
||||
Object? printToChecker = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? isActive = freezed,
|
||||
Object? createdAt = freezed,
|
||||
@@ -579,6 +589,10 @@ class __$$ProductDtoImplCopyWithImpl<$Res>
|
||||
? _value.printerType
|
||||
: printerType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
printToChecker: freezed == printToChecker
|
||||
? _value.printToChecker
|
||||
: printToChecker // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
metadata: freezed == metadata
|
||||
? _value._metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
@@ -619,6 +633,7 @@ class _$ProductDtoImpl extends _ProductDto {
|
||||
@JsonKey(name: "business_type") this.businessType,
|
||||
@JsonKey(name: "image_url") this.imageUrl,
|
||||
@JsonKey(name: "printer_type") this.printerType,
|
||||
@JsonKey(name: "print_to_checker") this.printToChecker,
|
||||
@JsonKey(name: "metadata") final Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "is_active") this.isActive,
|
||||
@JsonKey(name: "created_at") this.createdAt,
|
||||
@@ -664,6 +679,9 @@ class _$ProductDtoImpl extends _ProductDto {
|
||||
@override
|
||||
@JsonKey(name: "printer_type")
|
||||
final String? printerType;
|
||||
@override
|
||||
@JsonKey(name: "print_to_checker")
|
||||
final bool? printToChecker;
|
||||
final Map<String, dynamic>? _metadata;
|
||||
@override
|
||||
@JsonKey(name: "metadata")
|
||||
@@ -697,7 +715,7 @@ class _$ProductDtoImpl extends _ProductDto {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProductDto(id: $id, organizationId: $organizationId, categoryId: $categoryId, sku: $sku, name: $name, description: $description, price: $price, cost: $cost, businessType: $businessType, imageUrl: $imageUrl, printerType: $printerType, metadata: $metadata, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, variants: $variants)';
|
||||
return 'ProductDto(id: $id, organizationId: $organizationId, categoryId: $categoryId, sku: $sku, name: $name, description: $description, price: $price, cost: $cost, businessType: $businessType, imageUrl: $imageUrl, printerType: $printerType, printToChecker: $printToChecker, metadata: $metadata, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt, variants: $variants)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -722,6 +740,8 @@ class _$ProductDtoImpl extends _ProductDto {
|
||||
other.imageUrl == imageUrl) &&
|
||||
(identical(other.printerType, printerType) ||
|
||||
other.printerType == printerType) &&
|
||||
(identical(other.printToChecker, printToChecker) ||
|
||||
other.printToChecker == printToChecker) &&
|
||||
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
|
||||
(identical(other.isActive, isActive) ||
|
||||
other.isActive == isActive) &&
|
||||
@@ -747,6 +767,7 @@ class _$ProductDtoImpl extends _ProductDto {
|
||||
businessType,
|
||||
imageUrl,
|
||||
printerType,
|
||||
printToChecker,
|
||||
const DeepCollectionEquality().hash(_metadata),
|
||||
isActive,
|
||||
createdAt,
|
||||
@@ -781,6 +802,7 @@ abstract class _ProductDto extends ProductDto {
|
||||
@JsonKey(name: "business_type") final String? businessType,
|
||||
@JsonKey(name: "image_url") final String? imageUrl,
|
||||
@JsonKey(name: "printer_type") final String? printerType,
|
||||
@JsonKey(name: "print_to_checker") final bool? printToChecker,
|
||||
@JsonKey(name: "metadata") final Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "is_active") final bool? isActive,
|
||||
@JsonKey(name: "created_at") final String? createdAt,
|
||||
@@ -826,6 +848,9 @@ abstract class _ProductDto extends ProductDto {
|
||||
@JsonKey(name: "printer_type")
|
||||
String? get printerType;
|
||||
@override
|
||||
@JsonKey(name: "print_to_checker")
|
||||
bool? get printToChecker;
|
||||
@override
|
||||
@JsonKey(name: "metadata")
|
||||
Map<String, dynamic>? get metadata;
|
||||
@override
|
||||
|
||||
@@ -40,6 +40,7 @@ _$ProductDtoImpl _$$ProductDtoImplFromJson(Map<String, dynamic> json) =>
|
||||
businessType: json['business_type'] as String?,
|
||||
imageUrl: json['image_url'] as String?,
|
||||
printerType: json['printer_type'] as String?,
|
||||
printToChecker: json['print_to_checker'] as bool?,
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
isActive: json['is_active'] as bool?,
|
||||
createdAt: json['created_at'] as String?,
|
||||
@@ -62,6 +63,7 @@ Map<String, dynamic> _$$ProductDtoImplToJson(_$ProductDtoImpl instance) =>
|
||||
'business_type': instance.businessType,
|
||||
'image_url': instance.imageUrl,
|
||||
'printer_type': instance.printerType,
|
||||
'print_to_checker': instance.printToChecker,
|
||||
'metadata': instance.metadata,
|
||||
'is_active': instance.isActive,
|
||||
'created_at': instance.createdAt,
|
||||
|
||||
@@ -38,7 +38,7 @@ class TableRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(TableFailure.empty());
|
||||
return DC.error(const TableFailure.empty());
|
||||
}
|
||||
|
||||
final tables = ListTableDto.fromJson(
|
||||
@@ -71,7 +71,7 @@ class TableRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(TableFailure.unexpectedError());
|
||||
return DC.error(const TableFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final table = TableDto.fromJson(
|
||||
@@ -99,7 +99,7 @@ class TableRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(TableFailure.unexpectedError());
|
||||
return DC.error(const TableFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final table = TableDto.fromJson(
|
||||
@@ -124,7 +124,7 @@ class TableRemoteDataProvider {
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(TableFailure.unexpectedError());
|
||||
return DC.error(const TableFailure.unexpectedError());
|
||||
}
|
||||
|
||||
return DC.data(unit);
|
||||
|
||||
+94
-44
@@ -26,6 +26,8 @@ import 'package:apskel_pos_flutter_v2/application/analytic/sales_analytic_loader
|
||||
import 'package:apskel_pos_flutter_v2/application/auth/auth_bloc.dart' as _i343;
|
||||
import 'package:apskel_pos_flutter_v2/application/auth/login_form/login_form_bloc.dart'
|
||||
as _i46;
|
||||
import 'package:apskel_pos_flutter_v2/application/auth/logout/logout_bloc.dart'
|
||||
as _i641;
|
||||
import 'package:apskel_pos_flutter_v2/application/category/category_loader/category_loader_bloc.dart'
|
||||
as _i1018;
|
||||
import 'package:apskel_pos_flutter_v2/application/checkout/checkout_form/checkout_form_bloc.dart'
|
||||
@@ -63,6 +65,8 @@ import 'package:apskel_pos_flutter_v2/application/report/report_bloc.dart'
|
||||
import 'package:apskel_pos_flutter_v2/application/split_bill/split_bill_form/split_bill_form_bloc.dart'
|
||||
as _i334;
|
||||
import 'package:apskel_pos_flutter_v2/application/sync/sync_bloc.dart' as _i741;
|
||||
import 'package:apskel_pos_flutter_v2/application/sync/sync_setting/sync_setting_bloc.dart'
|
||||
as _i729;
|
||||
import 'package:apskel_pos_flutter_v2/application/table/table_form/table_form_bloc.dart'
|
||||
as _i248;
|
||||
import 'package:apskel_pos_flutter_v2/application/table/table_loader/table_loader_bloc.dart'
|
||||
@@ -76,10 +80,14 @@ import 'package:apskel_pos_flutter_v2/common/di/di_auto_route.dart' as _i729;
|
||||
import 'package:apskel_pos_flutter_v2/common/di/di_connectivity.dart' as _i807;
|
||||
import 'package:apskel_pos_flutter_v2/common/di/di_database.dart' as _i209;
|
||||
import 'package:apskel_pos_flutter_v2/common/di/di_dio.dart' as _i86;
|
||||
import 'package:apskel_pos_flutter_v2/common/di/di_firebase.dart' as _i857;
|
||||
import 'package:apskel_pos_flutter_v2/common/di/di_shared_preferences.dart'
|
||||
as _i135;
|
||||
import 'package:apskel_pos_flutter_v2/common/network/network_client.dart'
|
||||
as _i171;
|
||||
import 'package:apskel_pos_flutter_v2/common/service/device_info_service.dart'
|
||||
as _i288;
|
||||
import 'package:apskel_pos_flutter_v2/common/service/fcm_service.dart' as _i312;
|
||||
import 'package:apskel_pos_flutter_v2/domain/analytic/analytic.dart' as _i346;
|
||||
import 'package:apskel_pos_flutter_v2/domain/auth/auth.dart' as _i776;
|
||||
import 'package:apskel_pos_flutter_v2/domain/category/category.dart' as _i502;
|
||||
@@ -143,9 +151,14 @@ import 'package:apskel_pos_flutter_v2/infrastructure/table/repositories/table_re
|
||||
import 'package:apskel_pos_flutter_v2/presentation/router/app_router.dart'
|
||||
as _i800;
|
||||
import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
|
||||
import 'package:device_info_plus/device_info_plus.dart' as _i833;
|
||||
import 'package:dio/dio.dart' as _i361;
|
||||
import 'package:firebase_messaging/firebase_messaging.dart' as _i892;
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart'
|
||||
as _i163;
|
||||
import 'package:get_it/get_it.dart' as _i174;
|
||||
import 'package:injectable/injectable.dart' as _i526;
|
||||
import 'package:package_info_plus/package_info_plus.dart' as _i655;
|
||||
import 'package:shared_preferences/shared_preferences.dart' as _i460;
|
||||
|
||||
const String _dev = 'dev';
|
||||
@@ -158,23 +171,39 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
_i526.EnvironmentFilter? environmentFilter,
|
||||
}) async {
|
||||
final gh = _i526.GetItHelper(this, environment, environmentFilter);
|
||||
final firebaseDi = _$FirebaseDi();
|
||||
final sharedPreferencesDi = _$SharedPreferencesDi();
|
||||
final databaseDi = _$DatabaseDi();
|
||||
final dioDi = _$DioDi();
|
||||
final autoRouteDi = _$AutoRouteDi();
|
||||
final connectivityDi = _$ConnectivityDi();
|
||||
final dioDi = _$DioDi();
|
||||
gh.factory<_i13.CheckoutFormBloc>(() => _i13.CheckoutFormBloc());
|
||||
gh.factory<_i96.PrinterBloc>(() => _i96.PrinterBloc());
|
||||
gh.factory<_i257.ReportBloc>(() => _i257.ReportBloc());
|
||||
gh.factory<_i334.SplitBillFormBloc>(() => _i334.SplitBillFormBloc());
|
||||
await gh.factoryAsync<_i655.PackageInfo>(
|
||||
() => firebaseDi.packageInfo,
|
||||
preResolve: true,
|
||||
);
|
||||
await gh.factoryAsync<_i460.SharedPreferences>(
|
||||
() => sharedPreferencesDi.prefs,
|
||||
preResolve: true,
|
||||
);
|
||||
gh.factory<_i334.SplitBillFormBloc>(() => _i334.SplitBillFormBloc());
|
||||
gh.factory<_i96.PrinterBloc>(() => _i96.PrinterBloc());
|
||||
gh.factory<_i13.CheckoutFormBloc>(() => _i13.CheckoutFormBloc());
|
||||
gh.factory<_i257.ReportBloc>(() => _i257.ReportBloc());
|
||||
gh.singleton<_i487.DatabaseHelper>(() => databaseDi.databaseHelper);
|
||||
gh.lazySingleton<_i361.Dio>(() => dioDi.dio);
|
||||
gh.lazySingleton<_i800.AppRouter>(() => autoRouteDi.appRouter);
|
||||
gh.lazySingleton<_i895.Connectivity>(() => connectivityDi.connectivity);
|
||||
gh.lazySingleton<_i361.Dio>(() => dioDi.dio);
|
||||
gh.lazySingleton<_i892.FirebaseMessaging>(() => firebaseDi.messaging);
|
||||
gh.lazySingleton<_i163.FlutterLocalNotificationsPlugin>(
|
||||
() => firebaseDi.localNotifications,
|
||||
);
|
||||
gh.lazySingleton<_i833.DeviceInfoPlugin>(() => firebaseDi.deviceInfo);
|
||||
gh.lazySingleton<_i288.DeviceInfoService>(
|
||||
() => _i288.DeviceInfoService(
|
||||
gh<_i833.DeviceInfoPlugin>(),
|
||||
gh<_i655.PackageInfo>(),
|
||||
),
|
||||
);
|
||||
gh.lazySingleton<_i171.NetworkClient>(
|
||||
() => _i171.NetworkClient(gh<_i895.Connectivity>()),
|
||||
);
|
||||
@@ -188,6 +217,12 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i464.ProductLocalDataProvider>(
|
||||
() => _i464.ProductLocalDataProvider(gh<_i487.DatabaseHelper>()),
|
||||
);
|
||||
gh.lazySingleton<_i312.FcmService>(
|
||||
() => _i312.FcmService(
|
||||
gh<_i892.FirebaseMessaging>(),
|
||||
gh<_i163.FlutterLocalNotificationsPlugin>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i204.AuthLocalDataProvider>(
|
||||
() => _i204.AuthLocalDataProvider(gh<_i460.SharedPreferences>()),
|
||||
);
|
||||
@@ -205,26 +240,35 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh<_i204.AuthLocalDataProvider>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i903.BluetoothLoaderBloc>(
|
||||
() => _i903.BluetoothLoaderBloc(gh<_i104.IPrinterRepository>()),
|
||||
);
|
||||
gh.factory<_i489.BluetoothConnectBloc>(
|
||||
() => _i489.BluetoothConnectBloc(gh<_i104.IPrinterRepository>()),
|
||||
);
|
||||
gh.factory<_i903.BluetoothLoaderBloc>(
|
||||
() => _i903.BluetoothLoaderBloc(gh<_i104.IPrinterRepository>()),
|
||||
);
|
||||
gh.factory<_i1028.PrinterLoaderBloc>(
|
||||
() => _i1028.PrinterLoaderBloc(gh<_i104.IPrinterRepository>()),
|
||||
);
|
||||
gh.factory<_i21.PrintStruckBloc>(
|
||||
() => _i21.PrintStruckBloc(gh<_i104.IPrinterRepository>()),
|
||||
);
|
||||
gh.factory<_i360.OrderRemoteDataProvider>(
|
||||
() => _i360.OrderRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
gh.factory<_i708.AnalyticRemoteDataProvider>(
|
||||
() => _i708.AnalyticRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i370.AuthRemoteDataProvider>(
|
||||
() => _i370.AuthRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i856.CategoryRemoteDataProvider>(
|
||||
() => _i856.CategoryRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i370.AuthRemoteDataProvider>(
|
||||
() => _i370.AuthRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
gh.factory<_i841.CustomerRemoteDataProvider>(
|
||||
() => _i841.CustomerRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i360.OrderRemoteDataProvider>(
|
||||
() => _i360.OrderRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i132.OutletRemoteDataProvider>(
|
||||
() => _i132.OutletRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i833.PaymentMethodRemoteDataProvider>(
|
||||
() => _i833.PaymentMethodRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
@@ -232,18 +276,9 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i707.ProductRemoteDataProvider>(
|
||||
() => _i707.ProductRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i132.OutletRemoteDataProvider>(
|
||||
() => _i132.OutletRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i95.TableRemoteDataProvider>(
|
||||
() => _i95.TableRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i708.AnalyticRemoteDataProvider>(
|
||||
() => _i708.AnalyticRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i841.CustomerRemoteDataProvider>(
|
||||
() => _i841.CustomerRemoteDataProvider(gh<_i457.ApiClient>()),
|
||||
);
|
||||
gh.factory<_i776.IAuthRepository>(
|
||||
() => _i941.AuthRepository(
|
||||
gh<_i370.AuthRemoteDataProvider>(),
|
||||
@@ -256,6 +291,13 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh<_i708.CategoryLocalDataProvider>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i46.LoginFormBloc>(
|
||||
() => _i46.LoginFormBloc(
|
||||
gh<_i776.IAuthRepository>(),
|
||||
gh<_i312.FcmService>(),
|
||||
gh<_i288.DeviceInfoService>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i983.ITableRepository>(
|
||||
() => _i824.TableRepository(
|
||||
gh<_i95.TableRemoteDataProvider>(),
|
||||
@@ -288,8 +330,8 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh<_i833.PaymentMethodRemoteDataProvider>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i46.LoginFormBloc>(
|
||||
() => _i46.LoginFormBloc(gh<_i776.IAuthRepository>()),
|
||||
gh.factory<_i641.LogoutBloc>(
|
||||
() => _i641.LogoutBloc(gh<_i776.IAuthRepository>()),
|
||||
);
|
||||
gh.factory<_i1018.CategoryLoaderBloc>(
|
||||
() => _i1018.CategoryLoaderBloc(gh<_i502.ICategoryRepository>()),
|
||||
@@ -315,12 +357,12 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i194.PaymentFormBloc>(
|
||||
() => _i194.PaymentFormBloc(gh<_i299.IOrderRepository>()),
|
||||
);
|
||||
gh.factory<_i822.VoidFormBloc>(
|
||||
() => _i822.VoidFormBloc(gh<_i299.IOrderRepository>()),
|
||||
);
|
||||
gh.factory<_i837.RefundFormBloc>(
|
||||
() => _i837.RefundFormBloc(gh<_i299.IOrderRepository>()),
|
||||
);
|
||||
gh.factory<_i822.VoidFormBloc>(
|
||||
() => _i822.VoidFormBloc(gh<_i299.IOrderRepository>()),
|
||||
);
|
||||
gh.factory<_i683.CustomerLoaderBloc>(
|
||||
() => _i683.CustomerLoaderBloc(gh<_i143.ICustomerRepository>()),
|
||||
);
|
||||
@@ -348,21 +390,10 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh<_i502.ICategoryRepository>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i268.ProductAnalyticLoaderBloc>(
|
||||
() => _i268.ProductAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i651.InventoryAnalyticLoaderBloc>(
|
||||
() => _i651.InventoryAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i741.ProfitLossAnalyticLoaderBloc>(
|
||||
() => _i741.ProfitLossAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i413.SalesAnalyticLoaderBloc>(
|
||||
() => _i413.SalesAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i733.PaymentMethodAnalyticLoaderBloc>(
|
||||
() => _i733.PaymentMethodAnalyticLoaderBloc(
|
||||
gh<_i346.IAnalyticRepository>(),
|
||||
gh.factory<_i729.SyncSettingBloc>(
|
||||
() => _i729.SyncSettingBloc(
|
||||
gh<_i44.IProductRepository>(),
|
||||
gh<_i502.ICategoryRepository>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i911.CategoryAnalyticLoaderBloc>(
|
||||
@@ -371,16 +402,35 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i80.DashboardAnalyticLoaderBloc>(
|
||||
() => _i80.DashboardAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i651.InventoryAnalyticLoaderBloc>(
|
||||
() => _i651.InventoryAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i733.PaymentMethodAnalyticLoaderBloc>(
|
||||
() => _i733.PaymentMethodAnalyticLoaderBloc(
|
||||
gh<_i346.IAnalyticRepository>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i268.ProductAnalyticLoaderBloc>(
|
||||
() => _i268.ProductAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i741.ProfitLossAnalyticLoaderBloc>(
|
||||
() => _i741.ProfitLossAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
gh.factory<_i413.SalesAnalyticLoaderBloc>(
|
||||
() => _i413.SalesAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class _$FirebaseDi extends _i857.FirebaseDi {}
|
||||
|
||||
class _$SharedPreferencesDi extends _i135.SharedPreferencesDi {}
|
||||
|
||||
class _$DatabaseDi extends _i209.DatabaseDi {}
|
||||
|
||||
class _$DioDi extends _i86.DioDi {}
|
||||
|
||||
class _$AutoRouteDi extends _i729.AutoRouteDi {}
|
||||
|
||||
class _$ConnectivityDi extends _i807.ConnectivityDi {}
|
||||
|
||||
class _$DioDi extends _i86.DioDi {}
|
||||
|
||||
+6
-4
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import 'common/service/fcm_service.dart';
|
||||
import 'injection.dart';
|
||||
import 'presentation/app_widget.dart';
|
||||
|
||||
@@ -43,14 +44,15 @@ void main() async {
|
||||
debugPrint = (message, {wrapWidth}) => '';
|
||||
}
|
||||
|
||||
await configureDependencies(
|
||||
kReleaseMode ? Environment.prod : Environment.dev,
|
||||
);
|
||||
const String env = String.fromEnvironment('ENV', defaultValue: 'dev');
|
||||
await configureDependencies(env);
|
||||
|
||||
// Inisialisasi FCM setelah DI siap
|
||||
await getIt<FcmService>().initialize();
|
||||
|
||||
runApp(const AppWidget());
|
||||
},
|
||||
(error, stack) {
|
||||
// ✅ Ini udah bener
|
||||
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../application/auth/auth_bloc.dart';
|
||||
import '../application/auth/logout/logout_bloc.dart';
|
||||
import '../application/category/category_loader/category_loader_bloc.dart';
|
||||
import '../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../application/customer/customer_loader/customer_loader_bloc.dart';
|
||||
@@ -15,6 +16,7 @@ import '../application/printer/print_struck/print_struck_bloc.dart';
|
||||
import '../application/printer/printer_form/printer_form_bloc.dart';
|
||||
import '../application/printer/printer_loader/printer_loader_bloc.dart';
|
||||
import '../application/product/product_loader/product_loader_bloc.dart';
|
||||
import '../application/sync/sync_setting/sync_setting_bloc.dart';
|
||||
import '../application/table/table_form/table_form_bloc.dart';
|
||||
import '../application/table/table_loader/table_loader_bloc.dart';
|
||||
import '../application/void/void_form/void_form_bloc.dart';
|
||||
@@ -55,6 +57,8 @@ class _AppWidgetState extends State<AppWidget> {
|
||||
BlocProvider(create: (context) => getIt<PrinterFormBloc>()),
|
||||
BlocProvider(create: (context) => getIt<PrinterLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<PrintStruckBloc>()),
|
||||
BlocProvider(create: (context) => getIt<SyncSettingBloc>()),
|
||||
BlocProvider(create: (context) => getIt<LogoutBloc>()),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
@@ -10,7 +10,7 @@ class AppIconButton extends StatelessWidget {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
border: Border.all(color: AppColor.border),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user