diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1198130..6345584 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..94b8f71 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..feb2461 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..0318c6d 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..5346a4d 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..31b8796 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..ab98328 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #ffffff + \ No newline at end of file diff --git a/assets/img/siopas_apps.png b/assets/img/siopas_apps.png new file mode 100644 index 0000000..d85ef65 Binary files /dev/null and b/assets/img/siopas_apps.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc9ada4..6f02f64 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 7353c41..cd2103f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 797d452..208e4bf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6ed2d93..f4b6ce8 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cd7b00..8fb6a2a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index fe73094..55836bc 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 321773c..f474548 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 797d452..208e4bf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 502f463..2843a7c 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 0ec3034..533094e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..133f724 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..ba6764f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..263d2fe Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..35f5050 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 0ec3034..533094e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index e9f5fea..036e85c 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..94b8f71 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..5346a4d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 84ac32a..57d9a73 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 8953cba..09f6152 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 0467bf1..7d1f591 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index fde44d2..dc12d9a 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -17,7 +17,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - siopas + SIOPAS ISTW CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/connection/connection.dart b/lib/connection/connection.dart index 94c8d2f..c3a98df 100644 --- a/lib/connection/connection.dart +++ b/lib/connection/connection.dart @@ -1,4 +1,25 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -String baseUrl = 'http://192.168.0.20:8000/api/v1'; +import 'package:shared_preferences/shared_preferences.dart'; + +Future getBaseUrl() async { + try { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String ipAddress = + prefs.getString('ipAddress') ?? '192.168.0.18'; // Default value + String port = prefs.getString('port') ?? '8000'; // Default value + + String baseUrl = 'http://$ipAddress:$port/api/v1'; + + return baseUrl; + } catch (e) { + // Penanganan kesalahan + print('Error reading SharedPreferences: $e'); + return ''; // Atau nilai default lainnya jika terjadi kesalahan + } +} + + // return 'http://$ipAddress:$port/api/v1'; +// String baseUrl = 'http://192.168.0.18:8000/api/v1'; +// Gunakan fungsi ini saat diperlukan, misalnya di tempat-tempat yang membutuhkan baseUrl +// Contoh penggunaan: String url = await getBaseUrl(); diff --git a/lib/main.dart b/lib/main.dart index 10eeaef..414d8e8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,36 +1,54 @@ import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/migrations/databasehelper.dart'; +import 'package:siopas/pages/transfer_peti/edit.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:siopas/pages/pengembalian_barang/edit.dart'; -import 'package:siopas/pages/pengembalian_barang/pengembalian_index.dart'; -import 'package:siopas/pages/transfer_peti/edit.dart'; -import 'package:siopas/pages/transfer_peti/transfer_peti_index.dart'; import 'pages/home/main_page.dart'; import 'pages/peminjaman_barang/peminjaman_stock_page.dart'; import 'pages/peminjaman_barang/create.dart'; import 'pages/peminjaman_barang/show.dart'; +import 'pages/pengembalian_barang/edit.dart'; +import 'pages/pengembalian_barang/index.dart'; import 'pages/sign_in_page.dart'; import 'pages/splash_page.dart'; -import 'pages/transfer_peti/show.dart'; +import 'pages/transfer_peti/index.dart'; import 'providers/asset_status_provider.dart'; import 'providers/auth_provider.dart'; import 'providers/m_status_provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - // SharedPreferences prefs = await SharedPreferences.getInstance(); - // var email = prefs.getString("email"); - // var password = prefs.getString("password"); - // var token = prefs.getString("token"); - // await Firebase.initializeApp(); - runApp(MyApp()); + await SqfliteDatabaseHelper.instance.db; SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, // Atur orientasi ke potrait ]); + runApp(MyApp()); + configLoading(); // Pindahkan baris ini ke sini setelah runApp +} + +void configLoading() { + EasyLoading.instance + ..displayDuration = const Duration(milliseconds: 2000) + ..indicatorType = EasyLoadingIndicatorType.fadingCircle + ..loadingStyle = EasyLoadingStyle.dark + ..indicatorSize = 45.0 + ..radius = 10.0 + ..progressColor = Colors.yellow + ..backgroundColor = Colors.green + ..indicatorColor = Colors.yellow + ..textColor = Colors.yellow + ..maskColor = Colors.blue.withOpacity(0.5) + ..userInteractions = true + ..dismissOnTap = false; } class MyApp extends StatelessWidget { + MyApp() { + EasyLoading.init(); // Inisialisasi EasyLoading + } + @override Widget build(BuildContext context) { return MultiProvider( @@ -51,18 +69,19 @@ class MyApp extends StatelessWidget { visualDensity: VisualDensity.adaptivePlatformDensity, ), debugShowCheckedModeBanner: false, + home: SplashPage(), routes: { - '/': (context) => SplashPage(), '/sign-in': (context) => SignInPage(), '/home': (context) => MainPage(), '/peminjaman-barang': (context) => AssetStatusPage(), '/peminjaman-barang/create': (context) => CreatePeminjamanBarang(), '/pengembalian-barang': (context) => PengembalianBarangPage(), - '/pengembalian-barang/create': (context) => + '/pengembalian-barang/edit': (context) => CreatePengembalianBarangPage(), '/transfer-peti': (context) => TransferPetiPage(), '/transfer-peti/edit': (context) => EditTransferPetiPage(), }, + builder: EasyLoading.init(), ), ); } diff --git a/lib/migrations/databasehelper.dart b/lib/migrations/databasehelper.dart new file mode 100644 index 0000000..ee8870c --- /dev/null +++ b/lib/migrations/databasehelper.dart @@ -0,0 +1,265 @@ +import 'dart:io'; + +import 'package:path_provider/path_provider.dart'; +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +import '../models/warehouse_mode.dart'; + +class SqfliteDatabaseHelper { + SqfliteDatabaseHelper.internal(); + static final SqfliteDatabaseHelper instance = + SqfliteDatabaseHelper.internal(); + factory SqfliteDatabaseHelper() => instance; + + static final warehouseTable = 'm_warehouses'; + static final typePetiTable = 'type_petis'; + static final conditionPetiTable = 'kondisi_petis'; + static final customerTable = 'customers'; + static final petiTable = 'petis'; + static final transferPetiTable = 'transfers'; + static final disposalTable = 'disposals'; + + static final asset_statusesTable = 'asset_statuses'; + // static final assetLocalTable = 'asset_statuses_local'; + + static final peminjamanTable = 'peminjamans'; + static final pengembalianTable = 'pengembalians'; + + static final _version = 1; // Versi database ditingkatkan + + Database? _db; + + Future get db async { + if (_db != null) { + return _db; + } + _db = await initDb(); + return _db; + } + + Future saveWarehouseList(List warehouseList) async { + final dbClient = await db; + try { + await dbClient!.transaction((txn) async { + var batch = txn.batch(); + for (var warehouse in warehouseList) { + batch.insert( + warehouseTable, + warehouse.toJson(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + await batch.commit(); + }); + } catch (e) { + print('Error saving warehouse list to SQLite: $e'); + } + } + + Future initDb() async { + final Directory directory = await getApplicationDocumentsDirectory(); + String dbPath = join(directory.path, 'siopas.db'); + print(dbPath); + var openDb = await openDatabase(dbPath, version: _version, + onCreate: (Database db, int version) async { + await db.execute(""" + CREATE TABLE $peminjamanTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id INTEGER NULL, + peti_id INTEGER NULL, + customer_id INTEGER NULL, + warehouse_id INTEGER NULL, + exit_at DATETIME NULL, + est_pengembalian DATETIME NULL, + exit_pic TEXT NULL, + exit_warehouse INTEGER NULL, + enter_at DATETIME NULL, + enter_pic TEXT NULL, + enter_warehouse INTEGER NULL, + kondisi_peti_id INTEGER NULL, + status INTEGER NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $pengembalianTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id INTEGER NULL, + peti_id INTEGER NULL, + customer_id INTEGER NULL, + warehouse_id INTEGER NULL, + exit_at DATETIME NULL, + est_pengembalian DATETIME NULL, + exit_pic TEXT NULL, + exit_warehouse INTEGER NULL, + enter_at DATETIME NULL, + enter_pic TEXT NULL, + enter_warehouse INTEGER NULL, + kondisi_peti_id INTEGER NULL, + status INTEGER NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $asset_statusesTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id INTEGER NOT NULL, + peti_id INTEGER NULL, + customer_id INTEGER NULL, + warehouse_id INTEGER NULL, + exit_at DATETIME NULL, + est_pengembalian DATETIME NULL, + exit_pic TEXT NULL, + exit_warehouse INTEGER NULL, + enter_at DATETIME NULL, + enter_pic TEXT NULL, + enter_warehouse INTEGER NULL, + kondisi_peti_id INTEGER NULL, + status INTEGER NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $warehouseTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id TEXT NULL, + name TEXT NULL, + description TEXT NULL, + address TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $typePetiTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type TEXT NULL, + size_peti TEXT NULL, + description TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $conditionPetiTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + nama_kondisi TEXT NULL, + deskripsi_kondisi TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $customerTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NULL, + code_customer TEXT NULL, + lot_no TEXT NULL, + no_tlp TEXT NULL, + address TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $petiTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tipe_peti_id INTEGER NULL, + warna TEXT NULL, + fix_lot TEXT NULL, + packing_no INTEGER NULL, + customer_id INTEGER NULL, + jumlah INTEGER NULL, + date_pembuatan DATETIME NULL, + warehouse_id INTEGER NULL, + kondisipeti_id INTEGER NULL, + status TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL, + FOREIGN KEY (tipe_peti_id) REFERENCES $typePetiTable(id), + FOREIGN KEY (customer_id) REFERENCES $customerTable(id), + FOREIGN KEY (warehouse_id) REFERENCES $warehouseTable(id) + ); + """); + + await db.execute(""" + CREATE TABLE $transferPetiTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id TEXT NULL, + peti_id INTEGER NULL, + name_customer INTEGER NULL, + source_warehouse INTEGER NULL, + destination_warehouse INTEGER NULL, + date DATETIME NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + await db.execute(""" + CREATE TABLE $disposalTable ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mobile_id TEXT NULL, + peti_id INTEGER NULL, + customer_id INTEGER NULL, + warehouse_id INTEGER NULL, + date_disposal DATETIME NULL, + description LONGTEXT NULL, + status_disposal TEXT NULL, + created_at TIMESTAMP NULL, + updated_at TIMESTAMP NULL, + deleted_at TIMESTAMP NULL, + created_by TEXT NULL, + updated_by TEXT NULL + ); + """); + + // Tambahkan CREATE TABLE untuk tabel-tabel lainnya di sini + }, onUpgrade: (Database db, int oldversion, int newversion) async { + if (oldversion < newversion) { + print("Version Upgrade"); + // Tambahkan pernyataan ALTER TABLE jika diperlukan + } + }); + print('db initialize'); + return openDb; + } +} diff --git a/lib/models/asset_status_model.dart b/lib/models/asset_status_model.dart index 893637d..bbc82a4 100644 --- a/lib/models/asset_status_model.dart +++ b/lib/models/asset_status_model.dart @@ -3,7 +3,10 @@ import 'warehouse_mode.dart'; class AssetStatusModel { int? id; + String? mobile_id; int? peti_id; + int? customer_id; + int? warehouse_id; DateTime? exit_at; String? exit_pic; int? exit_warehouse; @@ -11,16 +14,23 @@ class AssetStatusModel { String? enter_pic; int? enter_warehouse; DateTime? est_pengembalian; - String? kondisi_peti; + int? kondisi_peti_id; + // int? status; String? created_by; String? updated_by; - PetiAssetModel? peti; - WarehouseModel? warehouse; - WarehouseEnterModel? warehouse_enter; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; + // PetiAssetModel? peti; + // WarehouseModel? warehouse; + // WarehouseEnterModel? warehouse_enter; AssetStatusModel({ - this.id, + required this.id, + this.mobile_id, this.peti_id, + this.customer_id, + this.warehouse_id, this.exit_at, this.exit_pic, this.exit_warehouse, @@ -28,64 +38,85 @@ class AssetStatusModel { this.enter_pic, this.enter_warehouse, this.est_pengembalian, - this.kondisi_peti, + this.kondisi_peti_id, + // this.status, this.created_by, this.updated_by, - this.peti, - this.warehouse, - this.warehouse_enter, + this.created_at, + this.updated_at, + this.deleted_at, + // this.peti, + // this.warehouse, + // this.warehouse_enter, }); factory AssetStatusModel.fromJson(Map json) { return AssetStatusModel( - id: json['id'], - peti_id: json['peti_id'] != null - ? int.parse(json['peti_id'].toString()) - : null, - exit_at: json['exit_at'] != null ? DateTime.parse(json['exit_at']) : null, + id: json['id'] != null ? int.parse(json['id'].toString()) : 0, + mobile_id: json['mobile_id'].toString(), + peti_id: + json['peti_id'] != null ? int.parse(json['peti_id'].toString()) : 0, + customer_id: json['customer_id'] != null + ? int.parse(json['customer_id'].toString()) + : 0, + warehouse_id: json['warehouse_id'] != null + ? int.parse(json['warehouse_id'].toString()) + : 0, + exit_at: parseDateTime(json['exit_at']), exit_pic: json['exit_pic'], exit_warehouse: json['exit_warehouse'] != null ? int.parse(json['exit_warehouse'].toString()) - : null, - enter_at: - json['enter_at'] != null ? DateTime.parse(json['enter_at']) : null, - enter_pic: json['enter_pic'] != null ? json['enter_pic'] : null, + : 0, + enter_at: parseDateTime(json['enter_at']), + enter_pic: json['enter_pic'], enter_warehouse: json['enter_warehouse'] != null ? int.parse(json['enter_warehouse'].toString()) - : null, - est_pengembalian: json['est_pengembalian'] != null - ? DateTime.parse(json['est_pengembalian']) - : null, - kondisi_peti: - json['kondisi_peti'] != null ? json['kondisi_peti'] : 'null', - created_by: json['created_by'] != null ? json['created_by'] : 'null', - updated_by: json['updated_by'] != null ? json['updated_by'] : 'null', - peti: PetiAssetModel.fromJson(json['peti'] != null ? json['peti'] : null), - warehouse: WarehouseModel.fromJson(json['warehouse'] != null - ? json['warehouse'] - : {'id': 0, 'name': 'null'}), - warehouse_enter: WarehouseEnterModel.fromJson( - json['warehouse_enter'] != null - ? json['warehouse_enter'] - : {'id': 0, 'name': 'null'}), + : 0, + est_pengembalian: parseDateTime(json['est_pengembalian']), + kondisi_peti_id: json['kondisi_peti_id'] != null + ? int.parse(json['kondisi_peti_id'].toString()) + : 0, + created_by: json['created_by'] ?? 'null', + updated_by: json['updated_by'] ?? 'null', + created_at: parseDateTime(json['created_at']), + updated_at: parseDateTime(json['updated_at']), + deleted_at: parseDateTime(json['deleted_at']), ); } Map toJson() => { 'id': id, + 'mobile_id': mobile_id.toString(), 'peti_id': peti_id, - 'exit_at': exit_at, - 'exit_pic': exit_pic, + 'customer_id': customer_id, + 'warehouse_id': warehouse_id, + 'exit_at': exit_at?.toIso8601String(), + 'exit_pic': exit_pic.toString(), 'exit_warehouse': exit_warehouse, - 'enter_at': enter_at, + 'enter_at': enter_at?.toIso8601String(), 'enter_pic': enter_pic, - 'enter_warehouse': enter_warehouse, - 'est_pengembalian': est_pengembalian, - 'kondisi_peti': kondisi_peti, + 'enter_warehouse': enter_warehouse?.toString(), + 'est_pengembalian': est_pengembalian?.toIso8601String(), + 'kondisi_peti_id': kondisi_peti_id, + // 'status': status.toString(), 'created_by': created_by, 'updated_by': updated_by, - 'peti': peti!.toJson(), - 'warehouse': warehouse!.toJson(), - 'warehouse_enter': warehouse_enter!.toJson(), + 'created_at': created_at?.toIso8601String(), + 'updated_at': updated_at?.toIso8601String(), + 'deleted_at': deleted_at?.toIso8601String(), + // 'peti': peti!.toJson(), + // 'warehouse': warehouse!.toJson(), + // 'warehouse_enter': warehouse_enter!.toJson(), }; + + static DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString != null && dateTimeString.isNotEmpty) { + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + } + } + return null; + } } diff --git a/lib/models/condition_peti_model.dart b/lib/models/condition_peti_model.dart new file mode 100644 index 0000000..c262ad5 --- /dev/null +++ b/lib/models/condition_peti_model.dart @@ -0,0 +1,56 @@ +class ConditionPetiModel { + int? id; + String? nama_kondisi; + String? deskripsi_kondisi; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; + String? created_by; + String? updated_by; + + ConditionPetiModel({ + this.id, + this.nama_kondisi, + this.deskripsi_kondisi, + this.created_at, + this.updated_at, + this.deleted_at, + this.created_by, + this.updated_by, + }); + + factory ConditionPetiModel.fromJson(Map json) { + return ConditionPetiModel( + id: json['id'], + nama_kondisi: json['nama_kondisi'], + deskripsi_kondisi: json['deskripsi_kondisi'], + created_at: parseDateTime(json['created_at']), + updated_at: parseDateTime(json['updated_at']), + deleted_at: parseDateTime(json['deleted_at']), + created_by: json['created_by'].toString(), + updated_by: json['updated_by'].toString(), + ); + } + + Map toJson() => { + 'id': id, + 'nama_kondisi': nama_kondisi, + 'deskripsi_kondisi': deskripsi_kondisi, + 'created_by': created_by.toString(), + 'updated_by': updated_by.toString(), + 'created_at': created_at?.toIso8601String(), + 'updated_at': updated_at?.toIso8601String(), + 'deleted_at': deleted_at?.toIso8601String(), + }; + + static DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString != null && dateTimeString.isNotEmpty) { + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + } + } + return null; + } +} diff --git a/lib/models/customer_model.dart b/lib/models/customer_model.dart index 28a1b35..722fa73 100644 --- a/lib/models/customer_model.dart +++ b/lib/models/customer_model.dart @@ -3,26 +3,32 @@ class CustomerModel { String? name; String? code_customer; String? lot_no; - String? nip; - String? no_hp; - DateTime? tgl_lahir; - String? jenis_kelamin; - String? agama; + // String? nip; + // String? no_hp; + // DateTime? tgl_lahir; + // String? jenis_kelamin; + // String? agama; String? created_by; String? updated_by; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; CustomerModel({ this.id, this.name, this.code_customer, this.lot_no, - this.nip, - this.no_hp, - this.tgl_lahir, - this.jenis_kelamin, - this.agama, + // this.nip, + // this.no_hp, + // this.tgl_lahir, + // this.jenis_kelamin, + // this.agama, this.created_by, this.updated_by, + this.created_at, + this.updated_at, + this.deleted_at, }); factory CustomerModel.fromJson(Map json) { @@ -32,15 +38,24 @@ class CustomerModel { code_customer: json['code_customer'] != null ? json['code_customer'] : null, lot_no: json['lot_no'] != null ? json['lot_no'] : null, - nip: json['nip'] != null ? json['nip'] : null, - no_hp: json['no_hp'] != null ? json['no_hp'] : null, - tgl_lahir: - json['tgl_lahir'] != null ? DateTime.parse(json['tgl_lahir']) : null, - jenis_kelamin: - json['jenis_kelamin'] != null ? json['jenis_kelamin'] : null, - agama: json['agama'] != null ? json['agama'] : null, + // nip: json['nip'] != null ? json['nip'] : null, + // no_hp: json['no_hp'] != null ? json['no_hp'] : null, + // tgl_lahir: + // json['tgl_lahir'] != null ? DateTime.parse(json['tgl_lahir']) : null, + // jenis_kelamin: + // json['jenis_kelamin'] != null ? json['jenis_kelamin'] : null, + // agama: json['agama'] != null ? json['agama'] : null, created_by: json['created_by'] != null ? json['created_by'] : null, updated_by: json['updated_by'] != null ? json['updated_by'] : null, + created_at: json['created_at'] != null + ? DateTime.parse(json['created_at']) + : null, + updated_at: json['updated_at'] != null + ? DateTime.parse(json['updated_at']) + : null, + deleted_at: json['deleted_at'] != null + ? DateTime.parse(json['deleted_at']) + : null, ); } @@ -49,12 +64,15 @@ class CustomerModel { 'name': name, 'code_customer': code_customer, 'lot_no': lot_no, - 'nip': nip, - 'no_hp': no_hp, - 'tgl_lahir': tgl_lahir, - 'jenis_kelamin': jenis_kelamin, - 'agama': agama, + // 'nip': nip, + // 'no_hp': no_hp, + // 'tgl_lahir': tgl_lahir, + // 'jenis_kelamin': jenis_kelamin, + // 'agama': agama, 'created_by': created_by, 'updated_by': updated_by, + 'created_at': created_at, + 'updated_at': updated_at, + 'deleted_at': deleted_at, }; } diff --git a/lib/models/disposal_model.dart b/lib/models/disposal_model.dart new file mode 100644 index 0000000..1b3c6a3 --- /dev/null +++ b/lib/models/disposal_model.dart @@ -0,0 +1,84 @@ +class DisposalPetiModel { + int? id; + String? mobile_id; + int? peti_id; + int? customer_id; + int? warehouse_id; + DateTime? date_disposal; + String? description; + String? status_disposal; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; + String? created_by; + String? updated_by; + + DisposalPetiModel({ + this.id, + this.mobile_id, + this.peti_id, + this.customer_id, + this.warehouse_id, + this.date_disposal, + this.description, + this.status_disposal, + this.created_at, + this.updated_at, + this.deleted_at, + this.created_by, + this.updated_by, + }); + + factory DisposalPetiModel.fromJson(Map json) => + DisposalPetiModel( + id: json['id'], + mobile_id: + json['mobile_id'] != null ? json['mobile_id'].toString() : null, + peti_id: json['peti_id'] != null + ? int.parse(json['peti_id'].toString()) + : null, + customer_id: json['customer_id'] != null + ? int.parse(json['customer_id'].toString()) + : null, + warehouse_id: json['warehouse_id'] != null + ? int.parse(json['warehouse_id'].toString()) + : null, + date_disposal: json['date_disposal'] != null + ? DateTime.parse(json['date_disposal']) + : null, + description: + json['description'] != null ? json['description'].toString() : null, + status_disposal: json['status_disposal'] != null + ? json['status_disposal'].toString() + : null, + created_at: json['created_at'] != null + ? DateTime.parse(json['created_at']) + : null, + updated_at: json['updated_at'] != null + ? DateTime.parse(json['updated_at']) + : null, + deleted_at: json['deleted_at'] != null + ? DateTime.parse(json['deleted_at']) + : null, + created_by: + json['created_by'] != null ? json['created_by'].toString() : null, + updated_by: + json['updated_by'] != null ? json['updated_by'].toString() : null, + ); + + Map toJson() => { + "id": id, + "mobile_id": mobile_id, + "peti_id": peti_id, + "customer_id": customer_id, + "warehouse_id": warehouse_id, + "date_disposal": date_disposal, + "description": description, + "status_disposal": status_disposal, + "created_at": created_at, + "updated_at": updated_at, + "deleted_at": deleted_at, + "created_by": created_by, + "updated_by": updated_by, + }; +} diff --git a/lib/models/m_asset_status_model.dart b/lib/models/m_asset_status_model.dart index fc00f65..0d095b3 100644 --- a/lib/models/m_asset_status_model.dart +++ b/lib/models/m_asset_status_model.dart @@ -4,47 +4,56 @@ import 'package:siopas/models/warehouse_mode.dart'; class PetiAssetModel { int? id; - String? tipe_peti_id; + int? tipe_peti_id; String? warna; - String? fix_lot; + final String fix_lot; int? packing_no; int? customer_id; - int? warehouse_id; int? jumlah; DateTime? date_pembuatan; - WarehouseModel? warehouse; - TypePetiModel? tipe_peti; - CustomerModel? customer; + int? warehouse_id; + int? kondisipeti_id; + String? status; + // WarehouseModel? warehouse; + // TypePetiModel? tipe_peti; + // CustomerModel? customer; - String? status_disposal; String? created_by; String? updated_by; - // late WarehouseModel warehouse; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; PetiAssetModel({ this.id, this.tipe_peti_id, this.warna, - this.fix_lot, + required this.fix_lot, this.packing_no, this.customer_id, - this.warehouse_id, this.jumlah, this.date_pembuatan, - this.warehouse, - this.tipe_peti, - this.customer, - this.status_disposal, + // this.warehouse, + // this.tipe_peti, + // this.customer, + this.warehouse_id, + this.kondisipeti_id, + this.status, this.created_by, this.updated_by, + this.created_at, + this.updated_at, + this.deleted_at, // required this.warehouse, }); factory PetiAssetModel.fromJson(Map json) { return PetiAssetModel( id: json['id'], - tipe_peti_id: json['tipe_peti_id'], - warna: json['warna'], + tipe_peti_id: json['tipe_peti_id'] != null + ? int.parse(json['tipe_peti_id'].toString()) + : null, + warna: json['warna'] != null ? json['warna'].toString() : null, fix_lot: json['fix_lot'], packing_no: json['packing_no'] != null ? int.parse(json['packing_no'].toString()) @@ -55,25 +64,39 @@ class PetiAssetModel { warehouse_id: json['warehouse_id'] != null ? int.parse(json['warehouse_id'].toString()) : null, + kondisipeti_id: json['kondisipeti_id'] != null + ? int.parse(json['kondisipeti_id'].toString()) + : null, + status: json['status'] != null ? json['status'].toString() : null, jumlah: json['jumlah'] != null ? int.parse(json['jumlah'].toString()) : null, - date_pembuatan: DateTime.parse(json['date_pembuatan']), - warehouse: json['warehouse'] != null - ? WarehouseModel.fromJson(json['warehouse']) - : null, - tipe_peti: json['tipe_peti'] != null - ? TypePetiModel.fromJson(json['tipe_peti']) - : null, - customer: json['customer'] != null - ? CustomerModel.fromJson(json['customer']) + date_pembuatan: json['date_pembuatan'] != null + ? DateTime.parse(json['date_pembuatan'].toString()) : null, - status_disposal: json['status_disposal'], + // warehouse: json['warehouse'] != null + // ? WarehouseModel.fromJson(json['warehouse']) + // : null, + // tipe_peti: json['tipe_peti'] != null + // ? TypePetiModel.fromJson(json['tipe_peti']) + // : null, + // customer: json['customer'] != null + // ? CustomerModel.fromJson(json['customer']) + // : null, created_by: json['created_by'] != null ? json['created_by'].toString() : json['created_by'], updated_by: json['updated_by'] != null ? json['updated_by'].toString() : json['updated_by'], + created_at: json['created_at'] != null + ? DateTime.parse(json['created_at'].toString()) + : DateTime.now(), + updated_at: json['updated_at'] != null + ? DateTime.parse(json['updated_at'].toString()) + : DateTime.now(), + deleted_at: json['deleted_at'] != null + ? DateTime.parse(json['deleted_at'].toString()) + : DateTime.now(), ); } @@ -81,17 +104,21 @@ class PetiAssetModel { 'id': id, 'tipe_peti_id': tipe_peti_id, 'warna': warna, - 'fix_lot': fix_lot, + 'fix_lot': fix_lot.toString(), 'packing_no': packing_no, 'customer_id': customer_id, 'warehouse_id': warehouse_id, + 'kondisipeti_id': kondisipeti_id, + 'status': status, 'jumlah': jumlah, 'date_pembuatan': date_pembuatan!.toIso8601String(), - 'warehouse': warehouse!.toJson(), - 'tipe_peti': tipe_peti!.toJson(), - 'customer': customer!.toJson(), - 'status_disposal': status_disposal, + // 'warehouse': warehouse != null ? warehouse!.toJson() : null, + // 'customer': customer != null ? customer!.toJson() : null, + // 'tipe_peti': tipe_peti != null ? tipe_peti!.toJson() : null, 'created_by': created_by, 'updated_by': updated_by, + 'created_at': created_at!.toIso8601String(), + 'updated_at': updated_at!.toIso8601String(), + 'deleted_at': deleted_at!.toIso8601String(), }; } diff --git a/lib/models/transfer_peti_model.dart b/lib/models/transfer_peti_model.dart new file mode 100644 index 0000000..80de4ba --- /dev/null +++ b/lib/models/transfer_peti_model.dart @@ -0,0 +1,84 @@ +class TransferPetiModel { + int? id; + String? mobile_id; + int? peti_id; + int? name_customer; + int? source_warehouse; + int? destination_warehouse; + DateTime? date; + + String? created_by; + String? updated_by; + + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; + + TransferPetiModel({ + this.id, + this.mobile_id, + this.peti_id, + this.name_customer, + this.source_warehouse, + this.destination_warehouse, + this.date, + this.created_by, + this.updated_by, + this.created_at, + this.updated_at, + this.deleted_at, + }); + + factory TransferPetiModel.fromJson(Map json) { + return TransferPetiModel( + id: json['id'], + mobile_id: json['mobile_id'] != null ? json['mobile_id'] : null, + peti_id: json['peti_id'] != null + ? int.parse(json['peti_id'].toString()) + : null, + name_customer: json['name_customer'] != null + ? int.parse(json['name_customer'].toString()) + : null, + source_warehouse: json['source_warehouse'] != null + ? int.parse(json['source_warehouse'].toString()) + : null, + destination_warehouse: json['destination_warehouse'] != null + ? int.parse(json['destination_warehouse'].toString()) + : null, + date: parseDateTime(json['date']), + created_by: json['created_by'] != null ? json['created_by'] : null, + updated_by: json['updated_by'] != null ? json['updated_by'] : null, + created_at: parseDateTime(json['created_at']), + updated_at: parseDateTime(json['updated_at']), + deleted_at: parseDateTime(json['deleted_at']), + ); + } + + Map toJson() { + return { + 'id': id, + 'mobile_id': mobile_id, + 'peti_id': peti_id, + 'name_customer': name_customer, + 'source_warehouse': source_warehouse, + 'destination_warehouse': destination_warehouse, + 'date': date?.toIso8601String(), + 'created_by': created_by, + 'updated_by': updated_by, + 'created_at': created_at?.toIso8601String(), + 'updated_at': updated_at?.toIso8601String(), + 'deleted_at': deleted_at?.toIso8601String(), + }; + } + + static DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString != null && dateTimeString.isNotEmpty) { + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + } + } + return null; + } +} diff --git a/lib/models/type_peti_model.dart b/lib/models/type_peti_model.dart index a8d40e3..79c6295 100644 --- a/lib/models/type_peti_model.dart +++ b/lib/models/type_peti_model.dart @@ -29,7 +29,7 @@ class TypePetiModel { } Map toJson() => { - 'id': id, + 'id': id.toString(), 'type': type, 'size_peti': size_peti, 'description': description, diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index 3a8999b..8b04301 100644 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -1,12 +1,17 @@ import 'package:flutter/cupertino.dart'; class UserModel { - int? id; + String? id; String? username; String? fullname; String? email; + String? nip; + String? no_hp; + String? jenis_kelamin; + String? address; String? password; int? role_id; + int? warehouse_id; String? token; UserModel({ @@ -14,28 +19,47 @@ class UserModel { this.username, this.fullname, this.email, + this.nip, + this.no_hp, + this.jenis_kelamin, + this.address, this.password, this.role_id, + this.warehouse_id, this.token, }); UserModel.fromJson(Map json) { - id = json['id']; + id = json['id'].toString(); username = json['username']; fullname = json['fullname']; email = json['email']; + nip = json['nip']; + no_hp = json['no_hp']; + jenis_kelamin = json['jenis_kelamin']; + address = json['address']; password = json['password']; - role_id = int.parse(json['role_id'].toString()); + role_id = + json['role_id'] != null ? int.parse(json['role_id'].toString()) : null; + warehouse_id = json['warehouse_id'] != null + ? int.parse(json['warehouse_id'].toString()) + : null; token = json['token'].toString(); } Map toJson() { return { - 'id': id, + 'id': id.toString(), 'username': username, 'email': email, + 'fullname': fullname, + 'nip': nip, + 'no_hp': no_hp, + 'jenis_kelamin': jenis_kelamin, + 'address': address, 'password': password, - 'role_id': role_id, + 'role_id': role_id.toString(), + 'warehouse_id': warehouse_id.toString(), 'token': token.toString(), }; } diff --git a/lib/models/warehouse_mode.dart b/lib/models/warehouse_mode.dart index d3c6312..3b7fba1 100644 --- a/lib/models/warehouse_mode.dart +++ b/lib/models/warehouse_mode.dart @@ -8,6 +8,10 @@ class WarehouseModel { String? created_by; String? updated_by; + DateTime? created_at; + DateTime? updated_at; + DateTime? deleted_at; + WarehouseModel({ this.id, this.name, @@ -15,19 +19,31 @@ class WarehouseModel { this.address, this.created_by, this.updated_by, + this.created_at, + this.updated_at, + this.deleted_at, }); WarehouseModel.fromJson(Map json) { - id = json['id']; + id = json['id'] != null ? int.parse(json['id'].toString()) : 0; name = json['name']; description = json['description']; address = json['address']; created_by = json['created_by']; updated_by = json['updated_by']; + created_at = DateTime.parse(json['created_at'] != null + ? json['created_at'].toString() + : DateTime.now().toString()); + updated_at = DateTime.parse(json['updated_at'] != null + ? json['updated_at'].toString() + : DateTime.now().toString()); + deleted_at = DateTime.parse(json['deleted_at'] != null + ? json['deleted_at'].toString() + : DateTime.now().toString()); } Map toJson() => { - 'id': id, + 'id': id.toString(), 'name': name, 'description': description, 'address': address, @@ -37,7 +53,7 @@ class WarehouseModel { } class WarehouseEnterModel { - int? id; + String? id; String? name; String? description; String? address; @@ -51,7 +67,7 @@ class WarehouseEnterModel { factory WarehouseEnterModel.fromJson(Map json) { return WarehouseEnterModel( - id: json['id'], + id: json['id'].toString(), name: json['name'], description: json['description'], address: json['address'], @@ -59,7 +75,7 @@ class WarehouseEnterModel { } Map toJson() => { - 'id': id, + 'id': id.toString(), 'name': name, 'description': description, 'address': address, diff --git a/lib/pages/home/conn_home_page.dart/syncronize.dart b/lib/pages/home/conn_home_page.dart/syncronize.dart new file mode 100644 index 0000000..5d69e06 --- /dev/null +++ b/lib/pages/home/conn_home_page.dart/syncronize.dart @@ -0,0 +1,259 @@ +import 'dart:convert'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:intl/intl.dart'; +import '../../../connection/connection.dart'; +import '../../../migrations/databasehelper.dart'; +import '../../../models/asset_status_model.dart'; +import 'package:http/http.dart' as http; + +class SyncronizationGlobalData { + Future addData(AssetStatusModel assetStatusModel) async { + final dbClient = await conn.db; + late int result; + try { + result = await dbClient!.insert( + SqfliteDatabaseHelper.peminjamanTable, assetStatusModel.toJson()); + } catch (e) { + print('Error adding data to local SQLite: $e'); + result = 0; // Handle the error appropriately + } + return result; + } + + Future fetchData() async { + var dbclient = await conn.db; + List assetStatusList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.peminjamanTable, orderBy: 'id DESC'); + for (var item in maps) { + assetStatusList.add(item); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllPeminjamanInfo() async { + final dbClient = await conn.db; + List peminjamanList = []; + try { + final maps = await dbClient!.query(SqfliteDatabaseHelper.peminjamanTable); + for (var item in maps) { + peminjamanList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return peminjamanList; + } + + Future> fetchAllPengembalianInfo() async { + final dbClient = await conn.db; + List pengembalianList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.pengembalianTable); + for (var item in maps) { + pengembalianList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return pengembalianList; + } + + Future> fetchAllTransferInfo() async { + final dbClient = await conn.db; + List transferList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.transferPetiTable); + for (var item in maps) { + transferList.add(TransferPetiModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return transferList; + } + + Future deleteAllPeminjamanData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); + } + + Future deleteAllPengembalianData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.pengembalianTable); + } + + Future deleteAllTransferData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); + } + + Future saveToMysqlWith(List assetStatusesLocalList) async { + for (var i = 0; i < assetStatusesLocalList.length; i++) { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + // Format tanggal sesuai kebutuhan + String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i].created_at!) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": assetStatusesLocalList[i].mobile_id.toString(), + "peti_id": assetStatusesLocalList[i].peti_id.toString(), + "exit_at": assetStatusesLocalList[i].exit_at.toString(), + "est_pengembalian": + assetStatusesLocalList[i].est_pengembalian.toString(), + "exit_pic": assetStatusesLocalList[i].exit_pic.toString(), + "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), + // "status": assetStatusesLocalList[i].status.toString(), + "created_by": assetStatusesLocalList[i].created_by.toString(), + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/store'), + body: data, + ); + + if (response.statusCode == 200) { + // print("Data uploaded successfully for index $i:"); + // print("Response body: ${response.body}"); + print("Saving Data saveToMysqlWith"); + } else { + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Response body: ${response.body}"); + } + } + + return true; // Pengunggahan berhasil + } + + Future fetchAllCustomerInfo() async { + final dbClient = await conn.db; + List contactList = []; + try { + final maps = await dbClient!.query(SqfliteDatabaseHelper.peminjamanTable); + for (var item in maps) { + contactList.add(item); + } + } catch (e) { + print(e.toString()); + } + return contactList; + } + + Future saveToMysql(List assetStatusesLocalList) async { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + for (var i = 0; i < assetStatusesLocalList.length; i++) { +// Format tanggal sesuai kebutuhan + String formattedCreatedAt = + assetStatusesLocalList[i]['created_at'] != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i]['created_at']) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": assetStatusesLocalList[i]['mobile_id'].toString(), + "peti_id": assetStatusesLocalList[i]['peti_id'].toString(), + "exit_at": assetStatusesLocalList[i]['exit_at'].toString(), + "est_pengembalian": + assetStatusesLocalList[i]['est_pengembalian'].toString(), + "exit_pic": assetStatusesLocalList[i]['exit_pic'].toString(), + "exit_warehouse": + assetStatusesLocalList[i]['exit_warehouse'].toString(), + "status": assetStatusesLocalList[i]['status'].toString(), + "created_by": assetStatusesLocalList[i]['created_by'].toString(), + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/store'), + body: data); + if (response.statusCode == 200) { + print(response.body); + print("Saving Data saveToMysql"); + } else { + print(response.statusCode); + } + } + } + + Future> fetchFromApi() async { + final response = await http.get( + Uri.parse(await getBaseUrl() + '/asset-status'), + ); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['asset_status']; + List contactDBList = data + .map( + (item) => AssetStatusModel.fromJson(item as Map)) + .toList(); + + return contactDBList; + } else { + throw Exception('Failed to fetch data from API Asset Status'); + } + } +} diff --git a/lib/pages/home/controller/home_controller.dart b/lib/pages/home/controller/home_controller.dart new file mode 100644 index 0000000..50d7de2 --- /dev/null +++ b/lib/pages/home/controller/home_controller.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:http/http.dart' as http; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:sqflite/sqflite.dart'; + +import '../../../migrations/databasehelper.dart'; + +class ControllerHome { + final conn = SqfliteDatabaseHelper.instance; + Future getPeminjamanCount() async { + final dbClient = await conn.db; + final count = Sqflite.firstIntValue(await dbClient! + .query(SqfliteDatabaseHelper.peminjamanTable, columns: ['COUNT(*)'])); + return count ?? 0; + } + + Future getPengembalianCount() async { + final dbClient = await conn.db; + final count = Sqflite.firstIntValue( + await dbClient!.query(SqfliteDatabaseHelper.pengembalianTable, + columns: ['COUNT(*)']), + ); + return count ?? 0; + } + + Future getTransferCount() async { + final dbClient = await conn.db; + final count = Sqflite.firstIntValue( + await dbClient!.query(SqfliteDatabaseHelper.transferPetiTable, + columns: ['COUNT(*)']), + ); + return count ?? 0; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data nor WIFI detected, no internet connection found."); + return false; + } + } +} diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index b4216bd..47ddefd 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -1,14 +1,31 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/migrations/databasehelper.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../../models/asset_status_model.dart'; +import '../../models/condition_peti_model.dart'; +import '../../models/customer_model.dart'; +import '../../models/m_asset_status_model.dart'; +import '../../models/type_peti_model.dart'; import '../../models/user_model.dart'; +import '../../models/warehouse_mode.dart'; import '../../providers/auth_provider.dart'; import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; +import '../../services/controllerApi.dart'; +import '../../services/syncronizeAPI.dart'; import '../../theme.dart'; +import '../peminjaman_barang/conn/syncronize.dart'; +import '../peminjaman_barang/controller/peminjaman_controller.dart'; +import '../pengembalian_barang/conn/syncronize.dart'; +import '../transfer_peti/conn/syncronize.dart'; +import 'conn_home_page.dart/syncronize.dart'; +import 'controller/home_controller.dart'; class HomePage extends StatefulWidget { @override @@ -17,20 +34,45 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { String? token; - // final items = ["Android", "iOS", "Desktop", "Web"]; - // final items = ['assets/gps_samara.jpeg']; - final items = [ - 'https://mypertamina.id/uploads/posts/Survey-Bright-Cafe-2021-1024x576.jpg', - 'https://grhaproperti.com/wp-content/uploads/2022/05/banner-survey-on-520.jpg', - 'https://grhaproperti.com/wp-content/uploads/2022/05/banner-properti-agent-1-1.jpg' - ]; - - // bool isLoading = true; + bool loading = true; + + // Reinit atau Upload Only + WarehouseModel? warehouseSqfliteApi; + List? typePetiSqfliteApi; + List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + + // Datatable + int _currentPage = 1; + int _pageSize = 10; + List? _data; + List? _petiData; + List? _tipePetiData; + List? _customerData; + List? _warehouseData; + bool _isLoading = false; + Timer? _timer; + @override void initState() { super.initState(); - initializeDateFormatting("id_ID", null); // Inisialisasi pustaka intl _getUserToken(); + + warehouseListAPI(); + typePetiListAPI(); + customerListAPI(); + petiListAPI(); + + // Tampil data Datatables + datatablesAssetStatusList(); + datatablesPetiList(); + datatablesTipePetiList(); + datatablesCustomerList(); + datatablesWarehouseList(); + _data = []; } void _getUserToken() async { @@ -38,11 +80,251 @@ class _HomePageState extends State { if (mounted) { setState(() { token = prefs.getString('token'); - // getInit(); // Panggil getInit jika token sudah didapatkan }); } } + // Reinit atau Upload Only ------------------------------------------------------------------------ + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future typePetiListAPI() async { + if (mounted) { + await ControllerApi().fetchTipePetiDataAPI().then((value) { + setState(() { + typePetiSqfliteApi = (value as List) + .map((item) => TypePetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerSqfliteApi = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future reinitWarehouseApi() async { + EasyLoading.show(status: 'Mengambil data Warehouse...'); + List warehouseApiData = + await SyncronizationDataAPI().fetchWarehouseFromApi(); + await ControllerApi() + .deleteAllWarehouseDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllWarehouseDataAPI(warehouseApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitPetiApi() async { + EasyLoading.show(status: 'Mengambil data Peti...'); + List petiApiData = + await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() + .deleteAllPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitCustomerApi() async { + EasyLoading.show(status: 'Mengambil data Customer...'); + List customerApiData = + await SyncronizationDataAPI().fetchCustomerFromApi(); + await ControllerApi() + .deleteAllCustomerDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllCustomerDataAPI(customerApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitConditionPetiApi() async { + EasyLoading.show(status: 'Mengambil data Condition Peti...'); + List conditionPetiApiData = + await SyncronizationDataAPI().fetchKondisiPetiFromApi(); + await ControllerApi() + .deleteAllKondisiPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi().addAllKondisiPetiDataAPI( + conditionPetiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future fetchDataFromApiAndSync() async { + EasyLoading.show(status: 'Mengambil data dari Server...'); + try { + // await syncToGlobal(); + await syncToGlobal('Peminjaman'); + await syncToGlobal('Pengembalian'); + await syncToGlobal('Transfer'); + + // await reinitAssetStatusApi(); + await reinitWarehouseApi(); + await reinitPetiApi(); + await reinitCustomerApi(); + // await reinitTypePetiApi(); + await reinitConditionPetiApi(); + + await datatablesAssetStatusList(); + EasyLoading.showSuccess('Data berhasil diperbarui'); + } catch (e) { + EasyLoading.showError('Gagal memperbarui data: $e'); + } finally { + EasyLoading.dismiss(); + } + } + + Future syncToGlobal(String type) async { + try { + EasyLoading.show( + status: 'Jangan tutup aplikasi. Kami sedang menyinkronkan...'); + await Future.delayed(Duration(seconds: 3)); + + // Tambahkan penanganan pengunggahan + bool uploadSuccess = false; // Berikan nilai awal false + + if (type == 'Peminjaman') { + List peminjamanList = + await SyncronizationGlobalData().fetchAllPeminjamanInfo(); + uploadSuccess = await SyncronizationPeminjamanData() + .saveToPeminjamanWith(peminjamanList); + + // Jika pengunggahan berhasil, hapus data lokal Peminjaman + if (uploadSuccess) { + await SyncronizationGlobalData().deleteAllPeminjamanData(); + } + } else if (type == 'Pengembalian') { + List pengembalianList = + await SyncronizationGlobalData().fetchAllPengembalianInfo(); + uploadSuccess = await SyncronizationPengembalianData() + .savePengembalianToServerWith(pengembalianList); + + // Jika pengunggahan berhasil, hapus data lokal Pengembalian + if (uploadSuccess) { + await SyncronizationGlobalData().deleteAllPengembalianData(); + } + } else if (type == 'Transfer') { + List transferPetiList = + await SyncronizationGlobalData().fetchAllTransferInfo(); + uploadSuccess = await SyncronizationTransferPetiData() + .saveTransferPetiServerWith(transferPetiList); + + // Jika pengunggahan berhasil, hapus data lokal Pengembalian + if (uploadSuccess) { + await SyncronizationGlobalData().deleteAllTransferData(); + } + } + + // Setelah selesai, tampilkan pesan sukses atau gagal + if (uploadSuccess) { + EasyLoading.showSuccess('Berhasil disinkronkan dengan Server'); + } else { + EasyLoading.showError('Gagal disinkronkan dengan Server'); + } + } catch (error) { + // Handle error jika terjadi + EasyLoading.showError('Terjadi kesalahan: $error'); + } + } + + Future isInteret() async { + await SyncronizationGlobalData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); + } else { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); + } + }); + } + + // Datatables ------------------------------------------------------------------------ + Future datatablesAssetStatusList() async { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesPetiList() async { + await Controller().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesTipePetiList() async { + await Controller().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesCustomerList() async { + await Controller().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesWarehouseList() async { + await Controller().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + @override void dispose() { // Memastikan untuk membatalkan timer saat widget di-dispose @@ -55,156 +337,6 @@ class _HomePageState extends State { UserModel user = authProvider.user; // String? token = authProvider.token; - Widget header() { - return Container( - margin: EdgeInsets.only( - top: defaultMargin, - left: 10, - right: 10, - bottom: 15.5, - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Hallo, ${user.email}', - style: primaryTextStyle.copyWith( - fontSize: 16, - fontWeight: semiBold, - ), - ), - Text( - '${user.email}', - style: subtitleTextStyle.copyWith( - fontSize: 14, - ), - ), - ], - ), - ), - Stack( - children: [ - GestureDetector( - onTap: () { - // Tambahkan aksi yang ingin Anda lakukan ketika ikon notifikasi diklik di sini - }, - child: Icon( - Icons - .notifications, // Ubah ikon notifikasi sesuai kebutuhan - size: 30, - color: Colors.blue[700], // Ubah warna sesuai kebutuhan - ), - ), - Positioned( - right: 0, - top: 0, - child: Container( - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.red, // Warna latar belakang notifikasi - ), - child: Text( - '1', // Jumlah notifikasi (Anda dapat mengubahnya sesuai kebutuhan) - style: TextStyle( - color: Colors.white, // Warna teks notifikasi - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget subHeader() { - return Card( - margin: EdgeInsets.only( - top: 10, - left: 10, - right: 10, - ), - child: Container( - padding: EdgeInsets.all(15), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Pengumuman', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - Text( - DateFormat('dd MMMM yyyy', 'id_ID').format(DateTime.now()), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - SizedBox(height: 10), - Text( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisl eget aliquet ultricies, nunc nisl aliquam nisl, vitae aliquam nisl nisl eget nisl. Donec euismod, nisl eget aliquet ultricies, nunc nisl aliquam nisl, vitae aliquam nisl nisl eget nisl.', - style: TextStyle( - fontSize: 11.5, - ), - ), - ], - ), - ), - ); - } - - Widget titleMenu() { - return Container( - margin: EdgeInsets.only( - top: 5, - left: 10, - right: 10, - bottom: 5, - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Menu Apps', - style: primaryTextStyle.copyWith( - fontSize: 16, - fontWeight: semiBold, - ), - ), - Text( - 'See All', - style: TextStyle(fontSize: 12, color: Colors.blue[700]), - ), - ], - ), - ], - ), - ), - ], - ), - ); - } - Widget cardMenuPeminjaman() { return Container( margin: EdgeInsets.all(10), @@ -352,82 +484,161 @@ class _HomePageState extends State { ); } - Widget cardRow() { + Widget _buildCountTile(IconData icon, int count, Color color, String text) { return Column( children: [ - Row( - children: [ - cardTotal('PENGADAAN', 0, Icons.shopping_cart), - cardTotal('PEMINJAMAN', 0, Icons.shopping_basket), - ], + CircleAvatar( + backgroundColor: color, + radius: 12, + child: Icon(icon, size: 12, color: Colors.white), ), - SizedBox(height: 5), - Row( - children: [ - cardTotal('PENGEMBALIAN', 0, Icons.reply), - cardTotal('REMINDER PENGEMBALIAN', 0, Icons.access_alarm), - ], + SizedBox(height: 4), + Text( + text, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Text( + '$count', + style: TextStyle(fontSize: 12), ), ], ); } - Widget _buildDrawer() { - return SizedBox( - //membuat menu drawer - child: Drawer( - //membuat list, - //list digunakan untuk melakukan scrolling jika datanya terlalu panjang - child: ListView( - padding: EdgeInsets.zero, - //di dalam listview ini terdapat beberapa widget drawable - children: [ - UserAccountsDrawerHeader( - //membuat gambar profil - currentAccountPicture: Image( - image: NetworkImage( - "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png")), - //membuat nama akun - accountName: Text("Sahretech"), - //membuat nama email - accountEmail: Text("ig: @sahretech"), - //memberikan background - decoration: BoxDecoration( - image: DecorationImage( - image: NetworkImage( - "https://cdn.pixabay.com/photo/2016/04/24/20/52/laundry-1350593_960_720.jpg"), - fit: BoxFit.cover)), - ), - //membuat list menu - ListTile( - leading: Icon(Icons.home), - title: Text("Beranda"), - onTap: () {}, - ), - ListTile( - leading: Icon(Icons.people), - title: Text("Pegawai"), - onTap: () {}, - ), - ListTile( - leading: Icon(Icons.money), - title: Text("Transaksi"), - onTap: () {}, - ), - Divider(), - ListTile( - leading: Icon(Icons.emoji_emotions), - title: Text("Profil"), - onTap: () {}, - ), - ListTile( - leading: Icon(Icons.info), - title: Text("Tentang"), - onTap: () {}, - ), - ], - ), - ), + Future showSyncDialog(BuildContext context) async { + // Create an instance of ControllerHome + ControllerHome controllerHome = ControllerHome(); + + // Fetch counts from the ControllerHome + int peminjamanCount = await controllerHome.getPeminjamanCount(); + int pengembalianCount = await controllerHome.getPengembalianCount(); + int transferCount = await controllerHome.getTransferCount(); + + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + // Dialog shape and style + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: Colors.grey[100], + elevation: 0, + + // Dialog content + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Dialog title with close button + Container( + width: double.infinity, + color: Colors.indigo[700], // Indigo background + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Sync Server Global", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); // Close dialog + }, + ), + ], + ), + ), + + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + // Display counts for each table + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildCountTile(Icons.vertical_align_top, peminjamanCount, + Colors.green[700]!, 'Peminjaman'), + _buildCountTile(Icons.vertical_align_bottom, + pengembalianCount, Colors.blue[700]!, 'Pengembalian'), + _buildCountTile(Icons.input_outlined, transferCount, + Colors.yellow[700]!, 'Transfer'), + ], + ), + SizedBox(height: 10), + // Divider + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + + // Re-init Button + Container( + width: double.infinity, + child: TextButton( + onPressed: () { + Navigator.pop(context); // Close dialog + fetchDataFromApiAndSync(); + }, + child: Text( + "Upload + Download", + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), + ), + ), + + // Divider + // Divider( + // height: 1, + // thickness: 1, + // color: Colors.black, // Black divider + // ), + + // Upload Only Button + // Container( + // width: double.infinity, + // child: TextButton( + // onPressed: () { + // Navigator.pop(context); // Close dialog + // syncToGlobal('Peminjaman'); + // syncToGlobal('Pengembalian'); + // syncToGlobal('Transfer'); + // }, + // child: Text( + // "Upload Only", + // style: TextStyle( + // color: Colors.black, + // fontSize: 16.0, + // fontFamily: 'Poppins', + // ), + // ), + // ), + // ), + ], + ), + ); + }, ); } @@ -437,6 +648,24 @@ class _HomePageState extends State { elevation: 0, automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], + actions: [ + IconButton( + icon: Icon( + Icons.cloud_sync, + size: 30, + ), + onPressed: () async { + if (await SyncronizationGlobalData.isInternet()) { + // Display custom dialog when the IconButton is pressed + showSyncDialog(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("No internet connection")), + ); + } + }, + ), + ], title: Row( children: [ SizedBox(width: 10), @@ -445,7 +674,7 @@ class _HomePageState extends State { child: Column( children: [ Text( - 'Beranda', + 'SIOPAS-ISTW', textAlign: TextAlign.center, ), Text( @@ -460,54 +689,9 @@ class _HomePageState extends State { ), ], ), - // actions: [ - // Align( - // alignment: Alignment.center, - // child: Stack( - // children: [ - // GestureDetector( - // onTap: () { - // // Tambahkan aksi yang diinginkan saat ikon ditekan - // }, - // child: Icon( - // Icons.notifications, - // color: Colors.white, - // size: 30, - // ), - // ), - // Positioned( - // right: 0, - // top: 0, - // child: Container( - // padding: EdgeInsets.all(4), - // decoration: BoxDecoration( - // shape: BoxShape.circle, - // color: Colors.red, // Warna latar belakang notifikasi - // ), - // child: Text( - // '5', - // style: TextStyle( - // color: Colors.white, // Warna teks notifikasi - // fontSize: 12, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // SizedBox(width: 10), - // ], ), - // drawer: _buildDrawer(), body: ListView( children: [ - // header(), - // subHeader(), - // SizedBox(height: 10), - // cardRow(), - // titleMenu(), GridView.count( crossAxisCount: 2, shrinkWrap: true, diff --git a/lib/pages/home/main_page.dart b/lib/pages/home/main_page.dart index fb43b97..9386ac7 100644 --- a/lib/pages/home/main_page.dart +++ b/lib/pages/home/main_page.dart @@ -67,7 +67,7 @@ class _MainPageState extends State { // label: 'Receive', // ), BottomNavigationBarItem( - icon: Icon(Icons.person), + icon: Icon(Icons.settings), label: 'Pengaturan', ), ], diff --git a/lib/pages/home/setting_page.dart b/lib/pages/home/setting_page.dart index 6d03038..760aa87 100644 --- a/lib/pages/home/setting_page.dart +++ b/lib/pages/home/setting_page.dart @@ -163,7 +163,7 @@ class SettingPageState extends State { appBar: AppBar( elevation: 0, backgroundColor: Colors.indigo[700], - title: const Text("Settings"), + title: const Text("Pengaturan"), automaticallyImplyLeading: false, ), body: Center( @@ -182,7 +182,7 @@ class SettingPageState extends State { _SingleSection( children: [ _Logout( - title: "Sign out", + title: "Keluar", icon: Icons.exit_to_app_rounded, handleLogout: handleGetLogout, ), diff --git a/lib/pages/peminjaman_barang/conn/syncronize.dart b/lib/pages/peminjaman_barang/conn/syncronize.dart new file mode 100644 index 0000000..1fd92a9 --- /dev/null +++ b/lib/pages/peminjaman_barang/conn/syncronize.dart @@ -0,0 +1,222 @@ +import 'dart:convert'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:intl/intl.dart'; +import '../../../connection/connection.dart'; +import '../../../migrations/databasehelper.dart'; +import '../../../models/asset_status_model.dart'; +import 'package:http/http.dart' as http; + +class SyncronizationPeminjamanData { + Future addData(AssetStatusModel assetStatusModel) async { + final dbClient = await conn.db; + late int result; + try { + result = await dbClient!.insert( + SqfliteDatabaseHelper.peminjamanTable, assetStatusModel.toJson()); + } catch (e) { + print('Error adding data to local SQLite: $e'); + result = 0; // Handle the error appropriately + } + return result; + } + + Future fetchData() async { + var dbclient = await conn.db; + List assetStatusList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.peminjamanTable, orderBy: 'id DESC'); + for (var item in maps) { + assetStatusList.add(item); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllInfo() async { + final dbClient = await conn.db; + List assetStatusList = []; + try { + final maps = await dbClient!.query(SqfliteDatabaseHelper.peminjamanTable); + for (var item in maps) { + assetStatusList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + Future deleteAllAssetStatusData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); + } + + Future saveToPeminjamanWith( + List assetStatusesLocalList) async { + for (var i = 0; i < assetStatusesLocalList.length; i++) { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + // Format tanggal sesuai kebutuhan + String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i].created_at!) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": assetStatusesLocalList[i].mobile_id.toString(), + "peti_id": assetStatusesLocalList[i].peti_id.toString(), + "customer_id": assetStatusesLocalList[i].customer_id.toString(), + "warehouse_id": assetStatusesLocalList[i].warehouse_id.toString(), + "exit_at": assetStatusesLocalList[i].exit_at.toString(), + "est_pengembalian": + assetStatusesLocalList[i].est_pengembalian.toString(), + "exit_pic": assetStatusesLocalList[i].exit_pic.toString(), + "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), + "created_by": assetStatusesLocalList[i].created_by.toString(), + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/store'), + body: data, + ); + + if (response.statusCode == 200) { + // print("Data uploaded successfully for index $i:"); + // print("Response body: ${response.body}"); + print("Saving Data saveToMysqlWith"); + } else { + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Response body: ${response.body}"); + } + } + + return true; // Pengunggahan berhasil + } + + Future fetchAllCustomerInfo() async { + final dbClient = await conn.db; + List contactList = []; + try { + final maps = await dbClient!.query(SqfliteDatabaseHelper.peminjamanTable); + for (var item in maps) { + contactList.add(item); + } + } catch (e) { + print(e.toString()); + } + return contactList; + } + + Future saveToMysql(List assetStatusesLocalList) async { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + for (var i = 0; i < assetStatusesLocalList.length; i++) { +// Format tanggal sesuai kebutuhan + String formattedCreatedAt = + assetStatusesLocalList[i]['created_at'] != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i]['created_at']) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": assetStatusesLocalList[i]['mobile_id'].toString(), + "peti_id": assetStatusesLocalList[i]['peti_id'].toString(), + "customer_id": assetStatusesLocalList[i]['customer_id'].toString(), + "warehouse_id": assetStatusesLocalList[i]['warehouse_id'].toString(), + "exit_at": assetStatusesLocalList[i]['exit_at'].toString(), + "est_pengembalian": + assetStatusesLocalList[i]['est_pengembalian'].toString(), + "exit_pic": assetStatusesLocalList[i]['exit_pic'].toString(), + "exit_warehouse": + assetStatusesLocalList[i]['exit_warehouse'].toString(), + "status": assetStatusesLocalList[i]['status'].toString(), + "created_by": assetStatusesLocalList[i]['created_by'].toString(), + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/store'), + body: data); + if (response.statusCode == 200) { + print(response.body); + print("Saving Data saveToMysql"); + } else { + print(response.statusCode); + } + } + } + + Future> fetchFromApi() async { + final response = await http.get( + Uri.parse(await getBaseUrl() + '/asset-status'), + ); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['asset_status']; + List contactDBList = data + .map( + (item) => AssetStatusModel.fromJson(item as Map)) + .toList(); + + return contactDBList; + } else { + throw Exception('Failed to fetch data from API Asset Status'); + } + } +} diff --git a/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart new file mode 100644 index 0000000..6605b56 --- /dev/null +++ b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart @@ -0,0 +1,204 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:http/http.dart' as http; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:sqflite/sqflite.dart'; + +import '../../../migrations/databasehelper.dart'; + +class Controller { + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllPeminjamanInfo() async { + final dbClient = await conn.db; + List assetStatusList = []; + try { + final maps = await dbClient!.query(SqfliteDatabaseHelper.peminjamanTable); + for (var item in maps) { + assetStatusList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + Future addPeminjamanData(AssetStatusModel peminjamanAddModel) async { + var dbclient = await conn.db; + int result = 0; // Provide an initial value + try { + result = await dbclient!.insert( + SqfliteDatabaseHelper.peminjamanTable, peminjamanAddModel.toJson()); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future updatePeminjamanData(AssetStatusModel peminjamanAddModel) async { + var dbclient = await conn.db; + late int result; + try { + result = await dbclient!.update( + SqfliteDatabaseHelper.peminjamanTable, + peminjamanAddModel.toJson(), + where: 'id=?', + whereArgs: [peminjamanAddModel.id], + ); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future fetchAssetStatusLocalController() async { + var dbclient = await conn.db; + List peminjamanStatusList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.peminjamanTable, orderBy: 'id DESC'); + for (var item in maps) { + peminjamanStatusList.add(item); + } + } catch (e) { + print(e.toString()); + } + return peminjamanStatusList; + } + + Future> fetchPeminjamanDataId() async { + var dbclient = await conn.db; + List peminjamanList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.peminjamanTable, orderBy: 'id DESC'); + for (var item in maps) { + peminjamanList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return peminjamanList; + } + + Future deleteAllData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); + } + + Future addAllData(List contactList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var contact in contactList) { + batch.insert( + SqfliteDatabaseHelper.peminjamanTable, + contact.toJson(), + ); + } + + await batch.commit(); + } + + Future fetchPetiData() async { + var dbclient = await conn.db; + List petiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.petiTable, orderBy: 'id DESC'); + for (var item in maps) { + petiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return petiList; + } + + Future fetchTipePetiData() async { + var dbclient = await conn.db; + List tipePetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.typePetiTable, orderBy: 'id DESC'); + for (var item in maps) { + tipePetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return tipePetiList; + } + + Future fetchCustomerData() async { + var dbclient = await conn.db; + List customerList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.customerTable, orderBy: 'id DESC'); + for (var item in maps) { + customerList.add(item); + } + } catch (e) { + print(e.toString()); + } + return customerList; + } + + Future fetchWarehouseData() async { + var dbclient = await conn.db; + List warehouseList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.warehouseTable, orderBy: 'id DESC'); + for (var item in maps) { + warehouseList.add(item); + } + } catch (e) { + print(e.toString()); + } + return warehouseList; + } + + Future fetchDisposalData() async { + var dbclient = await conn.db; + List disposalList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.disposalTable, orderBy: 'id DESC'); + for (var item in maps) { + disposalList.add(item); + } + } catch (e) { + print(e.toString()); + } + return disposalList; + } +} diff --git a/lib/pages/peminjaman_barang/create.dart b/lib/pages/peminjaman_barang/create.dart index 0aa0fad..15c5bc7 100644 --- a/lib/pages/peminjaman_barang/create.dart +++ b/lib/pages/peminjaman_barang/create.dart @@ -1,7 +1,15 @@ import 'dart:convert'; import 'dart:core'; +import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/disposal_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/pages/peminjaman_barang/conn/syncronize.dart'; +import 'package:siopas/services/controllerApi.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; @@ -10,12 +18,16 @@ import 'package:siopas/models/m_asset_status_model.dart'; import 'package:siopas/models/warehouse_mode.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl +import 'package:uuid/uuid.dart'; import '../../connection/connection.dart'; import 'package:http/http.dart' as http; import '../../models/user_model.dart'; import '../../providers/auth_provider.dart'; +import '../../services/syncronizeAPI.dart'; +import 'controller/peminjaman_controller.dart'; +import 'package:collection/collection.dart'; class CreatePeminjamanBarang extends StatefulWidget { const CreatePeminjamanBarang({Key? key}) : super(key: key); @@ -25,12 +37,28 @@ class CreatePeminjamanBarang extends StatefulWidget { } class _CreatePeminjamanBarangState extends State { - List _dataAsset = []; - List _dataWarehouse = []; - bool _isLoading = false; String? token; - PetiAssetModel? _valAsset; - WarehouseModel? _valWarehouse; + List? typePetiSqfliteApi; + // List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + WarehouseModel? warehouseSqfliteApi; + WarehouseModel? warehouseTujuanSqfliteApi; + DisposalPetiModel? disposalSqfliteApi; + CustomerModel? customerSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valwarehouseTujuan; + List? _valcustomer; + List? _valdisposal; + + List _allPetiList = []; + + List _unrestrictedPetiList = []; + List _filteredPetiList = []; + bool isQRCodeScanned = false; + + bool loading = true; TextEditingController _exit_atController = TextEditingController(); TextEditingController _est_pengembalianController = TextEditingController(); TextEditingController _penanggungJawabController = TextEditingController(); @@ -44,9 +72,12 @@ class _CreatePeminjamanBarangState extends State { void initState() { super.initState(); _getUserToken(); - fetchDataWarehouse(); - fetchDataAsset(); - initializeDateFormatting('id_ID'); + warehouseListAPI(); + petiListAPI(); + disposalListAPI(); + customerListAPI(); + + initializeDateFormatting('id_ID', null); } void _getUserToken() async { @@ -54,76 +85,226 @@ class _CreatePeminjamanBarangState extends State { if (mounted) { setState(() { token = prefs.getString('token'); + loading = false; }); } } - Future fetchDataAsset() async { - setState(() { - _isLoading = true; - }); - - final response = await http.get(Uri.parse('$baseUrl/peti-asset')); - + Future disposalListAPI() async { if (mounted) { - // Periksa apakah widget masih "mounted" - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['petis']; - - final List newDataAsset = (jsonData as List) - .map((item) => PetiAssetModel.fromJson(item)) - .toList(); - - if (mounted) { - // Periksa lagi sebelum memanggil setState - setState(() { - _dataAsset.addAll(newDataAsset); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Asset Status'); - } + await ControllerApi().fetchDisposalDataAPI().then((value) { + setState(() { + _valdisposal = (value as List) + .map((item) => DisposalPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); } } - Future fetchDataWarehouse() async { - setState(() { - _isLoading = true; - }); + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + _valcustomer = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - final response = await http.get(Uri.parse('$baseUrl/m-warehouse')); + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + Future petiListAPI() async { if (mounted) { - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['warehouse']; - - final List newDataWarehouse = (jsonData as List) - .map((item) => WarehouseModel.fromJson(item)) - .toList(); - - if (mounted) { - setState(() { - _dataWarehouse.addAll(newDataWarehouse); - _isLoading = false; - }); - } + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future isInteret() async { + await SyncronizationPeminjamanData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Warehouse'); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); } - } + }); } + // Future _onQRViewCreated(QRViewController controller) async { + // this.controller = controller; + // bool scanned = false; + + // // code to auto focus kamera belakang + // controller.flipCamera(); + // await Future.delayed(const Duration(milliseconds: 400)); + // controller.flipCamera(); + + // controller.scannedDataStream.listen( + // (scanData) { + // if (!scanned) { + // try { + // setState(() { + // result = scanData; + // List lines = result!.code!.split('\n'); + // String idPeti = ''; + // String idWarehouse = ''; + + // for (String line in lines) { + // if (line.contains(';')) { + // List values = line.split(';'); + // if (values.length >= 3) { + // idPeti = values[1]; + // idWarehouse = values[2]; + // break; + // } + // } + // } + + // int? petiId = int.tryParse(idPeti); + // int? warehouseId = int.tryParse(idWarehouse); + // // AuthProvider authProvider = + // // Provider.of(context, listen: false); + // // UserModel user = authProvider.user; + + // if (petiId != null && warehouseId != null) { + // // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan + // PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + // (peti) => + // peti.id == petiId && + // peti.deleted_at != true && + // // peti.warehouse_id == user.warehouse_id && + // peti.status == 'AKTIF', + // ); + + // if (allowedPeti != null) { + // petiSqfliteApi = allowedPeti; + + // warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( + // // warehouseSqfliteApi = _valwarehouse?.firstWhere( + // (warehouse) => warehouse.id == allowedPeti.warehouse_id, + // ); + // } else { + // // Tampilkan pesan error jika data tidak sesuai dengan hak akses + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // content: Text( + // 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', + // style: TextStyle( + // color: Colors.white, + // fontSize: 12, + // ), + // ), + // backgroundColor: Colors.red[700], + // action: SnackBarAction( + // label: 'Tutup', + // onPressed: () { + // ScaffoldMessenger.of(context).hideCurrentSnackBar(); + // }, + // ), + // ), + // ); + // petiSqfliteApi = null; + // warehouseSqfliteApi = null; + // } + // } else { + // // Tampilkan pesan error jika nilai yang dipindai tidak sesuai + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // content: Row( + // children: [ + // Icon( + // Icons.warning, + // color: Colors.black, + // ), + // SizedBox(width: 8), + // Text( + // 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + // style: TextStyle( + // color: Colors.black, + // fontSize: 12, + // ), + // ), + // ], + // ), + // backgroundColor: Colors.yellow[700], + // ), + // ); + // petiSqfliteApi = null; + // warehouseSqfliteApi = null; + // } + + // scanned = true; + // }); + + // controller.stopCamera(); + + // Future.delayed(Duration(milliseconds: 500), () { + // if (mounted) { + // Navigator.of(context).pop(); + // } + // }); + // } catch (e) { + // controller.stopCamera(); + + // // Reset nilai dropdown Peti dan Warehouse + // setState(() { + // petiSqfliteApi = null; + // warehouseSqfliteApi = null; + // }); + // print('Error scanning QR Code: $e'); + + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // content: Row( + // children: [ + // Icon( + // Icons.error, + // color: Colors.red[400], + // ), + // SizedBox(width: 8), + // Flexible( + // child: Text( + // e.toString(), + // style: TextStyle( + // color: Colors.white, + // fontSize: 12, + // ), + // ), + // ), + // ], + // ), + // backgroundColor: Colors.red[700], + // ), + // ); + // } + // } + // }, + // ); + // } + Future _onQRViewCreated(QRViewController controller) async { this.controller = controller; bool scanned = false; @@ -133,151 +314,164 @@ class _CreatePeminjamanBarangState extends State { await Future.delayed(const Duration(milliseconds: 400)); controller.flipCamera(); - controller.scannedDataStream.listen((scanData) { - if (!scanned) { - try { - setState(() { - result = scanData; - - List lines = result!.code!.split('\n'); - - String idPeti = ''; - String idWarehouse = ''; - - for (String line in lines) { - if (line.contains(';')) { - List values = line.split(';'); - if (values.length >= 3) { - idPeti = values[1]; - idWarehouse = values[2]; - break; + controller.scannedDataStream.listen( + (scanData) { + if (!scanned) { + try { + setState(() { + result = scanData; + List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + + for (String line in lines) { + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; + } } } - } - - int? petiId = int.tryParse(idPeti); - int? warehouseId = int.tryParse(idWarehouse); - - if (petiId != null && warehouseId != null) { - _valAsset = _dataAsset.firstWhere( - (peti) => peti.id == petiId, - orElse: () => _valAsset!, - ); - - _valWarehouse = _dataWarehouse.firstWhere( - (warehouse) => warehouse.id == warehouseId, - orElse: () => _valWarehouse!, - ); - } else { - // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.warning, - color: Colors.black, // Warna ikon - ), - SizedBox(width: 8), // Jarak antara ikon dan teks - Text( - 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + + int? petiId = int.tryParse(idPeti); + int? warehouseId = int.tryParse(idWarehouse); + // AuthProvider authProvider = Provider.of(context, listen: false); + // UserModel user = authProvider.user; + + // Dalam fungsi yang menangani pemindaian QR code + // Dalam fungsi yang menangani pemindaian QR code + if (petiId != null && warehouseId != null) { + // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan + PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + (peti) => + peti.id == petiId && + peti.deleted_at != true && + peti.status == 'AKTIF', + ); + + if (allowedPeti != null) { + setState(() { + isQRCodeScanned = true; + // Mengisi _filteredPetiList untuk dropdown hasil QR Code + _filteredPetiList = [ + _valpeti!.firstWhere((peti) => peti.id == allowedPeti.id) + ]; + + petiSqfliteApi = allowedPeti; + + warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( + (warehouse) => warehouse.id == allowedPeti.warehouse_id, + ); + + customerSqfliteApi = _valcustomer?.firstWhereOrNull( + (customer) => customer.id == allowedPeti.customer_id, + ); + }); + } else { + // Tampilkan pesan error jika data tidak sesuai dengan hak akses + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', style: TextStyle( - color: Colors.black, + color: Colors.white, fontSize: 12, - ), // Warna teks + ), ), - ], + backgroundColor: Colors.red[700], + action: SnackBarAction( + label: 'Tutup', + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } + } else { + // Tampilkan pesan error jika nilai yang dipindai tidak sesuai + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, + ), + SizedBox(width: 8), + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), + ), + ], + ), + backgroundColor: Colors.yellow[700], ), - backgroundColor: - Colors.yellow[700], // Warna latar belakang SnackBar - ), - ); - } - - scanned = true; - }); - - controller.stopCamera(); - - Future.delayed(Duration(milliseconds: 500), () { - if (mounted) { - Navigator.of(context).pop(); - } - }); - } catch (e) { - print('Error scanning QR Code: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Error scanning QR Code: $e'), - ), - ); - } - } - }); - } + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } - // void _onQRViewCreated(QRViewController controller) { - // this.controller = controller; - // bool scanned = false; + scanned = true; + }); - // controller.scannedDataStream.listen((scanData) { - // if (!scanned) { - // try { - // setState(() { - // result = scanData; - - // List lines = result!.code!.split('\n'); - - // for (String line in lines) { - // if (line.startsWith('ID Peti')) { - // String idPeti = line.split(': ')[1]; - // // Isi formulir dropdown asset - // _valAsset = _dataAsset - // .firstWhere((peti) => peti.id == int.parse(idPeti)); - // } else if (line.startsWith('Date:')) { - // String datePeminjaman = line.split(': ')[1]; - // try { - // DateTime parsedDate = - // DateFormat('dd-MM-yyyy').parse(datePeminjaman); - // String formattedDate = - // DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(parsedDate); - // _exit_atController.text = formattedDate; - // } catch (e) { - // print('Error parsing date: $e'); - // // Lakukan penanganan jika format tanggal tidak sesuai - // } - // } else if (line.startsWith('ID Warehouse')) { - // String idWarehouse = line.split(': ')[1]; - // // Isi formulir dropdown gudang - // _valWarehouse = _dataWarehouse.firstWhere( - // (warehouse) => warehouse.id == int.parse(idWarehouse)); - // } - // } - - // scanned = true; - // }); - - // controller.stopCamera(); - - // Future.delayed(Duration(milliseconds: 500), () { - // if (mounted) { - // Navigator.of(context).pop(); - // } - // }); - // } catch (e) { - // print('Error scanning QR Code: $e'); - // ScaffoldMessenger.of(context).showSnackBar(SnackBar( - // content: Text('Error scanning QR Code: $e'), - // )); - // } - // } - // }); - // } + controller.stopCamera(); - @override - void dispose() { - super.dispose(); - controller?.dispose(); + Future.delayed(Duration(milliseconds: 500), () { + if (mounted) { + Navigator.of(context).pop(); + } + }); + } catch (e) { + controller.stopCamera(); + + // Reset nilai dropdown Peti dan Warehouse + setState(() { + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + print('Error scanning QR Code: $e'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.error, + color: Colors.red[400], + ), + SizedBox(width: 8), + Flexible( + child: Text( + e.toString(), + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + ], + ), + backgroundColor: Colors.red[700], + ), + ); + } + } + }, + ); } @override @@ -285,104 +479,59 @@ class _CreatePeminjamanBarangState extends State { AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 150.0 - : 300.0; - - // var now = DateTime.now(); - // var dt = DateTime(DateTime.now().year, DateTime.now().month, - // DateTime.now().day, DateTime.now().hour, DateTime.now().minute); - // // _exit_atController.text = DateFormat('yyyy-MM-dd HH:mm:ss').format(dt); - // _exit_atController.text = DateFormat('dd-MM-yyyy').format(dt); + var uuid = Uuid(); - Future _storePeminjaman() async { - setState(() { - _isLoading = true; - }); + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } try { - final response = await http.post( - Uri.parse('$baseUrl/asset-status/store'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': token!, - }, - body: jsonEncode({ - 'peti_id': _valAsset!.id, - 'exit_at': _exit_atController.text, - 'exit_pic': _penanggungJawabController.text, - 'exit_warehouse': _valWarehouse!.id, - 'est_pengembalian': _est_pengembalianController.text, - 'created_by': user.fullname, - // 'updated_by': user.fullname, - }), - ); - - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['peminjam']; - - print('Berhasil menyimpan data: $jsonData'); + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } - // Tampilkan snackbar - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.greenAccent[700], - content: Row( - children: [ - Icon( - Icons.check_circle_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Data berhasil disimpan'), - ], - ), - duration: Duration(seconds: 3), // Durasi tampilan snackbar - ), - ); + Future saveAssetData() async { + DateTime now = DateTime.now().toLocal(); + String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); + + if (_exit_atController.text.isNotEmpty) { + AssetStatusModel assetAddModel = AssetStatusModel( + id: null, + peti_id: petiSqfliteApi!.id, + customer_id: customerSqfliteApi!.id, + warehouse_id: warehouseSqfliteApi!.id, + exit_at: parseDateTime(_exit_atController.text), + exit_pic: _penanggungJawabController.text, + exit_warehouse: warehouseTujuanSqfliteApi!.id, + est_pengembalian: parseDateTime(_est_pengembalianController.text), + created_by: user.fullname, + created_at: parseDateTime(formattedDate), + mobile_id: uuid.v4(), + ); - // Reset form input - _exit_atController.text = ''; - _valAsset = null; - _valWarehouse = null; - result = null; + // Call addData function + int result = await Controller().addPeminjamanData(assetAddModel); + if (result > 0) { + print("Success Tambah data"); + // print(result); + Navigator.pushNamed(context, '/peminjaman-barang'); + EasyLoading.showSuccess("Data Berhasil Disimpan"); } else { - // Reset form input - _exit_atController.text = ''; - _valAsset = null; - _valWarehouse = null; - result = null; - throw Exception('Gagal menyimpan data Asset Status'); - } - } catch (e) { - print('Error storing data: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Gagal menyimpan data'), - ], - ), - duration: Duration(seconds: 2), // Durasi tampilan snackbar - ), - ); - } finally { - if (mounted) { - setState(() { - _isLoading = false; - }); + print("Failed"); } } } + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 250.0 + : 300.0; + return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, @@ -392,18 +541,12 @@ class _CreatePeminjamanBarangState extends State { style: TextStyle( fontSize: 16, )), - leading: IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - Navigator.pushNamed(context, '/peminjaman-barang'); - }, - ), ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) + body: loading + ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Padding( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(8.0), child: Form( key: _formKey, child: Column( @@ -415,7 +558,61 @@ class _CreatePeminjamanBarangState extends State { elevation: 2, child: Container( margin: EdgeInsets.all(8), - child: DropdownButtonFormField( + child: + // DropdownButtonFormField( + // validator: (value) { + // if (value == null) { + // return 'Harus diisi'; + // } + // return null; + // }, + // decoration: InputDecoration( + // labelText: 'Peti', + // border: OutlineInputBorder(), + // ), + // hint: Text("Pilih Peti"), + // value: petiSqfliteApi, + // items: (_valpeti ?? []) + // .where((peti) => + // peti.deleted_at != true && + // (peti.warehouse_id == + // user.warehouse_id) && + // (peti.status == 'AKTIF')) + // .map((PetiAssetModel peti) { + // return DropdownMenuItem( + // child: Text( + // '${peti.fix_lot}', // Menampilkan warehouse_id + // style: TextStyle( + // fontSize: 12, + // ), + // ), + // value: peti, + // ); + // }).toList(), + // onChanged: (PetiAssetModel? value) { + // setState( + // () { + // petiSqfliteApi = value; + // if (value != null) { + // warehouseSqfliteApi = + // _valwarehouse?.firstWhere( + // (warehouse) => + // warehouse.id == + // value.warehouse_id, + // ); + // customerSqfliteApi = + // _valcustomer?.firstWhereOrNull( + // (customer) => + // customer.id == + // value.customer_id, + // ); + // } + // }, + // ); + // }, + // ), + + DropdownButtonFormField( validator: (value) { if (value == null) { return 'Harus diisi'; @@ -427,25 +624,46 @@ class _CreatePeminjamanBarangState extends State { border: OutlineInputBorder(), ), hint: Text("Pilih Peti"), - value: _valAsset, - items: _dataAsset.map((PetiAssetModel item) { + value: petiSqfliteApi, + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .map((PetiAssetModel peti) { return DropdownMenuItem( - child: Text('${item.fix_lot}'), - value: item, + child: Text( + '${peti.fix_lot}', + style: TextStyle( + fontSize: 12, + ), + ), + value: peti, ); }).toList(), onChanged: (PetiAssetModel? value) { setState(() { - _valAsset = value; + petiSqfliteApi = value; if (value != null) { - // Set _valWarehouse berdasarkan warehouse_id dari PetiAssetModel - _valWarehouse = - _dataWarehouse.firstWhere( + warehouseSqfliteApi = + _valwarehouse?.firstWhere( (warehouse) => warehouse.id == - int.parse(value.warehouse_id - .toString()), + value.warehouse_id, ); + customerSqfliteApi = + _valcustomer?.firstWhereOrNull( + (customer) => + customer.id == value.customer_id, + ); + + // Perbarui _unrestrictedPetiList sesuai pemilihan manual + _unrestrictedPetiList = [ + _valpeti!.firstWhere( + (peti) => peti.id == value.id) + ]; } }); }, @@ -533,39 +751,40 @@ class _CreatePeminjamanBarangState extends State { elevation: 2, child: Padding( padding: const EdgeInsets.all(8), - child: FormBuilderDateTimePicker( + child: DropdownButtonFormField( validator: (value) { - if (_exit_atController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Tanggal Peminjaman harus diisi'), - ], - ), - duration: Duration(seconds: 2), - ), - ); - return null; // Return null jika ada kesalahan + if (value == null) { + return 'Harus diisi'; } - return null; // Return null jika tidak ada kesalahan + return null; }, - controller: _exit_atController, - name: 'tanggal', - inputType: InputType.date, - // format: DateFormat('yyyy-MM-dd HH:mm:ss.SSS'), - format: DateFormat('yyyy-MM-dd', 'id_ID'), decoration: InputDecoration( - labelText: 'Tanggal Peminjaman', + labelText: 'Customer', border: OutlineInputBorder(), - suffixIcon: Icon(Icons.calendar_today), ), + hint: Text("Pilih Customer"), + value: customerSqfliteApi, + items: (_valcustomer ?? []) + .where( + (customer) => customer.deleted_at != true) + .map((CustomerModel customer) { + return DropdownMenuItem( + child: Text( + '${customer.name}', // Menampilkan warehouse_id + style: TextStyle( + fontSize: 12, + ), + ), + value: customer, + ); + }).toList(), + onChanged: (CustomerModel? value) { + setState( + () { + customerSqfliteApi = value; + }, + ); + }, ), ), ), @@ -575,43 +794,67 @@ class _CreatePeminjamanBarangState extends State { child: Padding( padding: const EdgeInsets.all(8), child: FormBuilderDateTimePicker( - validator: (value) { - if (_est_pengembalianController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text( - 'Estimasi Tanggal Pengembalian harus diisi'), - ], - ), - duration: Duration(seconds: 2), - ), - ); - return null; // Return null jika ada kesalahan - } - return null; // Return null jika tidak ada kesalahan - }, - controller: _est_pengembalianController, - name: 'tanggal', + controller: _exit_atController, + name: 'tanggal_peminjaman', inputType: InputType.date, - // format: DateFormat('yyyy-MM-dd HH:mm:ss.SSS'), format: DateFormat('yyyy-MM-dd', 'id_ID'), decoration: InputDecoration( - labelText: 'Estimasi Tanggal Pengembalian', + labelText: 'Tanggal Peminjaman', border: OutlineInputBorder(), suffixIcon: Icon(Icons.calendar_today), ), + onChanged: (DateTime? selectedDate) { + if (selectedDate != null) { + // Mengisi tanggal estimasi 7 hari ke depan + DateTime estimasiPengembalian = + selectedDate.add(Duration(days: 7)); + _est_pengembalianController.text = + DateFormat('yyyy-MM-dd') + .format(estimasiPengembalian); + } + }, ), ), ), SizedBox(height: 16), + Card( + elevation: 2, + child: Column( + children: [ + SizedBox(height: 8), + Container( + margin: EdgeInsets.only( + left: 8), // Atur nilai left sesuai kebutuhan + child: Align( + alignment: Alignment.centerLeft, + child: Text( + '* Terisi otomatis 7 hari setelah tanggal peminjaman', + style: TextStyle( + fontSize: 12, + color: Colors.red, + fontStyle: FontStyle.italic), + ), + ), + ), + SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8), + child: FormBuilderDateTimePicker( + controller: _est_pengembalianController, + name: 'estimasi_pengembalian', + inputType: InputType.date, + format: DateFormat('yyyy-MM-dd', 'id_ID'), + decoration: InputDecoration( + labelText: 'Estimasi Tanggal Pengembalian', + border: OutlineInputBorder(), + suffixIcon: Icon(Icons.calendar_today), + ), + ), + ), + ], + ), + ), + SizedBox(height: 16), Card( elevation: 2, child: Padding( @@ -632,11 +875,10 @@ class _CreatePeminjamanBarangState extends State { ), ), ), - SizedBox(height: 16), + SizedBox(height: 13), Card( - elevation: 2, child: Padding( - padding: const EdgeInsets.all(8), + padding: const EdgeInsets.all(8.0), child: DropdownButtonFormField( validator: (value) { if (value == null) { @@ -645,82 +887,65 @@ class _CreatePeminjamanBarangState extends State { return null; }, decoration: InputDecoration( - labelText: 'Pilih Gudang', + labelText: 'Asal Gudang', border: OutlineInputBorder(), ), - hint: Text("Pilih Gudang"), - value: _valWarehouse, - items: - _dataWarehouse.map((WarehouseModel warehouse) { - return DropdownMenuItem( - child: Text('${warehouse.name}'), - value: warehouse, - ); - }).toList(), + hint: Text("Asal Gudang"), + value: warehouseSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouse) => + warehouse.deleted_at != true) + .map((WarehouseModel warehouse) + // _valwarehouse?.map((WarehouseModel warehouse) + { + return DropdownMenuItem( + child: Text('${warehouse.name}'), + value: warehouse, + ); + }).toList() ?? + [], onChanged: (WarehouseModel? value) { setState(() { - _valWarehouse = value; + warehouseSqfliteApi = value; }); }, ), ), ), - SizedBox(height: 16), - // FractionallySizedBox( - // widthFactor: 1.0, // Lebar penuh - // child: Card( - // elevation: 1, - // child: Padding( - // padding: const EdgeInsets.all(8), - // child: Column( - // children: [ - // Text( - // 'Data dari QR Code:', - // style: TextStyle( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 8), - // Text( - // result != null - // ? result!.code ?? - // 'Belum ada data QR Code terpindai' - // : 'Belum ada data QR Code terpindai', - // style: TextStyle(fontSize: 14), - // ), - // ], - // ), - // ), - // ), - // ), - Visibility( - visible: false, - child: FractionallySizedBox( - widthFactor: 1.0, - child: Card( - elevation: 1, - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: [ - Text( - 'Data dari QR Code:', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 8), - Text( - result != null && result!.code != null - ? result!.code! - : 'Belum ada data QR Code terpindai', - style: TextStyle(fontSize: 14), - ), - ], - ), + SizedBox(height: 13), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + labelText: 'Tujuan Gudang', + border: OutlineInputBorder(), ), + hint: Text("Tujuan Gudang"), + value: warehouseTujuanSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouseTujuan) => + warehouseTujuan.deleted_at != true) + .map((WarehouseModel warehouseTujuan) + // _valwarehouse?.map((WarehouseModel warehouse) + { + return DropdownMenuItem( + child: Text('${warehouseTujuan.name}'), + value: warehouseTujuan, + ); + }).toList() ?? + [], + onChanged: (WarehouseModel? value) { + setState(() { + warehouseTujuanSqfliteApi = value; + }); + }, ), ), ), @@ -758,58 +983,6 @@ class _CreatePeminjamanBarangState extends State { ], ), ), - // Container( - // // width: 50, // Lebar sesuai kebutuhan - // width: 65.0, - // height: 50, // Tinggi sesuai kebutuhan - // decoration: BoxDecoration( - // color: Colors.indigoAccent, // Warna latar belakang - // shape: BoxShape.circle, // Membuat lingkaran - // ), - // child: IconButton( - // onPressed: () { - // showModalBottomSheet( - // context: context, - // builder: (BuildContext context) { - // return Stack( - // alignment: Alignment.center, - // children: [ - // Container( - // height: double.infinity, - // width: double.infinity, - // child: QRView( - // key: qrKey, - // onQRViewCreated: _onQRViewCreated, - // overlay: QrScannerOverlayShape( - // borderColor: Colors.red, - // borderRadius: 10, - // borderLength: 30, - // borderWidth: 10, - // cutOutSize: 300, - // ), - // ), - // ), - // Positioned( - // bottom: 16, - // child: ElevatedButton( - // onPressed: () { - // Navigator.of(context).pop(); - // }, - // child: Text('Tutup'), - // ), - // ), - // ], - // ); - // }, - // ); - // }, - // icon: Icon( - // Icons.qr_code, - // size: 30, - // ), - // color: Colors.white, // Warna ikon - // ), - // ), Container( width: MediaQuery.of(context).size.width / 3, child: Column( @@ -823,11 +996,13 @@ class _CreatePeminjamanBarangState extends State { color: Colors.green, // Warna hijau untuk save ), child: IconButton( - onPressed: () { + onPressed: () async { if (_formKey.currentState!.validate()) { try { - if (_exit_atController.text.isNotEmpty) { - _storePeminjaman(); + if (_exit_atController.text.isNotEmpty && + petiSqfliteApi != null && + warehouseSqfliteApi != null) { + await saveAssetData(); } } catch (e) { print('Error storing data: $e'); diff --git a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart index b991e11..3fe62fd 100644 --- a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart +++ b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart @@ -1,16 +1,26 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/disposal_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:siopas/pages/peminjaman_barang/conn/syncronize.dart'; +import 'package:siopas/services/syncronizeAPI.dart'; +import 'package:siopas/services/controllerApi.dart'; +import 'package:siopas/pages/peminjaman_barang/controller/peminjaman_controller.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/providers/asset_status_provider.dart'; -import 'package:http/http.dart' as http; +import 'package:collection/collection.dart'; -import '../../connection/connection.dart'; +import '../../models/condition_peti_model.dart'; import 'show.dart'; class AssetStatusPage extends StatefulWidget { @@ -22,16 +32,49 @@ class AssetStatusPage extends StatefulWidget { class AssetStatusPageState extends State { String? token; + bool loading = true; + + // Reinit atau Upload Only + WarehouseModel? warehouseSqfliteApi; + List? typePetiSqfliteApi; + List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + DisposalPetiModel? disposalSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valdisposal; + + // Datatable int _currentPage = 1; int _pageSize = 10; - List _data = []; + List? _data; + List? _petiData; + List? _tipePetiData; + List? _customerData; + List? _warehouseData; + bool _isLoading = false; + Timer? _timer; @override void initState() { super.initState(); _getUserToken(); - fetchData(); + + warehouseListAPI(); + typePetiListAPI(); + customerListAPI(); + petiListAPI(); + // disposalListAPI(); + + // Tampil data Datatables + datatablesAssetStatusList(); + datatablesPetiList(); + datatablesTipePetiList(); + datatablesCustomerList(); + datatablesWarehouseList(); + _data = []; } void _getUserToken() async { @@ -43,149 +86,617 @@ class AssetStatusPageState extends State { } } - Future fetchData() async { + // Reinit atau Upload Only ------------------------------------------------------------------------ + Future warehouseListAPI() async { if (mounted) { - setState(() { - _isLoading = true; + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); }); + } + } - try { - final response = await http.get(Uri.parse('$baseUrl/asset-status')); + // Future disposalListAPI() async { + // if (mounted) { + // await ControllerApi().fetchDisposalDataAPI().then((value) { + // setState(() { + // _valdisposal = (value as List) + // .map((item) => DisposalPetiModel.fromJson(item)) + // .toList(); + // loading = false; + // }); + // }); + // } + // } - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['asset_status']; + Future typePetiListAPI() async { + if (mounted) { + await ControllerApi().fetchTipePetiDataAPI().then((value) { + setState(() { + typePetiSqfliteApi = (value as List) + .map((item) => TypePetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - final List newData = (jsonData as List) - .map((item) => AssetStatusModel.fromJson(item)) + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerSqfliteApi = (value as List) + .map((item) => CustomerModel.fromJson(item)) .toList(); + loading = false; + }); + }); + } + } - if (mounted) { - setState(() { - _data.addAll(newData); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data'); - } - } catch (e) { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - print('Error fetching data: $e'); - } + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); } } + Future reinitAssetStatusApi() async { + EasyLoading.show(status: 'Mengambil data Asset Status...'); + List assetStatusApiData = + await SyncronizationDataAPI().fetchAssetStatusFromApi(); + await ControllerApi() + .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitWarehouseApi() async { + EasyLoading.show(status: 'Mengambil data Warehouse...'); + List warehouseApiData = + await SyncronizationDataAPI().fetchWarehouseFromApi(); + await ControllerApi() + .deleteAllWarehouseDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllWarehouseDataAPI(warehouseApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitPetiApi() async { + EasyLoading.show(status: 'Mengambil data Peti...'); + List petiApiData = + await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() + .deleteAllPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitCustomerApi() async { + EasyLoading.show(status: 'Mengambil data Customer...'); + List customerApiData = + await SyncronizationDataAPI().fetchCustomerFromApi(); + await ControllerApi() + .deleteAllCustomerDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllCustomerDataAPI(customerApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitTypePetiApi() async { + EasyLoading.show(status: 'Mengambil data Type Peti...'); + List typePetiApiData = + await SyncronizationDataAPI().fetchTipePetiFromApi(); + await ControllerApi() + .deleteAllTipePetiDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllTipePetiDataAPI(typePetiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitConditionPetiApi() async { + EasyLoading.show(status: 'Mengambil data Condition Peti...'); + List conditionPetiApiData = + await SyncronizationDataAPI().fetchKondisiPetiFromApi(); + await ControllerApi() + .deleteAllKondisiPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi().addAllKondisiPetiDataAPI( + conditionPetiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + // Future reinitDisposalApi() async { + // List disposalApiData = + // await SyncronizationDataAPI().fetchDisposalFromApi(); + // await ControllerApi() + // .deleteAllDisposalDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllDisposalDataAPI(disposalApiData); // Add new data to SQLite + // } + + Future fetchDataFromApiAndSync() async { + EasyLoading.show(status: 'Mengambil data dari Server...'); + await Future.delayed(Duration(seconds: 3)); + + try { + await syncToMysql(); + + // await reinitAssetStatusApi(); + await reinitWarehouseApi(); + await reinitPetiApi(); + await reinitCustomerApi(); + // await reinitTypePetiApi(); + await reinitConditionPetiApi(); + // await reinitDisposalApi(); + + await datatablesAssetStatusList(); + EasyLoading.showSuccess('Data berhasil diperbarui'); + } catch (e) { + EasyLoading.showError('Gagal memperbarui data: $e'); + } finally { + EasyLoading.dismiss(); + } + } + + Future syncToMysql() async { + await SyncronizationPeminjamanData() + .fetchAllInfo() + .then((peminjamanList) async { + EasyLoading.show( + status: 'Jangan tutup aplikasi. Kami sedang menyinkronkan...'); + await Future.delayed(Duration(seconds: 3)); + + // Tambahkan penanganan pengunggahan + bool uploadSuccess = await SyncronizationPeminjamanData() + .saveToPeminjamanWith(peminjamanList); + + // Jika pengunggahan berhasil, hapus data lokal + if (uploadSuccess) { + await SyncronizationPeminjamanData().deleteAllAssetStatusData(); + // Setelah selesai, tampilkan pesan sukses + EasyLoading.showSuccess('Berhasil disinkronkan dengan Server'); + await datatablesAssetStatusList(); + } else { + // Tampilkan pesan gagal jika pengunggahan tidak berhasil + EasyLoading.showError('Gagal disinkronkan dengan Server'); + } + }); + } + + // Future syncToMysql() async { + // await SyncronizationData().fetchAllInfo().then((assetList) async { + // EasyLoading.show(status: 'Don\'t close app. We are syncing...'); + // await SyncronizationData().saveToMysqlWith(assetList); + // await SyncronizationData().deleteAllAssetStatusData(); + // // EasyLoading.showSuccess('Successfully saved to MySQL'); + // }); + // } + + Future isInteret() async { + await SyncronizationPeminjamanData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); + } else { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); + } + }); + } + + // Datatables ------------------------------------------------------------------------ + Future datatablesAssetStatusList() async { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesPetiList() async { + await Controller().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesTipePetiList() async { + await Controller().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesCustomerList() async { + await Controller().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesWarehouseList() async { + await Controller().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + void _loadMoreData() { if (mounted && !_isLoading) { setState(() { _currentPage++; }); - fetchData(); + datatablesAssetStatusList(); } } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.indigo[700], - elevation: 0, - title: Text('Data Peminjaman Barang', - style: TextStyle( - fontSize: 16, - )), - leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushNamed(context, '/home'); - }, - ), - ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - child: SizedBox( - width: double.infinity, - child: PaginatedDataTable( - header: const Text('Peminjaman Barang'), - rowsPerPage: _pageSize, - availableRowsPerPage: const [10, 25, 50], - onRowsPerPageChanged: (value) { - setState(() { - _pageSize = value!; - }); - }, - columns: const [ - DataColumn(label: Text('No')), - DataColumn(label: Text('')), - DataColumn(label: Text('Kode Peti')), - DataColumn(label: Text('Nama Customer')), - DataColumn(label: Text('Tgl Peminjaman')), - DataColumn(label: Text('PJ Peminjaman')), - DataColumn(label: Text('Asal Gudang')), - ], - source: _DataSource(data: _data, context: context), - ), - ), + // Add this function outside the build method + void showSyncDialog(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + // Dialog shape and style + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), ), - bottomNavigationBar: BottomAppBar( - color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang - child: Container( - height: 65.0, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - customBorder: CircleBorder(), - onTap: () { - // Aksi ketika ikon diklik - Navigator.pushNamed(context, '/peminjaman-barang/create'); - }, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.greenAccent[700], + backgroundColor: Colors.grey[100], + elevation: 0, + + // Dialog content + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Dialog title with close button + Container( + width: double.infinity, + color: Colors.indigo[700], // Indigo background + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Sync Server Peminjaman", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); // Close dialog + }, + ), + ], ), - child: Icon( - Icons.add, - size: 30, - color: Colors.white, + ), + + // Divider + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + + // Re-init Button + Container( + width: double.infinity, + child: TextButton( + onPressed: () { + Navigator.pop(context); // Close dialog + fetchDataFromApiAndSync(); + }, + child: Text( + "Upload + Download", + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), ), ), - ), + + // Divider + // Divider( + // height: 1, + // thickness: 1, + // color: Colors.black, // Black divider + // ), + + // Upload Only Button + // Container( + // width: double.infinity, + // child: TextButton( + // onPressed: () { + // Navigator.pop(context); // Close dialog + // syncToMysql(); + // }, + // child: Text( + // "Upload Only", + // style: TextStyle( + // color: Colors.black, + // fontSize: 16.0, + // fontFamily: 'Poppins', + // ), + // ), + // ), + // ), + ], + ), + ); + }, + ); + } + + return DefaultTabController( + length: 1, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Data Peminjaman Barang', + style: TextStyle( + fontSize: 16, + )), + actions: [ + IconButton( + icon: Icon(Icons.backup), + onPressed: () async { + if (await SyncronizationPeminjamanData.isInternet()) { + // Display custom dialog when the IconButton is pressed + showSyncDialog(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("No internet connection")), + ); + } + }, + ), + ], + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + ), + bottom: TabBar( + indicator: BoxDecoration(color: Color.fromARGB(255, 50, 39, 122)), + tabs: [ + Tab(text: 'Peminjaman Hari ini'), ], ), ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : TabBarView( + children: [ + SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: PaginatedDataTable( + // header: Text('Searching'), // Removed const + rowsPerPage: _pageSize, + availableRowsPerPage: [10, 25, 50], // Removed const + onRowsPerPageChanged: (value) { + setState(() { + _pageSize = value!; + }); + }, + columns: [ + DataColumn(label: Text('No')), + DataColumn(label: Text('')), + DataColumn(label: Text('Kode Peti')), + DataColumn(label: Text('Nama Customer')), + DataColumn(label: Text('Tgl Peminjaman')), + DataColumn(label: Text('Est Peminjaman')), + DataColumn(label: Text('PJ Peminjaman')), + DataColumn(label: Text('Asal Gudang')), + DataColumn(label: Text('Tujuan Gudang')), + ], + source: _DataSourceLokal( + data: _data!, + context: context, + petiData: _petiData != null ? _petiData : [], + tipePetiData: + _tipePetiData != null ? _tipePetiData : [], + customerData: + _customerData != null ? _customerData : [], + warehouseData: + _warehouseData != null ? _warehouseData : [], + ), + ), + ), + ], + ), + ), + ], + ), + bottomNavigationBar: BottomAppBar( + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Container( + height: 65.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + customBorder: CircleBorder(), + onTap: () { + // Aksi ketika ikon diklik + Navigator.pushNamed(context, '/peminjaman-barang/create'); + }, + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.greenAccent[700], + ), + child: Icon( + Icons.add, + size: 30, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ), ), ); } } -class _DataSource extends DataTableSource { +class _DataSourceLokal extends DataTableSource { final List data; + List? petiData; + List? tipePetiData; + List? customerData; + List? warehouseData; final BuildContext context; - _DataSource({required this.data, required this.context}); + _DataSourceLokal({ + required this.data, + required this.petiData, + required this.tipePetiData, + required this.customerData, + required this.warehouseData, + required this.context, + }); @override DataRow? getRow(int index) { if (index >= data.length) { return null; } + data.sort((a, b) { + if (a.created_at == null && b.created_at == null) { + return 0; // Both dates are null, consider them equal + } else if (a.created_at == null) { + return 1; // Null is considered greater than non-null + } else if (b.created_at == null) { + return -1; // Non-null is considered smaller than null + } else { + return b.created_at!.compareTo(a.created_at!); // Compare non-null dates + } + }); + final item = data[index]; + // Menemukan data peti yang sesuai dengan asset + PetiAssetModel? petiSqfliteApi; + if (item.peti_id != null) { + petiSqfliteApi = petiData!.firstWhere( + (peti) => peti.id == item.peti_id, + orElse: () => PetiAssetModel( + id: null, + tipe_peti_id: null, + warna: 'null', + packing_no: null, + customer_id: null, + warehouse_id: null, + kondisipeti_id: null, + jumlah: null, + date_pembuatan: DateTime.now(), + created_by: 'null', + updated_by: 'null', + fix_lot: '', + ), + ); + } + + TypePetiModel? tipePetiSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.tipe_peti_id != null) { + tipePetiSqfliteApi = tipePetiData?.firstWhere( + (tipePeti) => tipePeti.id == petiSqfliteApi?.tipe_peti_id, + orElse: () => TypePetiModel( + id: null, + type: 'null', + size_peti: 'null', + description: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + CustomerModel? customerSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.customer_id != null) { + customerSqfliteApi = customerData?.firstWhere( + (customer) => customer.id == item.customer_id, + orElse: () => CustomerModel( + id: null, + name: 'null', + code_customer: 'null', + lot_no: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + WarehouseModel? warehouseSqfliteApi; + if (item.warehouse_id != null) { + warehouseSqfliteApi = warehouseData?.firstWhere( + (warehouse) => warehouse.id == item.warehouse_id, + orElse: () => WarehouseModel( + id: null, + name: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + WarehouseModel? warehouseTujuanSqfliteApi; + warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == item.exit_warehouse, + ); + return DataRow(cells: [ DataCell( Text( @@ -200,7 +711,7 @@ class _DataSource extends DataTableSource { context, MaterialPageRoute( builder: (context) => DetailPeminjamanBarangPage( - assetId: item.id!, + peminjamanId: item.id.toString(), ), ), ); @@ -215,22 +726,27 @@ class _DataSource extends DataTableSource { ), DataCell( Text( - // item.asset.exit_at.toString(), - item.peti!.customer!.code_customer.toString() + - '-' + - item.peti!.tipe_peti!.type.toString(), + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + ), + ), + DataCell( + Text( + customerSqfliteApi != null && customerSqfliteApi.name != null + ? customerSqfliteApi!.name.toString() + : '-', ), ), DataCell( Text( - item.peti!.customer!.name.toString(), + item.exit_at != null + ? DateFormat('dd-MM-yyyy').format(item.exit_at!) + : '-', ), ), DataCell( Text( - // item.asset.exit_at.toString(), - // item.exit_at.toString(), - // DateFormat('dd-MM-yyyy').format(item.est_pengembalian!) item.est_pengembalian != null ? DateFormat('dd-MM-yyyy').format(item.est_pengembalian!) : '-', @@ -238,11 +754,23 @@ class _DataSource extends DataTableSource { ), DataCell( Text( - item.exit_pic.toString(), + item.exit_pic != null ? item.exit_pic.toString() : '-', ), ), DataCell( - Text(item.warehouse!.name.toString()), + Text( + warehouseSqfliteApi != null && warehouseSqfliteApi.name != null + ? warehouseSqfliteApi.name.toString() + : '-', + ), + ), + DataCell( + Text( + warehouseTujuanSqfliteApi != null && + warehouseTujuanSqfliteApi.name != null + ? warehouseTujuanSqfliteApi.name.toString() + : '-', + ), ), ]); } diff --git a/lib/pages/peminjaman_barang/show.dart b/lib/pages/peminjaman_barang/show.dart index 5804526..1d88abd 100644 --- a/lib/pages/peminjaman_barang/show.dart +++ b/lib/pages/peminjaman_barang/show.dart @@ -1,13 +1,19 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/pages/peminjaman_barang/controller/peminjaman_controller.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; -import 'package:siopas/connection/connection.dart'; +import 'package:collection/collection.dart'; + +import '../../models/warehouse_mode.dart'; +import '../../services/controllerApi.dart'; class DetailPeminjamanBarangPage extends StatefulWidget { - final int assetId; - const DetailPeminjamanBarangPage({Key? key, required this.assetId}) + final String peminjamanId; + + const DetailPeminjamanBarangPage({Key? key, required this.peminjamanId}) : super(key: key); @override @@ -17,54 +23,118 @@ class DetailPeminjamanBarangPage extends StatefulWidget { class _DetailPeminjamanBarangPageState extends State { - Map? assetStatusData; + AssetStatusModel? peminjamanInfo; + WarehouseModel? warehouseInfo; - String _formatDate(String date) { - DateTime parsedDate = DateTime.parse(date); - String formattedDate = - DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); - return formattedDate; - } + List? petiData; + List? customerData; + List? warehouseData; + + bool loading = true; @override void initState() { super.initState(); - _fetchAssetStatusData(); + getPeminjamanIdData(); + customerListAPI(); + petiListAPI(); + warehouseListAPI(); + initializeDateFormatting('id_ID', null); + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerData = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } } - Future _fetchAssetStatusData() async { - try { - final response = await http.get( - Uri.parse('$baseUrl/asset-status/peminjaman/show/${widget.assetId}'), - headers: { - 'Content-Type': 'application/json', - }, - ); + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + petiData = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - if (response.statusCode == 200) { + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { setState(() { - assetStatusData = json.decode(response.body)['data']['asset_status']; + warehouseData = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; }); - } else { - throw Exception('Failed to load data'); - } - } catch (e) { - print('Error fetching data: $e'); + }); + } + } + + Future getPeminjamanIdData() async { + List peminjamans = + await Controller().fetchPeminjamanDataId(); + peminjamanInfo = peminjamans.firstWhereOrNull( + (peminjaman) => peminjaman.id.toString() == widget.peminjamanId, + ); + + setState(() {}); + } + + String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } else { + return ''; } } @override Widget build(BuildContext context) { + PetiAssetModel? petiSqfliteApi; + petiSqfliteApi = petiData?.firstWhereOrNull( + (peti) => peti.id == peminjamanInfo!.peti_id, + ); + + CustomerModel? customerSqfliteApi; + customerSqfliteApi = customerData?.firstWhereOrNull( + (customer) => customer.id == peminjamanInfo?.customer_id, + ); + + WarehouseModel? warehouseSqfliteApi; + warehouseSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, + ); + WarehouseModel? warehouseTujuanSqfliteApi; + warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, + ); + return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Detail Peminjaman Barang', - style: TextStyle( - color: Colors.white, - fontSize: 16, - )), + title: Text( + 'Detail Peminjaman Barang', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), leading: IconButton( icon: Icon(Icons.arrow_back, color: Colors.white), onPressed: () { @@ -91,45 +161,85 @@ class _DetailPeminjamanBarangPageState color: Colors.indigo[700], child: Padding( padding: const EdgeInsets.all(16.0), - child: Row( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.article, - size: 40, - color: Colors.white), // Ganti ikon sesuai kebutuhan - SizedBox(width: 10), - Text( - 'ID: ${widget.assetId}', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), + Row( + children: [ + Icon(Icons.article, size: 30, color: Colors.white), + SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ID:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + SizedBox(height: 5), + Text( + petiSqfliteApi != null && + petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ], ), ], ), ), ), SizedBox(height: 10), - if (assetStatusData != null) ...[ + if (peminjamanInfo != null) ...[ _buildDetailItem( 'Kode Peti', - assetStatusData!['peti']['customer']['code_customer'] + - ' - ' + - assetStatusData!['peti']['tipe_peti']['type'], + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', ), - // _buildDetailItem( - // 'Peti Nama', assetStatusData!['peti']['fix_lot']), Divider(thickness: 1), - _buildDetailItem('Nama Customer', - assetStatusData!['peti']['customer']['name']), + _buildDetailItem( + 'Nama Customer', + customerSqfliteApi != null && customerSqfliteApi.name != null + ? customerSqfliteApi!.name.toString() + : '-', + ), + Divider(thickness: 1), + _buildDetailItem('Tgl Peminjaman', + _formatDate(peminjamanInfo!.exit_at.toString())), + Divider(thickness: 1), + _buildDetailItem('Est Peminjaman', + _formatDate(peminjamanInfo!.est_pengembalian.toString())), Divider(thickness: 1), _buildDetailItem( - 'Tgl Peminjaman', _formatDate(assetStatusData!['exit_at'])), + 'PJ Peminjaman', peminjamanInfo!.exit_pic.toString()), Divider(thickness: 1), - _buildDetailItem('PJ Peminjaman', assetStatusData!['exit_pic']), + _buildDetailItem( + 'Asal Warehouse', + // peminjamanInfo!.exit_warehouse.toString()), + warehouseSqfliteApi != null && + warehouseSqfliteApi.name != null + ? warehouseSqfliteApi!.name.toString() + : '-'), Divider(thickness: 1), _buildDetailItem( - 'Exit Warehouse', assetStatusData!['warehouse']['name']), + 'Exit Warehouse', + // peminjamanInfo!.exit_warehouse.toString()), + warehouseSqfliteApi != null && + warehouseSqfliteApi.name != null + ? warehouseSqfliteApi!.name.toString() + : '-'), + Divider(thickness: 1), // ... tambahkan data lainnya sesuai kebutuhan ], ], @@ -147,7 +257,7 @@ class _DetailPeminjamanBarangPageState children: [ Text( label, - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.bold), ), Text(value), ], diff --git a/lib/pages/pengembalian_barang/conn/syncronize.dart b/lib/pages/pengembalian_barang/conn/syncronize.dart new file mode 100644 index 0000000..c69574f --- /dev/null +++ b/lib/pages/pengembalian_barang/conn/syncronize.dart @@ -0,0 +1,218 @@ +import 'dart:convert'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:intl/intl.dart'; +import '../../../connection/connection.dart'; +import '../../../migrations/databasehelper.dart'; +import '../../../models/asset_status_model.dart'; +import 'package:http/http.dart' as http; + +class SyncronizationPengembalianData { + Future addData(AssetStatusModel assetStatusModel) async { + final dbClient = await conn.db; + late int result; + try { + result = await dbClient!.insert( + SqfliteDatabaseHelper.pengembalianTable, assetStatusModel.toJson()); + } catch (e) { + print('Error adding data to local SQLite: $e'); + result = 0; // Handle the error appropriately + } + return result; + } + + Future fetchData() async { + var dbclient = await conn.db; + List assetStatusList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.pengembalianTable, orderBy: 'id DESC'); + for (var item in maps) { + assetStatusList.add(item); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllInfo() async { + final dbClient = await conn.db; + List assetStatusList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.pengembalianTable); + for (var item in maps) { + assetStatusList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return assetStatusList; + } + + Future deleteAllAssetStatusData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.pengembalianTable); + } + + Future savePengembalianToServerWith( + List assetStatusesLocalList) async { + for (var i = 0; i < assetStatusesLocalList.length; i++) { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + // Format tanggal sesuai kebutuhan + String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i].created_at!) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "peti_id": assetStatusesLocalList[i].peti_id.toString(), + "enter_at": assetStatusesLocalList[i].enter_at.toString(), + "enter_pic": assetStatusesLocalList[i].enter_pic.toString(), + "enter_warehouse": assetStatusesLocalList[i].enter_warehouse.toString(), + "kondisi_peti_id": assetStatusesLocalList[i].kondisi_peti_id.toString(), + "updated_by": assetStatusesLocalList[i].updated_by.toString(), + "updated_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/update'), + body: data, + ); + + if (response.statusCode == 200) { + // print("Data uploaded successfully for index $i:"); + // print("Response body: ${response.body}"); + print("Saving Data saveToPengembalianWith"); + } else { + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Response body: ${response.body}"); + } + } + + return true; // Pengunggahan berhasil + } + + Future fetchAllCustomerInfo() async { + final dbClient = await conn.db; + List contactList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.pengembalianTable); + for (var item in maps) { + contactList.add(item); + } + } catch (e) { + print(e.toString()); + } + return contactList; + } + + Future saveToMysql(List assetStatusesLocalList) async { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + for (var i = 0; i < assetStatusesLocalList.length; i++) { +// Format tanggal sesuai kebutuhan + String formattedCreatedAt = + assetStatusesLocalList[i]['created_at'] != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(assetStatusesLocalList[i]['created_at']) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "peti_id": assetStatusesLocalList[i]['peti_id'].toString(), + "enter_at": assetStatusesLocalList[i]['enter_at'].toString(), + "enter_pic": assetStatusesLocalList[i]['enter_pic'].toString(), + "enter_warehouse": + assetStatusesLocalList[i]['enter_warehouse'].toString(), + "kondisi_peti_id": + assetStatusesLocalList[i]['kondisi_peti_id'].toString(), + "updated_by": assetStatusesLocalList[i]['updated_by'].toString(), + "updated_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/asset-status/update'), + body: data); + if (response.statusCode == 200) { + print(response.body); + print("Saving Data saveToMysql"); + } else { + print(response.statusCode); + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + } + } + } + + Future> fetchFromApi() async { + final response = await http.get( + Uri.parse(await getBaseUrl() + '/asset-status'), + ); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['asset_status']; + List contactDBList = data + .map( + (item) => AssetStatusModel.fromJson(item as Map)) + .toList(); + + return contactDBList; + } else { + throw Exception('Failed to fetch data from API Asset Status'); + } + } +} diff --git a/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart b/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart new file mode 100644 index 0000000..4971402 --- /dev/null +++ b/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart @@ -0,0 +1,221 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:http/http.dart' as http; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:sqflite/sqflite.dart'; + +import '../../../migrations/databasehelper.dart'; + +class ControllerPengembalian { + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllPengembalianInfo() async { + final dbClient = await conn.db; + List pengembalianList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.pengembalianTable); + for (var item in maps) { + pengembalianList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return pengembalianList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + Future addPengembalianData(AssetStatusModel pengembalianAddModel) async { + var dbclient = await conn.db; + int result = 0; // Provide an initial value + try { + result = await dbclient!.insert(SqfliteDatabaseHelper.pengembalianTable, + pengembalianAddModel.toJson()); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future updatePengembalianData( + AssetStatusModel pengembalianAddModel) async { + var dbclient = await conn.db; + late int result; + try { + result = await dbclient!.update( + SqfliteDatabaseHelper.pengembalianTable, + pengembalianAddModel.toJson(), + where: 'id=?', + whereArgs: [pengembalianAddModel.id], + ); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future fetchPengembalianLocalController() async { + var dbclient = await conn.db; + List pengembalianStatusList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.pengembalianTable, orderBy: 'id DESC'); + for (var item in maps) { + pengembalianStatusList.add(item); + } + } catch (e) { + print(e.toString()); + } + return pengembalianStatusList; + } + + Future> fetchPengembalianDataId() async { + var dbclient = await conn.db; + List pengembalianList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.pengembalianTable, orderBy: 'id DESC'); + for (var item in maps) { + pengembalianList.add(AssetStatusModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return pengembalianList; + } + + Future deleteAllData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.pengembalianTable); + } + + Future addAllData(List pengembalianList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var pengembalian in pengembalianList) { + batch.insert( + SqfliteDatabaseHelper.pengembalianTable, + pengembalian.toJson(), + ); + } + + await batch.commit(); + } + + Future fetchPetiData() async { + var dbclient = await conn.db; + List petiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.petiTable, orderBy: 'id DESC'); + for (var item in maps) { + petiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return petiList; + } + + Future fetchTipePetiData() async { + var dbclient = await conn.db; + List tipePetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.typePetiTable, orderBy: 'id DESC'); + for (var item in maps) { + tipePetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return tipePetiList; + } + + Future fetchCustomerData() async { + var dbclient = await conn.db; + List customerList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.customerTable, orderBy: 'id DESC'); + for (var item in maps) { + customerList.add(item); + } + } catch (e) { + print(e.toString()); + } + return customerList; + } + + Future fetchWarehouseData() async { + var dbclient = await conn.db; + List warehouseList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.warehouseTable, orderBy: 'id DESC'); + for (var item in maps) { + warehouseList.add(item); + } + } catch (e) { + print(e.toString()); + } + return warehouseList; + } + + Future fetchConditionData() async { + var dbclient = await conn.db; + List conditionList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.conditionPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + conditionList.add(item); + } + } catch (e) { + print(e.toString()); + } + return conditionList; + } + + Future fetchDisposalData() async { + var dbclient = await conn.db; + List disposalList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.disposalTable, orderBy: 'id DESC'); + for (var item in maps) { + disposalList.add(item); + } + } catch (e) { + print(e.toString()); + } + return disposalList; + } +} diff --git a/lib/pages/pengembalian_barang/edit.dart b/lib/pages/pengembalian_barang/edit.dart index 868d503..4e14f55 100644 --- a/lib/pages/pengembalian_barang/edit.dart +++ b/lib/pages/pengembalian_barang/edit.dart @@ -1,22 +1,39 @@ import 'dart:convert'; +import 'dart:core'; import 'package:flutter/material.dart'; -import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:intl/date_symbol_data_local.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/condition_peti_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/pages/peminjaman_barang/conn/syncronize.dart'; +import 'package:siopas/pages/pengembalian_barang/conn/syncronize.dart'; +import 'package:siopas/pages/pengembalian_barang/controller/pengembalian_controller.dart'; +import 'package:siopas/services/controllerApi.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:siopas/connection/connection.dart'; -import 'package:http/http.dart' as http; -import 'package:siopas/models/asset_status_model.dart'; -// import 'package:siopas/models/m_asset_status_model.dart'; -import 'package:siopas/models/user_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; import 'package:siopas/models/warehouse_mode.dart'; -import 'package:siopas/providers/auth_provider.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/date_symbol_data_local.dart'; // Import package intl +import 'package:uuid/uuid.dart'; + +import '../../connection/connection.dart'; +import 'package:http/http.dart' as http; + +import '../../models/user_model.dart'; +import '../../providers/auth_provider.dart'; +import '../peminjaman_barang/controller/peminjaman_controller.dart'; +import 'package:collection/collection.dart'; + +// import 'conn/syncronizeAPI.dart'; +// import 'controller/peminjaman_controller.dart'; class CreatePengembalianBarangPage extends StatefulWidget { - const CreatePengembalianBarangPage({super.key}); + const CreatePengembalianBarangPage({Key? key}) : super(key: key); @override State createState() => @@ -25,15 +42,32 @@ class CreatePengembalianBarangPage extends StatefulWidget { class _CreatePengembalianBarangPageState extends State { - List _dataAsset = []; - List _dataWarehouse = []; - bool _isLoading = false; + List? _data; + String? token; - AssetStatusModel? _valAsset; - WarehouseModel? _valWarehouse; + List? typePetiSqfliteApi; + // List? customerSqfliteApi; + + PetiAssetModel? petiSqfliteApi; + ConditionPetiModel? conditionPetiSqfliteApi; + WarehouseModel? warehouseSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valconditionPeti; + + CustomerModel? customerSqfliteApi; + List? _valcustomer; + + List _unrestrictedPetiList = []; + List _filteredPetiList = []; + bool isQRCodeScanned = false; + + bool loading = true; TextEditingController _enterAtController = TextEditingController(); - TextEditingController _enterPicController = TextEditingController(); - TextEditingController _kondisiPetiController = TextEditingController(); + // TextEditingController _enterPicController = TextEditingController(); + // TextEditingController _kondisiPetiController = TextEditingController(); + // TextEditingController _penanggungJawabController = TextEditingController(); final _formKey = GlobalKey(); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); @@ -44,9 +78,15 @@ class _CreatePengembalianBarangPageState void initState() { super.initState(); _getUserToken(); - fetchDataWarehouse(); - fetchDataAsset(); - initializeDateFormatting('id_ID'); + warehouseListAPI(); + + datatablesAssetStatusList(); + // typePetiListAPI(); + // customerListAPI(); + petiListAPI(); + kondisiPetiListAPI(); + + initializeDateFormatting('id_ID', null); } void _getUserToken() async { @@ -54,75 +94,70 @@ class _CreatePengembalianBarangPageState if (mounted) { setState(() { token = prefs.getString('token'); + loading = false; }); } } - Future fetchDataAsset() async { - setState(() { - _isLoading = true; - }); - - final response = - await http.get(Uri.parse('$baseUrl/asset-status/pengembalian/create')); - + Future warehouseListAPI() async { if (mounted) { - // Periksa apakah widget masih "mounted" - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['asset_status']; - - final List newDataAsset = (jsonData as List) - .map((item) => AssetStatusModel.fromJson(item)) - .toList(); - - if (mounted) { - // Periksa lagi sebelum memanggil setState - setState(() { - _dataAsset.addAll(newDataAsset); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Asset Status'); - } + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); } } - Future fetchDataWarehouse() async { - setState(() { - _isLoading = true; + Future datatablesAssetStatusList() async { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); }); + } - final response = await http.get(Uri.parse('$baseUrl/m-warehouse')); - + Future petiListAPI() async { if (mounted) { - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['warehouse']; + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - final List newDataWarehouse = (jsonData as List) - .map((item) => WarehouseModel.fromJson(item)) - .toList(); + Future kondisiPetiListAPI() async { + if (mounted) { + await ControllerApi().fetchKondisiPetiDataAPI().then((value) { + setState(() { + _valconditionPeti = (value as List) + .map((item) => ConditionPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - if (mounted) { - setState(() { - _dataWarehouse.addAll(newDataWarehouse); - _isLoading = false; - }); - } + Future isInteret() async { + await SyncronizationPengembalianData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Warehouse'); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); } - } + }); } Future _onQRViewCreated(QRViewController controller) async { @@ -134,108 +169,164 @@ class _CreatePengembalianBarangPageState await Future.delayed(const Duration(milliseconds: 400)); controller.flipCamera(); - controller.scannedDataStream.listen((scanData) { - if (!scanned) { - try { - setState(() { - result = scanData; - - List lines = result!.code!.split('\n'); - - String idPeti = ''; - - for (String line in lines) { - if (line.contains(';')) { - List values = line.split(';'); - if (values.length >= 3) { - idPeti = values[1]; - break; + controller.scannedDataStream.listen( + (scanData) { + if (!scanned) { + try { + setState(() { + result = scanData; + List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + + for (String line in lines) { + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; + } } } - } - - int? petiId = int.tryParse(idPeti); - - if (petiId != null) { - _valAsset = _dataAsset.firstWhere( - (peminjaman) => peminjaman.peti_id == petiId, - orElse: () => _valAsset!, - ); - } else { - // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.warning, - color: Colors.black, // Warna ikon - ), - SizedBox(width: 8), // Jarak antara ikon dan teks - Text( - 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + + int? petiId = int.tryParse(idPeti); + int? warehouseId = int.tryParse(idWarehouse); + // AuthProvider authProvider = Provider.of(context, listen: false); + // UserModel user = authProvider.user; + + // Dalam fungsi yang menangani pemindaian QR code + // Dalam fungsi yang menangani pemindaian QR code + if (petiId != null && warehouseId != null) { + // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan + PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + (peti) => + peti.id == petiId && + peti.deleted_at != true && + peti.status == 'AKTIF', + ); + + if (allowedPeti != null) { + setState(() { + isQRCodeScanned = true; + // Mengisi _filteredPetiList untuk dropdown hasil QR Code + _filteredPetiList = [ + _valpeti!.firstWhere((peti) => peti.id == allowedPeti.id) + ]; + + petiSqfliteApi = allowedPeti; + + warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( + (warehouse) => warehouse.id == allowedPeti.warehouse_id, + ); + + customerSqfliteApi = _valcustomer?.firstWhereOrNull( + (customer) => customer.id == allowedPeti.customer_id, + ); + }); + } else { + // Tampilkan pesan error jika data tidak sesuai dengan hak akses + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', style: TextStyle( - color: Colors.black, + color: Colors.white, fontSize: 12, - ), // Warna teks + ), ), - ], + backgroundColor: Colors.red[700], + action: SnackBarAction( + label: 'Tutup', + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } + } else { + // Tampilkan pesan error jika nilai yang dipindai tidak sesuai + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, + ), + SizedBox(width: 8), + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), + ), + ], + ), + backgroundColor: Colors.yellow[700], ), - backgroundColor: Colors.yellow[700], - ), - ); - } - - scanned = true; - }); - - controller.stopCamera(); - - Future.delayed(Duration(milliseconds: 500), () { - if (mounted) { - Navigator.pop(context); - } - }); - } catch (e) { - controller.stopCamera(); - if (mounted) { - Navigator.pushNamed(context, '/pengembalian-barang/create'); - } - print('Error scanning QR Code: $e'); + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.error, // Icon error - color: Colors.red[400], // Warna merah - ), - SizedBox(width: 8), - Flexible( - // Menggunakan Flexible untuk menghindari overflow - child: Text( - 'Peti ini belum ada di menu pinjaman, silahkan untuk mengecek kembali.', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), // Warna teks merah + scanned = true; + }); + + controller.stopCamera(); + + Future.delayed(Duration(milliseconds: 500), () { + if (mounted) { + Navigator.of(context).pop(); + } + }); + } catch (e) { + controller.stopCamera(); + + // Reset nilai dropdown Peti dan Warehouse + setState(() { + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + print('Error scanning QR Code: $e'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.error, + color: Colors.red[400], ), - ), - ], + SizedBox(width: 8), + Flexible( + child: Text( + e.toString(), + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ), + ], + ), + backgroundColor: Colors.red[700], ), - backgroundColor: Colors.red[700], - ), - ); + ); + } } - } - }); - } - - @override - void dispose() { - super.dispose(); - controller?.dispose(); + }, + ); } @override @@ -243,110 +334,71 @@ class _CreatePengembalianBarangPageState AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 150.0 - : 300.0; - Future _updatePeminjaman() async { - setState(() { - _isLoading = true; - }); + // var uuid = Uuid(); - try { - final response = await http.put( - Uri.parse('$baseUrl/asset-status/update/${_valAsset!.id}'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': token!, - }, - body: jsonEncode({ - 'enter_at': _enterAtController.text, - 'enter_pic': _enterPicController.text, - 'enter_warehouse': _valWarehouse!.id, - 'kondisi_peti': _kondisiPetiController.text, - 'updated_by': user.fullname, - }), - ); - - print(response.body); + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['asset_status']; + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } - print('Berhasil memperbarui data: $jsonData'); + Future saveAssetData() async { + DateTime now = DateTime.now().toLocal(); + String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); + + if (_enterAtController.text.isNotEmpty) { + AssetStatusModel pengembalianAddModel = AssetStatusModel( + id: null, + peti_id: petiSqfliteApi!.id, + enter_at: parseDateTime(_enterAtController.text), + enter_pic: user.fullname, + enter_warehouse: warehouseSqfliteApi!.id, + kondisi_peti_id: conditionPetiSqfliteApi!.id, + updated_by: user.fullname, + updated_at: parseDateTime(formattedDate), + ); - // Tampilkan snackbar - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.greenAccent[700], - content: Row( - children: [ - Icon( - Icons.check_circle_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Data berhasil dikembalikan'), - ], - ), - duration: Duration(seconds: 3), // Durasi tampilan snackbar - ), - ); - - // Reset form input - _valAsset = null; - _enterAtController.text = ''; - _enterPicController.text = ''; - _kondisiPetiController.text = ''; - _valWarehouse = null; + // Call addData function + int result = await ControllerPengembalian() + .addPengembalianData(pengembalianAddModel); + if (result > 0) { + print("Success Tambah data"); + // print(result); + Navigator.pushNamed(context, '/pengembalian-barang'); + EasyLoading.showSuccess("Data Berhasil Disimpan"); } else { - throw Exception('Gagal memperbarui data Asset Status'); - } - } catch (e) { - print('Error updating data: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Gagal memperbarui data'), - ], - ), - duration: Duration(seconds: 2), // Durasi tampilan snackbar - ), - ); - } finally { - if (mounted) { - setState(() { - _isLoading = false; - }); + print("Failed"); } } } + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 250.0 + : 300.0; return Scaffold( appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Colors.indigo[700], elevation: 0, - backgroundColor: Color.fromARGB(255, 5, 28, 158), - title: Text('Pengembalian Barang'), - leading: IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - Navigator.pushNamed(context, '/pengembalian-barang'); - }, - ), + title: Text('Buat Pengembalian barang', + style: TextStyle( + fontSize: 16, + )), ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) + body: loading + ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( - child: Container( - padding: EdgeInsets.all(10.0), + child: Padding( + padding: const EdgeInsets.all(8.0), child: Form( key: _formKey, child: Column( @@ -358,8 +410,7 @@ class _CreatePengembalianBarangPageState elevation: 2, child: Container( margin: EdgeInsets.all(8), - child: - DropdownButtonFormField( + child: DropdownButtonFormField( validator: (value) { if (value == null) { return 'Harus diisi'; @@ -371,24 +422,48 @@ class _CreatePengembalianBarangPageState border: OutlineInputBorder(), ), hint: Text("Pilih Peti"), - value: _valAsset, - items: - _dataAsset.map((AssetStatusModel item) { - return DropdownMenuItem( - child: Text('${item.peti!.fix_lot!}'), - value: item, + value: petiSqfliteApi, + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .map((PetiAssetModel peti) { + return DropdownMenuItem( + child: Text( + '${peti.fix_lot}', + style: TextStyle( + fontSize: 12, + ), + ), + value: peti, ); }).toList(), - onChanged: (AssetStatusModel? value) { + onChanged: (PetiAssetModel? value) { setState(() { - _valAsset = value; + petiSqfliteApi = value; + if (value != null) { + warehouseSqfliteApi = + _valwarehouse?.firstWhere( + (warehouse) => + warehouse.id == + value.warehouse_id, + ); + + // Perbarui _unrestrictedPetiList sesuai pemilihan manual + _unrestrictedPetiList = [ + _valpeti!.firstWhere( + (peti) => peti.id == value.id) + ]; + } }); }, ), ), ), ), - SizedBox(width: 8), // Spacer antara dua card Card( elevation: 2, @@ -401,10 +476,6 @@ class _CreatePengembalianBarangPageState ), child: IconButton( onPressed: () { - setState(() { - _valAsset = - null; // Mengatur _valAsset menjadi null - }); showModalBottomSheet( context: context, isScrollControlled: @@ -468,32 +539,6 @@ class _CreatePengembalianBarangPageState ), ], ), - - SizedBox(height: 16), - // Visibility( - // visible: false, - // child: - Card( - elevation: 2, - child: Padding( - padding: const EdgeInsets.all(8), - child: TextFormField( - controller: _enterPicController = - TextEditingController(text: user.fullname), - decoration: InputDecoration( - labelText: 'Penanggung Jawab', - border: OutlineInputBorder(), - ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Harus diisi'; - } - return null; // Return null jika tidak ada kesalahan - }, - ), - ), - ), - // ), SizedBox(height: 16), Card( elevation: 2, @@ -512,7 +557,8 @@ class _CreatePengembalianBarangPageState color: Colors.white, ), SizedBox(width: 5), - Text('Tanggal Pengembalian'), + Text( + 'Tanggal Pengembalian harus diisi'), ], ), duration: Duration(seconds: 2), @@ -525,8 +571,10 @@ class _CreatePengembalianBarangPageState controller: _enterAtController, name: 'tanggal', inputType: InputType.date, - // format: DateFormat('dd-MMMM-yyyy', 'id_ID'), + // format: DateFormat('yyyy-MM-dd HH:mm:ss.SSS'), format: DateFormat('yyyy-MM-dd', 'id_ID'), + // format: DateFormat('yyyy-MM-dd'), + decoration: InputDecoration( labelText: 'Tanggal Pengembalian', border: OutlineInputBorder(), @@ -535,12 +583,10 @@ class _CreatePengembalianBarangPageState ), ), ), - - SizedBox(height: 16), + SizedBox(height: 13), Card( - elevation: 2, child: Padding( - padding: const EdgeInsets.all(8), + padding: const EdgeInsets.all(8.0), child: DropdownButtonFormField( validator: (value) { if (value == null) { @@ -553,74 +599,80 @@ class _CreatePengembalianBarangPageState border: OutlineInputBorder(), ), hint: Text("Pilih Gudang"), - value: _valWarehouse, - items: - _dataWarehouse.map((WarehouseModel warehouse) { - return DropdownMenuItem( - child: Text('${warehouse.name}'), - value: warehouse, - ); - }).toList(), + value: warehouseSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouse) => + warehouse.deleted_at != true) + .map((WarehouseModel warehouse) { + return DropdownMenuItem( + child: Text('${warehouse.name}'), + value: warehouse, + ); + }).toList() ?? + [], onChanged: (WarehouseModel? value) { setState(() { - _valWarehouse = value; + warehouseSqfliteApi = value; }); }, ), ), ), - - SizedBox(height: 16.0), + SizedBox(height: 13), Card( - elevation: 2, child: Padding( - padding: const EdgeInsets.all(8), - child: TextFormField( - controller: _kondisiPetiController, - decoration: InputDecoration( - labelText: 'Kondisi Barang', - border: OutlineInputBorder(), - ), + padding: const EdgeInsets.all(8.0), + child: DropdownButtonFormField( validator: (value) { - if (value == null || value.isEmpty) { + if (value == null) { return 'Harus diisi'; } - return null; // Return null jika tidak ada kesalahan + return null; }, - ), - ), - ), - SizedBox(height: 20.0), - Visibility( - visible: false, - child: FractionallySizedBox( - widthFactor: 1.0, - child: Card( - elevation: 1, - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: [ - Text( - 'Data dari QR Code:', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 8), - Text( - result != null && result!.code != null - ? result!.code! - : 'Belum ada data QR Code terpindai', - style: TextStyle(fontSize: 14), - ), - ], - ), + decoration: InputDecoration( + labelText: 'Pilih Kondisi Peti', + border: OutlineInputBorder(), ), + hint: Text("Pilih Kondisi Peti"), + value: conditionPetiSqfliteApi, + items: (_valconditionPeti ?? []) + .where( + (kondisi) => kondisi.deleted_at != true) + .map((ConditionPetiModel kondisi) { + return DropdownMenuItem( + child: Text('${kondisi.nama_kondisi}'), + value: kondisi, + ); + }).toList() ?? + [], + onChanged: (ConditionPetiModel? value) { + setState(() { + conditionPetiSqfliteApi = value; + }); + }, ), ), ), + // SizedBox(height: 16.0), + // Card( + // elevation: 2, + // child: Padding( + // padding: const EdgeInsets.all(8), + // child: TextFormField( + // controller: _kondisiPetiController, + // decoration: InputDecoration( + // labelText: 'Kondisi Barang', + // border: OutlineInputBorder(), + // ), + // validator: (value) { + // if (value == null || value.isEmpty) { + // return 'Harus diisi'; + // } + // return null; // Return null jika tidak ada kesalahan + // }, + // ), + // ), + // ), ], ), ), @@ -668,11 +720,13 @@ class _CreatePengembalianBarangPageState color: Colors.green, // Warna hijau untuk save ), child: IconButton( - onPressed: () { + onPressed: () async { if (_formKey.currentState!.validate()) { try { - if (_enterAtController.text.isNotEmpty) { - _updatePeminjaman(); + if (_enterAtController.text.isNotEmpty && + petiSqfliteApi != null && + warehouseSqfliteApi != null) { + await saveAssetData(); } } catch (e) { print('Error storing data: $e'); diff --git a/lib/pages/pengembalian_barang/index.dart b/lib/pages/pengembalian_barang/index.dart new file mode 100644 index 0000000..3f757d7 --- /dev/null +++ b/lib/pages/pengembalian_barang/index.dart @@ -0,0 +1,801 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/condition_peti_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/disposal_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:siopas/pages/pengembalian_barang/conn/syncronize.dart'; +import 'package:siopas/pages/pengembalian_barang/controller/pengembalian_controller.dart'; +import 'package:siopas/pages/pengembalian_barang/show.dart'; +import 'package:siopas/services/syncronizeAPI.dart'; +import 'package:siopas/services/controllerApi.dart'; +import 'package:siopas/pages/peminjaman_barang/controller/peminjaman_controller.dart'; +import 'package:intl/intl.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:collection/collection.dart'; + +import '../peminjaman_barang/show.dart'; +// import 'show.dart'; + +class PengembalianBarangPage extends StatefulWidget { + const PengembalianBarangPage({super.key}); + + @override + State createState() => PengembalianBarangPageState(); +} + +class PengembalianBarangPageState extends State { + String? token; + bool loading = true; + + // Reinit atau Upload Only + WarehouseModel? warehouseSqfliteApi; + List? typePetiSqfliteApi; + List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + ConditionPetiModel? conditionPetiSqfliteApi; + DisposalPetiModel? disposalSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valconditionPeti; + List? _valdisposal; + + // Datatable + int _currentPage = 1; + int _pageSize = 10; + List? _data; + List? _petiData; + List? _tipePetiData; + List? _customerData; + List? _warehouseData; + List? _conditionData; + bool _isLoading = false; + Timer? _timer; + + @override + void initState() { + super.initState(); + _getUserToken(); + + warehouseListAPI(); + conditionPetiListAPI(); + typePetiListAPI(); + customerListAPI(); + petiListAPI(); + // disposalListAPI(); + + // Tampil data Datatables + datatablesPengembalianList(); + datatablesPetiList(); + datatablesTipePetiList(); + datatablesCustomerList(); + datatablesWarehouseList(); + datatablesConditionList(); + _data = []; + } + + void _getUserToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + token = prefs.getString('token'); + }); + } + } + + // Reinit atau Upload Only ------------------------------------------------------------------------ + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + // Future disposalListAPI() async { + // if (mounted) { + // await ControllerApi().fetchDisposalDataAPI().then((value) { + // setState(() { + // _valdisposal = (value as List) + // .map((item) => DisposalPetiModel.fromJson(item)) + // .toList(); + // loading = false; + // }); + // }); + // } + // } + + Future typePetiListAPI() async { + if (mounted) { + await ControllerApi().fetchTipePetiDataAPI().then((value) { + setState(() { + typePetiSqfliteApi = (value as List) + .map((item) => TypePetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerSqfliteApi = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future conditionPetiListAPI() async { + if (mounted) { + await ControllerApi().fetchKondisiPetiDataAPI().then((value) { + setState(() { + _valconditionPeti = (value as List) + .map((item) => ConditionPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + // Future reinitAssetStatusApi() async { + // List assetStatusApiData = + // await SyncronizationDataAPI().fetchAssetStatusFromApi(); + // await ControllerApi() + // .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite + // } + + Future reinitWarehouseApi() async { + EasyLoading.show(status: 'Mengambil data Warehouse...'); + List warehouseApiData = + await SyncronizationDataAPI().fetchWarehouseFromApi(); + await ControllerApi() + .deleteAllWarehouseDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllWarehouseDataAPI(warehouseApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitPetiApi() async { + EasyLoading.show(status: 'Mengambil data Peti...'); + List petiApiData = + await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() + .deleteAllPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitCustomerApi() async { + EasyLoading.show(status: 'Mengambil data Customer...'); + List customerApiData = + await SyncronizationDataAPI().fetchCustomerFromApi(); + await ControllerApi() + .deleteAllCustomerDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllCustomerDataAPI(customerApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitConditionPetiApi() async { + EasyLoading.show(status: 'Mengambil data Condition Peti...'); + List conditionPetiApiData = + await SyncronizationDataAPI().fetchKondisiPetiFromApi(); + await ControllerApi() + .deleteAllKondisiPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi().addAllKondisiPetiDataAPI( + conditionPetiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + // Future reinitDisposalApi() async { + // List disposalApiData = + // await SyncronizationDataAPI().fetchDisposalFromApi(); + // await ControllerApi() + // .deleteAllDisposalDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllDisposalDataAPI(disposalApiData); // Add new data to SQLite + // } + + Future fetchDataFromApiAndSync() async { + EasyLoading.show(status: 'Mengambil data dari Server...'); + try { + await syncToMysql(); + + // await reinitAssetStatusApi(); + await reinitWarehouseApi(); + await reinitPetiApi(); + await reinitCustomerApi(); + // await reinitTypePetiApi(); + await reinitConditionPetiApi(); + // await reinitDisposalApi(); + + await datatablesPengembalianList(); + EasyLoading.showSuccess('Data berhasil diperbarui'); + } catch (e) { + EasyLoading.showError('Gagal memperbarui data: $e'); + } finally { + EasyLoading.dismiss(); + } + } + + Future syncToMysql() async { + await SyncronizationPengembalianData() + .fetchAllInfo() + .then((assetList) async { + EasyLoading.show( + status: 'Jangan tutup aplikasi. Kami sedang menyinkronkan...'); + await Future.delayed(Duration(seconds: 3)); + + // Tambahkan penanganan pengunggahan + bool uploadSuccess = await SyncronizationPengembalianData() + .savePengembalianToServerWith(assetList); + + // Jika pengunggahan berhasil, hapus data lokal + if (uploadSuccess) { + await SyncronizationPengembalianData().deleteAllAssetStatusData(); + // Setelah selesai, tampilkan pesan sukses + await datatablesPengembalianList(); + EasyLoading.showSuccess('Berhasil disinkronkan dengan Server'); + } else { + // Tampilkan pesan gagal jika pengunggahan tidak berhasil + EasyLoading.showError('Gagal disinkronkan dengan Server'); + } + }); + } + + // Future syncToMysql() async { + // await SyncronizationData().fetchAllInfo().then((assetList) async { + // EasyLoading.show(status: 'Don\'t close app. We are syncing...'); + // await SyncronizationData().saveToMysqlWith(assetList); + // await SyncronizationData().deleteAllAssetStatusData(); + // // EasyLoading.showSuccess('Successfully saved to MySQL'); + // }); + // } + + Future isInteret() async { + await SyncronizationPengembalianData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); + } else { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); + } + }); + } + + // Datatables ------------------------------------------------------------------------ + Future datatablesPengembalianList() async { + await ControllerPengembalian() + .fetchPengembalianLocalController() + .then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesPetiList() async { + await ControllerPengembalian().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesTipePetiList() async { + await ControllerPengembalian().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesCustomerList() async { + await ControllerPengembalian().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesWarehouseList() async { + await ControllerPengembalian().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesConditionList() async { + await ControllerPengembalian().fetchConditionData().then((value) { + setState(() { + _conditionData = (value as List) + .map((e) => ConditionPetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + void _loadMoreData() { + if (mounted && !_isLoading) { + setState(() { + _currentPage++; + }); + datatablesPengembalianList(); + } + } + + @override + Widget build(BuildContext context) { + // Add this function outside the build method + void showSyncDialog(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + // Dialog shape and style + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: Colors.grey[100], + elevation: 0, + + // Dialog content + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Dialog title with close button + Container( + width: double.infinity, + color: Colors.indigo[700], // Indigo background + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Sync Server Pengembalian", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); // Close dialog + }, + ), + ], + ), + ), + + // Divider + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + + // Re-init Button + Container( + width: double.infinity, + child: TextButton( + onPressed: () { + Navigator.pop(context); // Close dialog + fetchDataFromApiAndSync(); + }, + child: Text( + "Upload + Download", + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), + ), + ), + + // Divider + // Divider( + // height: 1, + // thickness: 1, + // color: Colors.black, // Black divider + // ), + + // Upload Only Button + // Container( + // width: double.infinity, + // child: TextButton( + // onPressed: () { + // Navigator.pop(context); // Close dialog + // syncToMysql(); + // }, + // child: Text( + // "Upload Only", + // style: TextStyle( + // color: Colors.black, + // fontSize: 16.0, + // fontFamily: 'Poppins', + // ), + // ), + // ), + // ), + ], + ), + ); + }, + ); + } + + return DefaultTabController( + length: 1, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Data Pengembalian Barang', + style: TextStyle( + fontSize: 16, + )), + actions: [ + IconButton( + icon: Icon(Icons.backup), + onPressed: () async { + if (await SyncronizationPengembalianData.isInternet()) { + // Display custom dialog when the IconButton is pressed + showSyncDialog(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("No internet connection")), + ); + } + }, + ), + ], + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + ), + bottom: TabBar( + indicator: BoxDecoration(color: Color.fromARGB(255, 50, 39, 122)), + tabs: [ + Tab(text: 'Pengembalian Peti Hari ini'), + ], + ), + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : TabBarView( + children: [ + SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: PaginatedDataTable( + // header: Text('Searching'), // Removed const + rowsPerPage: _pageSize, + availableRowsPerPage: [10, 25, 50], // Removed const + onRowsPerPageChanged: (value) { + setState(() { + _pageSize = value!; + }); + }, + columns: [ + DataColumn(label: Text('No')), + DataColumn(label: Text('')), + DataColumn(label: Text('Kode Peti')), + DataColumn(label: Text('Tgl Pengembalian')), + DataColumn(label: Text('PJ Pengembalian')), + DataColumn(label: Text('Tujuan WH Pengembalian')), + DataColumn(label: Text('Kondisi Peti')), + ], + source: _DataSourceLokal( + data: _data!, + context: context, + petiData: _petiData != null ? _petiData : [], + tipePetiData: + _tipePetiData != null ? _tipePetiData : [], + customerData: + _customerData != null ? _customerData : [], + warehouseData: + _warehouseData != null ? _warehouseData : [], + conditionData: + _conditionData != null ? _conditionData : [], + ), + ), + ), + ], + ), + ), + ], + ), + bottomNavigationBar: BottomAppBar( + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Container( + height: 65.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + customBorder: CircleBorder(), + onTap: () { + // Aksi ketika ikon diklik + Navigator.pushNamed(context, '/pengembalian-barang/edit'); + }, + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.greenAccent[700], + ), + child: Icon( + Icons.add, + size: 30, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +class _DataSourceLokal extends DataTableSource { + final List data; + List? petiData; + List? tipePetiData; + List? customerData; + List? warehouseData; + List? conditionData; + final BuildContext context; + + _DataSourceLokal({ + required this.data, + required this.petiData, + required this.tipePetiData, + required this.customerData, + required this.warehouseData, + required this.conditionData, + required this.context, + }); + @override + DataRow? getRow(int index) { + if (index >= data.length) { + return null; + } + + data.sort((a, b) { + if (a.created_at == null && b.created_at == null) { + return 0; // Both dates are null, consider them equal + } else if (a.created_at == null) { + return 1; // Null is considered greater than non-null + } else if (b.created_at == null) { + return -1; // Non-null is considered smaller than null + } else { + return b.created_at!.compareTo(a.created_at!); // Compare non-null dates + } + }); + + final item = data[index]; + + // Menemukan data peti yang sesuai dengan asset + PetiAssetModel? petiSqfliteApi; + if (item.peti_id != null) { + petiSqfliteApi = petiData!.firstWhere( + (peti) => peti.id == item.peti_id, + orElse: () => PetiAssetModel( + id: null, + tipe_peti_id: null, + warna: 'null', + packing_no: null, + customer_id: null, + warehouse_id: null, + kondisipeti_id: null, + jumlah: null, + date_pembuatan: DateTime.now(), + created_by: 'null', + updated_by: 'null', + fix_lot: '', + ), + ); + } + + TypePetiModel? tipePetiSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.tipe_peti_id != null) { + tipePetiSqfliteApi = tipePetiData?.firstWhere( + (tipePeti) => tipePeti.id == petiSqfliteApi?.tipe_peti_id, + orElse: () => TypePetiModel( + id: null, + type: 'null', + size_peti: 'null', + description: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + CustomerModel? customerSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.customer_id != null) { + customerSqfliteApi = customerData?.firstWhere( + (customer) => customer.id == petiSqfliteApi?.customer_id, + orElse: () => CustomerModel( + id: null, + name: 'null', + code_customer: 'null', + lot_no: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + ConditionPetiModel? conditionSqfliteApi; + if (item.kondisi_peti_id != null) { + conditionSqfliteApi = conditionData?.firstWhere( + (warehouse) => warehouse.id == item.kondisi_peti_id, + orElse: () => ConditionPetiModel( + id: null, + nama_kondisi: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + WarehouseModel? warehouseSqfliteApi; + if (item.enter_warehouse != null) { + warehouseSqfliteApi = warehouseData?.firstWhere( + (warehouse) => warehouse.id == item.enter_warehouse, + orElse: () => WarehouseModel( + id: null, + name: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + return DataRow(cells: [ + DataCell( + Text( + (index + 1).toString(), + ), + ), + DataCell( + GestureDetector( + onTap: () { + if (item.id != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailPengembalianBarangPage( + pengembalianId: item.id.toString(), + ), + ), + ); + + // print('asset id: ${item.id}'); + } + }, + child: Icon(Icons.article, + size: 40, + color: Colors.indigo[700]), // Ganti ikon sesuai kebutuhan + ), + ), + DataCell( + Text( + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + ), + ), + DataCell( + Text( + item.enter_at != null + ? DateFormat('dd-MM-yyyy').format(item.enter_at!) + : '-', + ), + ), + DataCell( + Text( + item.enter_pic.toString() != 'null' ? item.enter_pic.toString() : '-', + ), + ), + DataCell( + Text( + (item.enter_warehouse != null && item.enter_warehouse != 'null') + ? warehouseSqfliteApi != null && + warehouseSqfliteApi.id == item.enter_warehouse + ? warehouseSqfliteApi.name.toString() + : '-' + : '-', + ), + ), + DataCell( + Text( + conditionSqfliteApi != null && + conditionSqfliteApi.nama_kondisi != null + ? conditionSqfliteApi!.nama_kondisi.toString() + : '-', + ), + ), + ]); + } + + @override + bool get isRowCountApproximate => false; + + @override + int get rowCount => data.length; + + @override + int get selectedRowCount => 0; +} diff --git a/lib/pages/pengembalian_barang/pengembalian_index.dart b/lib/pages/pengembalian_barang/pengembalian_index.dart deleted file mode 100644 index cd2b237..0000000 --- a/lib/pages/pengembalian_barang/pengembalian_index.dart +++ /dev/null @@ -1,296 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; - -import 'package:flutter/material.dart'; -import 'package:data_table_2/data_table_2.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:siopas/models/asset_status_model.dart'; -import 'package:siopas/pages/pengembalian_barang/show.dart'; -import 'package:siopas/providers/asset_status_provider.dart'; -import 'package:http/http.dart' as http; - -import '../../connection/connection.dart'; -import '../peminjaman_barang/show.dart'; - -class PengembalianBarangPage extends StatefulWidget { - const PengembalianBarangPage({super.key}); - - @override - State createState() => PengembalianBarangPageState(); -} - -class PengembalianBarangPageState extends State { - String? token; - int _currentPage = 1; - int _pageSize = 10; - List _data = []; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - _getUserToken(); - fetchData(); - } - - void _getUserToken() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - if (mounted) { - setState(() { - token = prefs.getString('token'); - }); - } - } - - Future fetchData() async { - if (mounted) { - setState(() { - _isLoading = true; - }); - - try { - final response = - await http.get(Uri.parse('$baseUrl/asset-status/pengembalian')); - - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['asset_status']; - - final List newData = (jsonData as List) - .map((item) => AssetStatusModel.fromJson(item)) - .toList(); - - if (mounted) { - setState(() { - _data.addAll(newData); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data'); - } - } catch (e) { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - print('Error fetching data: $e'); - } - } - } - - void _loadMoreData() { - if (mounted && !_isLoading) { - setState(() { - _currentPage++; - }); - fetchData(); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.indigo[700], - elevation: 0, - title: Text('Data Pengembalian Barang', - style: TextStyle( - fontSize: 16, - )), - leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushNamed(context, '/home'); - }, - ), - ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - child: SizedBox( - width: double.infinity, - child: PaginatedDataTable( - header: const Text('Pengembalian Barang'), - rowsPerPage: _pageSize, - availableRowsPerPage: const [10, 25, 50], - onRowsPerPageChanged: (value) { - setState(() { - _pageSize = value!; - }); - }, - columns: const [ - DataColumn(label: Text('No')), - DataColumn(label: Text('')), - DataColumn(label: Text('Kode Peti')), - DataColumn(label: Text('Tgl Peminjaman')), - DataColumn(label: Text('Estimasi Pengembalian')), - DataColumn(label: Text('PJ Peminjaman')), - DataColumn(label: Text('Asal WH Peminjaman')), - DataColumn(label: Text('Tgl Pengembalian')), - DataColumn(label: Text('PJ Pengembalian')), - DataColumn(label: Text('Tujuan WH Pengembalian')), - DataColumn(label: Text('Kondisi Peti')), - DataColumn(label: Text('Status')), - ], - source: _DataSource(data: _data, context: context), - ), - ), - ), - bottomNavigationBar: BottomAppBar( - color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang - child: Container( - height: 65.0, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - customBorder: CircleBorder(), - onTap: () { - // Aksi ketika ikon diklik - Navigator.pushNamed(context, '/pengembalian-barang/create'); - }, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.greenAccent[700], - ), - child: Icon( - Icons.add, - size: 30, - color: Colors.white, - ), - ), - ), - ], - ), - ), - ), - ); - } -} - -class _DataSource extends DataTableSource { - final List data; - final BuildContext context; - - _DataSource({required this.data, required this.context}); - @override - DataRow? getRow(int index) { - if (index >= data.length) { - return null; - } - - final item = data[index]; - - return DataRow(cells: [ - DataCell( - Text( - (index + 1).toString(), - ), - ), - DataCell( - GestureDetector( - onTap: () { - if (item.id != null) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => DetailPengembalianBarangPage( - pengembalianId: item.id!, - ), - ), - ); - - print('asset id: ${item.id}'); - } - }, - child: Icon( - Icons.article_outlined, - size: 30, - color: Colors.indigo[700], - ), - ), - ), - DataCell( - Text( - // item.asset.exit_at.toString(), - item.peti!.customer!.code_customer.toString() + - '-' + - item.peti!.tipe_peti!.type.toString(), - ), - ), - DataCell( - Text( - item.exit_at != null - ? DateFormat('dd-MM-yyyy').format(item.exit_at!) - : '-', - ), - ), - DataCell( - Text( - // item.asset.exit_at.toString(), - item.est_pengembalian != null - ? DateFormat('dd-MM-yyyy').format(item.est_pengembalian!) - : '-', - ), - ), - DataCell( - Text( - item.exit_pic.toString() != 'null' ? item.exit_pic.toString() : '-', - ), - ), - DataCell( - Text(item.warehouse!.name.toString() != 'null' - ? item.warehouse!.name.toString() - : '-'), - ), - DataCell( - Text( - item.enter_at != null - ? DateFormat('dd-MM-yyyy').format(item.enter_at!) - : '-', - ), - ), - DataCell( - Text( - item.enter_pic.toString() != 'null' ? item.enter_pic.toString() : '-', - ), - ), - DataCell( - Text( - item.warehouse_enter!.id == item.enter_warehouse - ? item.warehouse_enter!.name.toString() - : '-', - ), - ), - DataCell( - Text(item.kondisi_peti.toString() != 'null' - ? item.kondisi_peti.toString() - : '-'), - ), - DataCell( - Text(item.warehouse_enter!.name == 'null' ? '-' : 'Sudah Dikembalikan'), - ), - ]); - } - - @override - bool get isRowCountApproximate => false; - - @override - int get rowCount => data.length; - - @override - int get selectedRowCount => 0; -} diff --git a/lib/pages/pengembalian_barang/show.dart b/lib/pages/pengembalian_barang/show.dart index 9cb0a46..56703dc 100644 --- a/lib/pages/pengembalian_barang/show.dart +++ b/lib/pages/pengembalian_barang/show.dart @@ -1,12 +1,19 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/condition_peti_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/pages/pengembalian_barang/controller/pengembalian_controller.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; -import 'package:siopas/connection/connection.dart'; +import 'package:collection/collection.dart'; + +import '../../models/warehouse_mode.dart'; +import '../../services/controllerApi.dart'; class DetailPengembalianBarangPage extends StatefulWidget { - final int pengembalianId; + final String pengembalianId; + const DetailPengembalianBarangPage({Key? key, required this.pengembalianId}) : super(key: key); @@ -17,60 +24,134 @@ class DetailPengembalianBarangPage extends StatefulWidget { class _DetailPengembalianBarangPageState extends State { - Map? assetStatusData; + AssetStatusModel? pengembalianInfo; + WarehouseModel? warehouseInfo; - String _formatDate(String date) { - try { - DateTime parsedDate = DateTime.parse(date); - String formattedDate = - DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); - return formattedDate; - } catch (e) { - // Handle the case where the date string is not valid - return 'Invalid date format'; - } - } + List? petiData; + List? customerData; + List? warehouseData; + List? _valconditionPeti; + + bool loading = true; @override void initState() { super.initState(); - _fetchAssetStatusDataPengembalian(); + getPengembalianIdData(); + customerListAPI(); + petiListAPI(); + warehouseListAPI(); + kondisiPetiListAPI(); + initializeDateFormatting('id_ID', null); + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerData = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + petiData = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future kondisiPetiListAPI() async { + if (mounted) { + await ControllerApi().fetchKondisiPetiDataAPI().then((value) { + setState(() { + _valconditionPeti = (value as List) + .map((item) => ConditionPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } } - Future _fetchAssetStatusDataPengembalian() async { - try { - final response = await http.get( - Uri.parse( - '$baseUrl/asset-status/pengembalian/show/${widget.pengembalianId}'), - headers: { - 'Content-Type': 'application/json', - }, - ); - - if (response.statusCode == 200) { + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { setState(() { - assetStatusData = json.decode(response.body)['data']['asset_status']; + warehouseData = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; }); - } else { - throw Exception('Failed to load data'); - } - } catch (e) { - print('Error fetching data: $e'); + }); + } + } + + Future getPengembalianIdData() async { + List pengembalians = + await ControllerPengembalian().fetchPengembalianDataId(); + pengembalianInfo = pengembalians.firstWhereOrNull( + (pengembalian) => pengembalian.id.toString() == widget.pengembalianId, + ); + + setState(() {}); + } + + String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } else { + return ''; } } @override Widget build(BuildContext context) { + PetiAssetModel? petiSqfliteApi; + petiSqfliteApi = petiData?.firstWhereOrNull( + (peti) => peti.id == pengembalianInfo!.peti_id, + ); + + CustomerModel? customerSqfliteApi; + customerSqfliteApi = customerData?.firstWhereOrNull( + (customer) => customer.id == pengembalianInfo?.customer_id, + ); + + WarehouseModel? warehouseSqfliteApi; + warehouseSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == pengembalianInfo!.enter_warehouse, + ); + + ConditionPetiModel? conditionPetiSqfliteApi; + conditionPetiSqfliteApi = _valconditionPeti?.firstWhereOrNull( + (conditionPeti) => conditionPeti.id == pengembalianInfo!.kondisi_peti_id, + ); + return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Detail Pengembalian Barang', - style: TextStyle( - color: Colors.white, - fontSize: 16, - )), + title: Text( + 'Detail Pengembalian Barang', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), leading: IconButton( icon: Icon(Icons.arrow_back, color: Colors.white), onPressed: () { @@ -97,89 +178,76 @@ class _DetailPengembalianBarangPageState color: Colors.indigo[700], child: Padding( padding: const EdgeInsets.all(16.0), - child: Row( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.article, - size: 40, - color: Colors.white), // Ganti ikon sesuai kebutuhan - SizedBox(width: 10), - Text( - 'ID: ${widget.pengembalianId}', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), + Row( + children: [ + Icon(Icons.article, size: 30, color: Colors.white), + SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ID:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + SizedBox(height: 5), + Text( + petiSqfliteApi != null && + petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ], ), ], ), ), ), SizedBox(height: 10), - if (assetStatusData != null) ...[ + if (pengembalianInfo != null) ...[ _buildDetailItem( 'Kode Peti', - assetStatusData!['peti']['customer']['code_customer'] + - ' - ' + - assetStatusData!['peti']['tipe_peti']['type'], + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', ), + Divider(thickness: 1), - _buildDetailItem( - 'Nama Customer', - assetStatusData!['peti']['customer']['name'] != null - ? assetStatusData!['peti']['customer']['name'] - .toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Tgl Peminjaman', - _formatDate(assetStatusData!['exit_at'] != null - ? assetStatusData!['exit_at'] - : '-')), + _buildDetailItem('Tgl Pengembalian', + _formatDate(pengembalianInfo!.enter_at.toString())), Divider(thickness: 1), _buildDetailItem( - 'PJ Peminjaman', - assetStatusData!['exit_pic'] != null - ? assetStatusData!['exit_pic'].toString() - : '-'), + 'PJ Pengembalian', pengembalianInfo!.enter_pic.toString()), Divider(thickness: 1), _buildDetailItem( - 'Asal WH Peminjaman', - assetStatusData!['warehouse']['name'] != null - ? assetStatusData!['warehouse']['name'].toString() + 'Gudang', + warehouseSqfliteApi != null && + warehouseSqfliteApi.name != null + ? warehouseSqfliteApi!.name.toString() : '-'), Divider(thickness: 1), _buildDetailItem( - 'Tgl Pengembalian', - assetStatusData!['enter_at'] != null && - assetStatusData!['enter_at'] != '0000-00-00 00:00:00' - ? _formatDate(assetStatusData!['enter_at']) + 'Kondisi Peti', + conditionPetiSqfliteApi != null && + conditionPetiSqfliteApi.nama_kondisi != null + ? conditionPetiSqfliteApi!.nama_kondisi.toString() : '-', ), Divider(thickness: 1), - _buildDetailItem( - 'PJ Pengembalian', - assetStatusData!['enter_pic'] != null - ? assetStatusData!['enter_pic'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Tujuan WH Pengembalian', - assetStatusData!['warehouse_enter'] != null - ? assetStatusData!['warehouse_enter']['name'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Kondisi Peti', - assetStatusData!['kondisi_peti'] != null - ? assetStatusData!['kondisi_peti'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Status', - assetStatusData!['warehouse_enter'] != null - ? assetStatusData!['warehouse_enter']['name'].toString() - : '-'), + // ... tambahkan data lainnya sesuai kebutuhan ], ], ), @@ -196,7 +264,7 @@ class _DetailPengembalianBarangPageState children: [ Text( label, - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.bold), ), Text(value), ], diff --git a/lib/pages/sign_in_page.dart b/lib/pages/sign_in_page.dart index d08c708..36b535a 100644 --- a/lib/pages/sign_in_page.dart +++ b/lib/pages/sign_in_page.dart @@ -19,38 +19,69 @@ class _SignInPageState extends State { bool isLoading = false; bool _isPasswordVisible = false; + // Create controllers for IP Address and Port + TextEditingController ipAddressController = TextEditingController(); + TextEditingController portController = TextEditingController(); + @override Widget build(BuildContext context) { final bool isSmallScreen = MediaQuery.of(context).size.width < 600; AuthProvider authProvider = Provider.of(context); UserModel user = authProvider.user; + // Function to show the SettingsModal + void _showSettingsModal(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return SettingsModal(); + }, + ); + } + return Scaffold( - body: Center( - child: isSmallScreen - ? SingleChildScrollView( - reverse: true, - scrollDirection: Axis.vertical, // Tambahkan ini - child: Column( - mainAxisSize: MainAxisSize.min, - children: const [ - _Logo(), - _FormContent(), - ], - ), - ) - : Container( - padding: const EdgeInsets.all(30.0), - constraints: const BoxConstraints(maxWidth: 800), - child: Row( - children: const [ - Expanded(child: _Logo()), - Expanded( - child: Center(child: _FormContent()), - ), - ], + body: Center( + child: isSmallScreen + ? SingleChildScrollView( + reverse: true, + scrollDirection: Axis.vertical, // Tambahkan ini + child: Column( + mainAxisSize: MainAxisSize.min, + children: const [ + _Logo(), + _FormContent(), + ], + ), + ) + : Container( + padding: const EdgeInsets.all(30.0), + constraints: const BoxConstraints(maxWidth: 800), + child: Row( + children: [ + Expanded(child: _Logo()), + Expanded( + child: Center(child: _FormContent()), ), - ))); + ], + ), + ), + ), + bottomNavigationBar: BottomAppBar( + color: Colors.grey[50], + elevation: 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () { + _showSettingsModal(context); // Show the modal + }, + child: Text('Settings'), + ), + ], + ), + ), + ); } } @@ -122,6 +153,9 @@ class __FormContentState extends State<_FormContent> { // Simpan token pengguna ke SharedPreferences SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('token', user.token!); // Pastikan user.token tidak null + // Role ID Operator + // final String roleId = 'A5C7B207-1A1C-43B8-89BF-222222222222'; + print('token dapat login: ${user.token}'); if (user.role_id == 2) { print('Berhasil login HALAMAN USER'); @@ -277,3 +311,95 @@ class __FormContentState extends State<_FormContent> { Widget _gap() => const SizedBox(height: 16); } + +class SettingsModal extends StatefulWidget { + const SettingsModal({Key? key}) : super(key: key); + + @override + State createState() => _SettingsModalState(); +} + +class _SettingsModalState extends State { + TextEditingController ipAddressController = TextEditingController(); + TextEditingController portController = TextEditingController(); + + @override + void initState() { + super.initState(); + // Load saved IP Address and Port when the modal is initialized + loadSettings(); + } + + void loadSettings() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String ipAddress = prefs.getString('ipAddress') ?? ''; + String port = prefs.getString('port') ?? ''; + + setState(() { + ipAddressController.text = ipAddress; + portController.text = port; + }); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Settings'), + GestureDetector( + onTap: () { + Navigator.of(context).pop(); // Close the modal + }, + child: Icon(Icons.close), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + controller: ipAddressController, + keyboardType: TextInputType.number, // Set numeric keyboard + decoration: InputDecoration(labelText: 'IP Address'), + ), + SizedBox(height: 16), + TextFormField( + controller: portController, + keyboardType: TextInputType.number, // Set numeric keyboard + decoration: InputDecoration(labelText: 'Port'), + ), + ], + ), + actions: [ + ElevatedButton( + onPressed: () { + // Save IP Address and Port to SharedPreferences + saveSettings(ipAddressController.text, portController.text); + Navigator.of(context).pop(); // Close the modal + }, + child: Text('Save'), + ), + ], + ); + } + + void saveSettings(String ipAddress, String port) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setString('ipAddress', ipAddress); + prefs.setString('port', port); + + // Print the saved data + print('IP Address saved: $ipAddress'); + print('Port saved: $port'); + } + + // Function to clear the IP Address and Port in SharedPreferences + void clearSettings() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.remove('ipAddress'); + prefs.remove('port'); + print('IP Address and Port cleared'); + } +} diff --git a/lib/pages/transfer_peti/conn/syncronize.dart b/lib/pages/transfer_peti/conn/syncronize.dart new file mode 100644 index 0000000..c9467d9 --- /dev/null +++ b/lib/pages/transfer_peti/conn/syncronize.dart @@ -0,0 +1,224 @@ +import 'dart:convert'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:intl/intl.dart'; +import '../../../connection/connection.dart'; +import '../../../migrations/databasehelper.dart'; +import '../../../models/asset_status_model.dart'; +import 'package:http/http.dart' as http; + +class SyncronizationTransferPetiData { + Future addData(TransferPetiModel transferPetiModel) async { + final dbClient = await conn.db; + late int result; + try { + result = await dbClient!.insert( + SqfliteDatabaseHelper.transferPetiTable, transferPetiModel.toJson()); + } catch (e) { + print('Error adding data to local SQLite: $e'); + result = 0; // Handle the error appropriately + } + return result; + } + + Future fetchData() async { + var dbclient = await conn.db; + List transferPetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.transferPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + transferPetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllInfoTransferPeti() async { + final dbClient = await conn.db; + List transferPetiList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.transferPetiTable); + for (var item in maps) { + transferPetiList.add(TransferPetiModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + Future deleteAllTransferPetiData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); + } + + Future saveTransferPetiServerWith( + List transferPetiLocalList) async { + for (var i = 0; i < transferPetiLocalList.length; i++) { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + // Format tanggal sesuai kebutuhan + String formattedCreatedAt = transferPetiLocalList[i].created_at != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(transferPetiLocalList[i].created_at!) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": transferPetiLocalList[i].mobile_id.toString(), // "id": "1 + "peti_id": transferPetiLocalList[i].peti_id.toString(), + "name_customer": transferPetiLocalList[i].name_customer.toString(), + "source_warehouse": + transferPetiLocalList[i].source_warehouse.toString(), + "destination_warehouse": + transferPetiLocalList[i].destination_warehouse.toString(), + "date": transferPetiLocalList[i].date.toString(), + "created_by": transferPetiLocalList[i].created_by.toString(), + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/m-transfer-peti/store'), + body: data, + ); + + if (response.statusCode == 200) { + // print("Data uploaded successfully for index $i:"); + // print("Response body: ${response.body}"); + print("Saving Data saveToTransferPetiWith"); + } else { + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Response body: ${response.body}"); + } + } + + return true; // Pengunggahan berhasil + } + + Future fetchAllPetiTransferInfo() async { + final dbClient = await conn.db; + List transferPetiList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.transferPetiTable); + for (var item in maps) { + transferPetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + Future saveToMysql(List transferPetiLocalList) async { + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + for (var i = 0; i < transferPetiLocalList.length; i++) { +// Format tanggal sesuai kebutuhan + String formattedCreatedAt = transferPetiLocalList[i]['created_at'] != null + ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + .format(transferPetiLocalList[i]['created_at']) + : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + Map data = { + "mobile_id": + transferPetiLocalList[i]['mobile_id'].toString(), // "id": "1 + "peti_id": transferPetiLocalList[i]['peti_id'].toString(), + "name_customer": transferPetiLocalList[i]['name_customer'].toString(), + "source_warehouse": + transferPetiLocalList[i]['source_warehouse'].toString(), + "destination_warehouse": + transferPetiLocalList[i]['destination_warehouse'].toString(), + "date": transferPetiLocalList[i]['date'].toString(), + "created_by": + transferPetiLocalList[i]['created_by'].toString(), // "id": "1 + "created_at": formattedCreatedAt, + }; + + final response = await http.post( + Uri.parse(await getBaseUrl() + '/m-transfer-peti/store'), + body: data); + if (response.statusCode == 200) { + print(response.body); + print("Saving Data Transfer Peti"); + } else { + print(response.statusCode); + print( + "Failed to upload data for index $i. Status code: ${response.statusCode}"); + } + } + } + + Future> fetchTransferPetiFromApi() async { + final response = await http.get( + Uri.parse(await getBaseUrl() + '/m-transfer-peti'), + ); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['transfer_peti']; + List transferPetiDBList = data + .map((item) => + TransferPetiModel.fromJson(item as Map)) + .toList(); + + return transferPetiDBList; + } else { + throw Exception('Failed to fetch data from API Transfer Peti'); + } + } +} diff --git a/lib/pages/transfer_peti/controller/transfer_peti_controller.dart b/lib/pages/transfer_peti/controller/transfer_peti_controller.dart new file mode 100644 index 0000000..59c8fbf --- /dev/null +++ b/lib/pages/transfer_peti/controller/transfer_peti_controller.dart @@ -0,0 +1,191 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +// import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +// import 'package:http/http.dart' as http; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:sqflite/sqflite.dart'; + +import '../../../migrations/databasehelper.dart'; + +class ControllerTransferPeti { + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAllInfo() async { + final dbClient = await conn.db; + List transferPetiList = []; + try { + final maps = + await dbClient!.query(SqfliteDatabaseHelper.transferPetiTable); + for (var item in maps) { + transferPetiList.add(TransferPetiModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + static Future isInternet() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + + Future addData(TransferPetiModel transferPetiAddModel) async { + var dbclient = await conn.db; + int result = 0; // Provide an initial value + try { + result = await dbclient!.insert(SqfliteDatabaseHelper.transferPetiTable, + transferPetiAddModel.toJson()); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future updateData(TransferPetiModel transferPetiAddModel) async { + var dbclient = await conn.db; + late int result; + try { + result = await dbclient!.update( + SqfliteDatabaseHelper.transferPetiTable, + transferPetiAddModel.toJson(), + where: 'id=?', + whereArgs: [transferPetiAddModel.id], + ); + } catch (e) { + print(e.toString()); + } + return result; + } + + Future fetchTransferPetiLocalController() async { + var dbclient = await conn.db; + List transferPetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.transferPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + transferPetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + Future> fetchDataId() async { + var dbclient = await conn.db; + List transferPetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.transferPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + transferPetiList.add(TransferPetiModel.fromJson(item)); + } + } catch (e) { + print(e.toString()); + } + return transferPetiList; + } + + Future deleteAllData() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); + } + + Future addAllData(List transferPetiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var transferPeti in transferPetiList) { + batch.insert( + SqfliteDatabaseHelper.transferPetiTable, + transferPeti.toJson(), + ); + } + + await batch.commit(); + } + + Future fetchPetiData() async { + var dbclient = await conn.db; + List petiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.petiTable, orderBy: 'id DESC'); + for (var item in maps) { + petiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return petiList; + } + + Future fetchTipePetiData() async { + var dbclient = await conn.db; + List tipePetiList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.typePetiTable, orderBy: 'id DESC'); + for (var item in maps) { + tipePetiList.add(item); + } + } catch (e) { + print(e.toString()); + } + return tipePetiList; + } + + Future fetchCustomerData() async { + var dbclient = await conn.db; + List customerList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.customerTable, orderBy: 'id DESC'); + for (var item in maps) { + customerList.add(item); + } + } catch (e) { + print(e.toString()); + } + return customerList; + } + + Future fetchWarehouseData() async { + var dbclient = await conn.db; + List warehouseList = []; + try { + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.warehouseTable, orderBy: 'id DESC'); + for (var item in maps) { + warehouseList.add(item); + } + } catch (e) { + print(e.toString()); + } + return warehouseList; + } +} diff --git a/lib/pages/transfer_peti/edit.dart b/lib/pages/transfer_peti/edit.dart index 14a33c7..9936897 100644 --- a/lib/pages/transfer_peti/edit.dart +++ b/lib/pages/transfer_peti/edit.dart @@ -1,38 +1,71 @@ import 'dart:convert'; +import 'dart:core'; import 'package:flutter/material.dart'; -import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:intl/date_symbol_data_local.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/condition_peti_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/pages/peminjaman_barang/conn/syncronize.dart'; +import 'package:siopas/pages/pengembalian_barang/conn/syncronize.dart'; +import 'package:siopas/pages/transfer_peti/controller/transfer_peti_controller.dart'; +import 'package:siopas/services/controllerApi.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:siopas/connection/connection.dart'; -import 'package:http/http.dart' as http; -import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/models/m_asset_status_model.dart'; -// import 'package:siopas/models/m_asset_status_model.dart'; -import 'package:siopas/models/user_model.dart'; import 'package:siopas/models/warehouse_mode.dart'; -import 'package:siopas/providers/auth_provider.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/date_symbol_data_local.dart'; // Import package intl +import 'package:uuid/uuid.dart'; + +import '../../models/user_model.dart'; +import '../../providers/auth_provider.dart'; +import 'package:collection/collection.dart'; + +// import 'conn/syncronizeAPI.dart'; +// import 'controller/peminjaman_controller.dart'; class EditTransferPetiPage extends StatefulWidget { - const EditTransferPetiPage({super.key}); + const EditTransferPetiPage({Key? key}) : super(key: key); @override - State createState() => EditTransferPetiPageState(); + State createState() => _EditTransferPetiPageState(); } -class EditTransferPetiPageState extends State { - List _dataAsset = []; - List _dataWarehouse = []; - bool _isLoading = false; +class _EditTransferPetiPageState extends State { + List? _data; + String? token; - PetiAssetModel? _valAsset; - WarehouseModel? _valWarehouse_asal_gudang; - WarehouseModel? _valWarehouse_tujuan_gudang; - // TextEditingController _exit_atController = TextEditingController(); - // TextEditingController _est_pengembalianController = TextEditingController(); + List? typePetiSqfliteApi; + // List? customerSqfliteApi; + // List? warehouseTujuanSqfliteApi; + + PetiAssetModel? petiSqfliteApi; + ConditionPetiModel? conditionPetiSqfliteApi; + WarehouseModel? warehouseSqfliteApi; + WarehouseModel? warehouseTujuanSqfliteApi; + CustomerModel? customerItemSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valWarehouse_tujuan_gudang; + List? _valconditionPeti; + List? _valcustomer; + + CustomerModel? customerSqfliteApi; + + List _unrestrictedPetiList = []; + List _filteredPetiList = []; + bool isQRCodeScanned = false; + + bool loading = true; + TextEditingController _dateController = TextEditingController(); + // TextEditingController _enterPicController = TextEditingController(); + // TextEditingController _kondisiPetiController = TextEditingController(); // TextEditingController _penanggungJawabController = TextEditingController(); final _formKey = GlobalKey(); @@ -44,9 +77,15 @@ class EditTransferPetiPageState extends State { void initState() { super.initState(); _getUserToken(); - fetchDataWarehouse(); - fetchDataAsset(); - initializeDateFormatting('id_ID'); + warehouseListAPI(); + + datatablesTransferPetiList(); + // typePetiListAPI(); + customerListAPI(); + petiListAPI(); + kondisiPetiListAPI(); + + initializeDateFormatting('id_ID', null); } void _getUserToken() async { @@ -54,74 +93,85 @@ class EditTransferPetiPageState extends State { if (mounted) { setState(() { token = prefs.getString('token'); + loading = false; }); } } - Future fetchDataAsset() async { - setState(() { - _isLoading = true; - }); - - final response = await http.get(Uri.parse('$baseUrl/peti-asset')); - + Future warehouseListAPI() async { if (mounted) { - // Periksa apakah widget masih "mounted" - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['petis']; - - final List newDataAsset = (jsonData as List) - .map((item) => PetiAssetModel.fromJson(item)) - .toList(); + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - if (mounted) { - // Periksa lagi sebelum memanggil setState - setState(() { - _dataAsset.addAll(newDataAsset); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Asset Status'); - } + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + _valcustomer = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); } } - Future fetchDataWarehouse() async { - setState(() { - _isLoading = true; + Future datatablesTransferPetiList() async { + await ControllerTransferPeti() + .fetchTransferPetiLocalController() + .then((value) { + setState(() { + _data = (value as List) + .map((e) => TransferPetiModel.fromJson(e)) + .toList(); + loading = false; + }); }); + } - final response = await http.get(Uri.parse('$baseUrl/m-warehouse')); - + Future petiListAPI() async { if (mounted) { - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['warehouse']; + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - final List newDataWarehouse = (jsonData as List) - .map((item) => WarehouseModel.fromJson(item)) - .toList(); + Future kondisiPetiListAPI() async { + if (mounted) { + await ControllerApi().fetchKondisiPetiDataAPI().then((value) { + setState(() { + _valconditionPeti = (value as List) + .map((item) => ConditionPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - if (mounted) { - setState(() { - _dataWarehouse.addAll(newDataWarehouse); - _isLoading = false; - }); - } + Future isInteret() async { + await SyncronizationPengembalianData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data Warehouse'); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); } - } + }); } Future _onQRViewCreated(QRViewController controller) async { @@ -133,93 +183,164 @@ class EditTransferPetiPageState extends State { await Future.delayed(const Duration(milliseconds: 400)); controller.flipCamera(); - controller.scannedDataStream.listen((scanData) { - if (!scanned) { - try { - setState(() { - result = scanData; + controller.scannedDataStream.listen( + (scanData) { + if (!scanned) { + try { + setState(() { + result = scanData; + List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + + for (String line in lines) { + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; + } + } + } - List lines = result!.code!.split('\n'); + int? petiId = int.tryParse(idPeti); + int? warehouseId = int.tryParse(idWarehouse); + // AuthProvider authProvider = Provider.of(context, listen: false); + // UserModel user = authProvider.user; + + // Dalam fungsi yang menangani pemindaian QR code + // Dalam fungsi yang menangani pemindaian QR code + if (petiId != null && warehouseId != null) { + // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan + PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + (peti) => + peti.id == petiId && + peti.deleted_at != true && + peti.status == 'AKTIF', + ); + + if (allowedPeti != null) { + setState(() { + isQRCodeScanned = true; + // Mengisi _filteredPetiList untuk dropdown hasil QR Code + _filteredPetiList = [ + _valpeti!.firstWhere((peti) => peti.id == allowedPeti.id) + ]; + + petiSqfliteApi = allowedPeti; + + warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( + (warehouse) => warehouse.id == allowedPeti.warehouse_id, + ); + + customerItemSqfliteApi = _valcustomer?.firstWhereOrNull( + (customer) => customer.id == allowedPeti.customer_id, + ); + }); + } else { + // Tampilkan pesan error jika data tidak sesuai dengan hak akses + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + backgroundColor: Colors.red[700], + action: SnackBarAction( + label: 'Tutup', + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } + } else { + // Tampilkan pesan error jika nilai yang dipindai tidak sesuai + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, + ), + SizedBox(width: 8), + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), + ), + ], + ), + backgroundColor: Colors.yellow[700], + ), + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } - String idPeti = ''; - String idWarehouse = ''; + scanned = true; + }); - for (String line in lines) { - if (line.contains(';')) { - List values = line.split(';'); - if (values.length >= 3) { - idPeti = values[1]; - idWarehouse = values[2]; - break; - } + controller.stopCamera(); + + Future.delayed(Duration(milliseconds: 500), () { + if (mounted) { + Navigator.of(context).pop(); } - } - - int? petiId = int.tryParse(idPeti); - int? warehouseId = int.tryParse(idWarehouse); - - if (petiId != null && warehouseId != null) { - _valAsset = _dataAsset.firstWhere( - (peti) => peti.id == petiId, - orElse: () => _valAsset!, - ); - - _valWarehouse_asal_gudang = _dataWarehouse.firstWhere( - (warehouse) => warehouse.id == warehouseId, - orElse: () => _valWarehouse_asal_gudang!, - ); - } else { - // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.warning, - color: Colors.black, // Warna ikon - ), - SizedBox(width: 8), // Jarak antara ikon dan teks - Text( - 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + }); + } catch (e) { + controller.stopCamera(); + + // Reset nilai dropdown Peti dan Warehouse + setState(() { + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + print('Error scanning QR Code: $e'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.error, + color: Colors.red[400], + ), + SizedBox(width: 8), + Flexible( + child: Text( + e.toString(), style: TextStyle( - color: Colors.black, + color: Colors.white, fontSize: 12, - ), // Warna teks + ), ), - ], - ), - backgroundColor: - Colors.yellow[700], // Warna latar belakang SnackBar + ), + ], ), - ); - } - - scanned = true; - }); - - controller.stopCamera(); - - Future.delayed(Duration(milliseconds: 500), () { - if (mounted) { - Navigator.of(context).pop(); - } - }); - } catch (e) { - print('Error scanning QR Code: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Error scanning QR Code: $e'), - ), - ); + backgroundColor: Colors.red[700], + ), + ); + } } - } - }); - } - - @override - void dispose() { - super.dispose(); - controller?.dispose(); + }, + ); } @override @@ -227,117 +348,73 @@ class EditTransferPetiPageState extends State { AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 150.0 - : 300.0; - - // var now = DateTime.now(); - // var dt = DateTime(DateTime.now().year, DateTime.now().month, - // DateTime.now().day, DateTime.now().hour, DateTime.now().minute); - // // _exit_atController.text = DateFormat('yyyy-MM-dd HH:mm:ss').format(dt); - // _exit_atController.text = DateFormat('dd-MM-yyyy').format(dt); + var uuid = Uuid(); - Future _updateTransferPeti() async { - setState(() { - _isLoading = true; - }); + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } try { - final response = await http.put( - Uri.parse('$baseUrl/peti-asset/update/${_valAsset!.id}'), - headers: { - 'Content-Type': 'application/json', - 'Authorization': token!, - }, - body: jsonEncode({ - 'warehouse_id': _valWarehouse_tujuan_gudang!.id, - 'updated_by': user.fullname, - }), - ); - - print(response.body); - - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['petis']; + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } - print('Berhasil memperbarui data: $jsonData'); + Future saveAssetData() async { + DateTime now = DateTime.now().toLocal(); + String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); + + if (_dateController.text.isNotEmpty) { + TransferPetiModel transferPetiAddModel = TransferPetiModel( + id: null, + mobile_id: uuid.v4(), + peti_id: petiSqfliteApi!.id, + name_customer: customerItemSqfliteApi!.id, + source_warehouse: warehouseSqfliteApi!.id, + destination_warehouse: warehouseTujuanSqfliteApi!.id, + date: parseDateTime(_dateController.text), + created_by: user.fullname, + created_at: parseDateTime(formattedDate), + ); - // Tampilkan snackbar - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.greenAccent[700], - content: Row( - children: [ - Icon( - Icons.check_circle_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Data berhasil ditransferkan'), - ], - ), - duration: Duration(seconds: 3), // Durasi tampilan snackbar - ), - ); - - // Reset form input - _valAsset = null; - _valWarehouse_asal_gudang = null; - _valWarehouse_tujuan_gudang = null; - // _enterAtController.text = ''; - // _enterPicController.text = ''; - // _kondisiPetiController.text = ''; - // _valWarehouse = null; + // Call addData function + int result = + await ControllerTransferPeti().addData(transferPetiAddModel); + if (result > 0) { + print("Success Tambah data"); + // print(result); + Navigator.pushNamed(context, '/transfer-peti'); + EasyLoading.showSuccess("Data Berhasil Disimpan Transfer Peti"); } else { - _valAsset = null; - _valWarehouse_asal_gudang = null; - _valWarehouse_tujuan_gudang = null; - throw Exception('Gagal memperbarui data Asset Status'); - } - } catch (e) { - print('Error updating data: $e'); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Gagal memperbarui data'), - ], - ), - duration: Duration(seconds: 2), // Durasi tampilan snackbar - ), - ); - } finally { - if (mounted) { - setState(() { - _isLoading = false; - }); + print("Failed"); } } } + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 250.0 + : 300.0; + return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Buat Peminjaman Barang', + title: Text('Buat Transfer Peti', style: TextStyle( fontSize: 16, )), ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) + body: loading + ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Padding( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(8.0), child: Form( key: _formKey, child: Column( @@ -361,25 +438,46 @@ class EditTransferPetiPageState extends State { border: OutlineInputBorder(), ), hint: Text("Pilih Peti"), - value: _valAsset, - items: _dataAsset.map((PetiAssetModel item) { + value: petiSqfliteApi, + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .map((PetiAssetModel peti) { return DropdownMenuItem( - child: Text('${item.fix_lot}'), - value: item, + child: Text( + '${peti.fix_lot}', + style: TextStyle( + fontSize: 12, + ), + ), + value: peti, ); }).toList(), onChanged: (PetiAssetModel? value) { setState(() { - _valAsset = value; + petiSqfliteApi = value; if (value != null) { - // Set _valWarehouse berdasarkan warehouse_id dari PetiAssetModel - _valWarehouse_asal_gudang = - _dataWarehouse.firstWhere( + warehouseSqfliteApi = + _valwarehouse?.firstWhere( (warehouse) => warehouse.id == - int.parse(value.warehouse_id - .toString()), + value.warehouse_id, + ); + customerItemSqfliteApi = + _valcustomer?.firstWhereOrNull( + (customer) => + customer.id == value.customer_id, ); + + // Perbarui _unrestrictedPetiList sesuai pemilihan manual + _unrestrictedPetiList = [ + _valpeti!.firstWhere( + (peti) => peti.id == value.id) + ]; } }); }, @@ -467,7 +565,50 @@ class EditTransferPetiPageState extends State { elevation: 2, child: Padding( padding: const EdgeInsets.all(8), - child: DropdownButtonFormField( + child: FormBuilderDateTimePicker( + validator: (value) { + if (_dateController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text( + 'Tanggal Transfer Peti harus diisi'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + return null; // Return null jika ada kesalahan + } + return null; // Return null jika tidak ada kesalahan + }, + controller: _dateController, + name: 'tanggal', + inputType: InputType.date, + // format: DateFormat('yyyy-MM-dd HH:mm:ss.SSS'), + format: DateFormat('yyyy-MM-dd', 'id_ID'), + // format: DateFormat('yyyy-MM-dd'), + + decoration: InputDecoration( + labelText: 'Tanggal Transfer Peti', + border: OutlineInputBorder(), + suffixIcon: Icon(Icons.calendar_today), + ), + ), + ), + ), + SizedBox(height: 13), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: DropdownButtonFormField( validator: (value) { if (value == null) { return 'Harus diisi'; @@ -475,32 +616,33 @@ class EditTransferPetiPageState extends State { return null; }, decoration: InputDecoration( - labelText: 'Asal Gudang', + labelText: 'Pilih Customer', border: OutlineInputBorder(), ), - hint: Text("Asal Gudang"), - value: _valWarehouse_asal_gudang, - items: - _dataWarehouse.map((WarehouseModel warehouse) { - return DropdownMenuItem( - child: Text('${warehouse.name}'), - value: warehouse, - ); - }).toList(), - onChanged: null, - // (WarehouseModel? value) { - // setState(() { - // _valWarehouse_asal_gudang = value; - // }); - // }, + hint: Text("Pilih Customer"), + value: customerItemSqfliteApi, + items: (_valcustomer ?? []) + .where((customer) => + customer.deleted_at != true) + .map((CustomerModel customer) { + return DropdownMenuItem( + child: Text('${customer.name}'), + value: customer, + ); + }).toList() ?? + [], + onChanged: (CustomerModel? value) { + setState(() { + customerItemSqfliteApi = value; + }); + }, ), ), ), - SizedBox(height: 16), + SizedBox(height: 13), Card( - elevation: 2, child: Padding( - padding: const EdgeInsets.all(8), + padding: const EdgeInsets.all(8.0), child: DropdownButtonFormField( validator: (value) { if (value == null) { @@ -509,56 +651,102 @@ class EditTransferPetiPageState extends State { return null; }, decoration: InputDecoration( - labelText: 'Tujuan Gudang', + labelText: 'Pilih Asal Gudang', border: OutlineInputBorder(), ), - hint: Text("Tujuan Gudang"), - value: _valWarehouse_tujuan_gudang, - items: - _dataWarehouse.map((WarehouseModel warehouse) { - return DropdownMenuItem( - child: Text('${warehouse.name}'), - value: warehouse, - ); - }).toList(), + hint: Text("Pilih Asal Gudang"), + value: warehouseSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouse) => + warehouse.deleted_at != true) + .map((WarehouseModel warehouse) { + return DropdownMenuItem( + child: Text('${warehouse.name}'), + value: warehouse, + ); + }).toList() ?? + [], onChanged: (WarehouseModel? value) { setState(() { - _valWarehouse_tujuan_gudang = value; + warehouseSqfliteApi = value; }); }, ), ), ), - Visibility( - visible: false, - child: FractionallySizedBox( - widthFactor: 1.0, - child: Card( - elevation: 1, - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: [ - Text( - 'Data dari QR Code:', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 8), - Text( - result != null && result!.code != null - ? result!.code! - : 'Belum ada data QR Code terpindai', - style: TextStyle(fontSize: 14), - ), - ], - ), + + SizedBox(height: 13), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + labelText: 'Pilih Tujuan Gudang', + border: OutlineInputBorder(), ), + hint: Text("Pilih Tujuan Gudang"), + value: warehouseTujuanSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouseTujuan) => + warehouseTujuan.deleted_at != true) + .map((WarehouseModel warehouseTujuan) { + return DropdownMenuItem( + child: Text('${warehouseTujuan.name}'), + value: warehouseTujuan, + ); + }).toList() ?? + [], + onChanged: (WarehouseModel? value) { + setState(() { + warehouseTujuanSqfliteApi = value; + }); + }, ), ), ), + // SizedBox(height: 16), + // Card( + // elevation: 2, + // child: Padding( + // padding: const EdgeInsets.all(8), + // child: DropdownButtonFormField( + // validator: (value) { + // if (value == null) { + // return 'Harus diisi'; + // } + // return null; + // }, + // decoration: InputDecoration( + // labelText: 'Pilih Tujuan Gudang', + // border: OutlineInputBorder(), + // ), + // hint: Text("Pilih Tujuan Gudang"), + // value: warehouseTujuanSqfliteApi, + // items: (_valWarehouse_tujuan_gudang ?? []) + // .where( + // (warehouse) => warehouse.deleted_at != true) + // .map((WarehouseModel warehouse) + // // _valWarehouse_tujuan_gudang?.map((warehouse) + // { + // return DropdownMenuItem( + // child: Text('${warehouse.name}'), + // value: warehouse, + // ); + // }).toList(), + // onChanged: (WarehouseModel? value) { + // setState(() { + // warehouseTujuanSqfliteApi = value; + // }); + // }, + // ), + // ), + // ), ], ), ), @@ -606,10 +794,14 @@ class EditTransferPetiPageState extends State { color: Colors.green, // Warna hijau untuk save ), child: IconButton( - onPressed: () { + onPressed: () async { if (_formKey.currentState!.validate()) { try { - _updateTransferPeti(); + if (_dateController.text.isNotEmpty && + petiSqfliteApi != null && + warehouseSqfliteApi != null) { + await saveAssetData(); + } } catch (e) { print('Error storing data: $e'); } diff --git a/lib/pages/transfer_peti/index.dart b/lib/pages/transfer_peti/index.dart new file mode 100644 index 0000000..60c69a3 --- /dev/null +++ b/lib/pages/transfer_peti/index.dart @@ -0,0 +1,751 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/disposal_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:siopas/pages/peminjaman_barang/conn/syncronize.dart'; +import 'package:siopas/pages/transfer_peti/conn/syncronize.dart'; +import 'package:siopas/pages/transfer_peti/controller/transfer_peti_controller.dart'; +import 'package:siopas/services/syncronizeAPI.dart'; +import 'package:siopas/services/controllerApi.dart'; +import 'package:siopas/pages/peminjaman_barang/controller/peminjaman_controller.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/providers/asset_status_provider.dart'; +import 'package:http/http.dart' as http; + +import '../../connection/connection.dart'; +import '../../models/condition_peti_model.dart'; + +class TransferPetiPage extends StatefulWidget { + const TransferPetiPage({super.key}); + + @override + State createState() => TransferPetiPageState(); +} + +class TransferPetiPageState extends State { + String? token; + bool loading = true; + + // Reinit atau Upload Only + WarehouseModel? warehouseSqfliteApi; + List? typePetiSqfliteApi; + List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + DisposalPetiModel? disposalSqfliteApi; + + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valdisposal; + + // Datatable + int _currentPage = 1; + int _pageSize = 10; + List? _data; + List? _petiData; + List? _tipePetiData; + List? _customerData; + List? _warehouseData; + bool _isLoading = false; + Timer? _timer; + + @override + void initState() { + super.initState(); + _getUserToken(); + + warehouseListAPI(); + typePetiListAPI(); + customerListAPI(); + petiListAPI(); + // disposalListAPI(); + + // Tampil data Datatables + // datatablesAssetStatusList(); + datatablesTransferPetiList(); + datatablesPetiList(); + datatablesTipePetiList(); + datatablesCustomerList(); + datatablesWarehouseList(); + _data = []; + } + + void _getUserToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + token = prefs.getString('token'); + }); + } + } + + // Reinit atau Upload Only ------------------------------------------------------------------------ + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + // Future disposalListAPI() async { + // if (mounted) { + // await ControllerApi().fetchDisposalDataAPI().then((value) { + // setState(() { + // _valdisposal = (value as List) + // .map((item) => DisposalPetiModel.fromJson(item)) + // .toList(); + // loading = false; + // }); + // }); + // } + // } + + Future typePetiListAPI() async { + if (mounted) { + await ControllerApi().fetchTipePetiDataAPI().then((value) { + setState(() { + typePetiSqfliteApi = (value as List) + .map((item) => TypePetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerSqfliteApi = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + // Future reinitAssetStatusApi() async { + // List assetStatusApiData = + // await SyncronizationDataAPI().fetchAssetStatusFromApi(); + // await ControllerApi() + // .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite + // } + + Future reinitWarehouseApi() async { + EasyLoading.show(status: 'Mengambil data Warehouse...'); + List warehouseApiData = + await SyncronizationDataAPI().fetchWarehouseFromApi(); + await ControllerApi() + .deleteAllWarehouseDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllWarehouseDataAPI(warehouseApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitPetiApi() async { + EasyLoading.show(status: 'Mengambil data Peti...'); + List petiApiData = + await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() + .deleteAllPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitCustomerApi() async { + EasyLoading.show(status: 'Mengambil data Customer...'); + List customerApiData = + await SyncronizationDataAPI().fetchCustomerFromApi(); + await ControllerApi() + .deleteAllCustomerDataAPI(); // Clear existing data in SQLite + await ControllerApi() + .addAllCustomerDataAPI(customerApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + + Future reinitConditionPetiApi() async { + EasyLoading.show(status: 'Mengambil data Condition Peti...'); + List conditionPetiApiData = + await SyncronizationDataAPI().fetchKondisiPetiFromApi(); + await ControllerApi() + .deleteAllKondisiPetiDataAPI(); // Clear existing data in SQLite + await ControllerApi().addAllKondisiPetiDataAPI( + conditionPetiApiData); // Add new data to SQLite + EasyLoading.dismiss(); + } + // Future reinitDisposalApi() async { + // List disposalApiData = + // await SyncronizationDataAPI().fetchDisposalFromApi(); + // await ControllerApi() + // .deleteAllDisposalDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllDisposalDataAPI(disposalApiData); // Add new data to SQLite + // } + + Future fetchDataFromApiAndSync() async { + EasyLoading.show(status: 'Mengambil data dari Server...'); + try { + await syncToMysql(); + + // await reinitAssetStatusApi(); + await reinitWarehouseApi(); + await reinitPetiApi(); + await reinitCustomerApi(); + // await reinitTypePetiApi(); + await reinitConditionPetiApi(); + // await reinitDisposalApi(); + + // await datatablesAssetStatusList(); + await datatablesTransferPetiList(); + EasyLoading.showSuccess('Data berhasil diperbarui'); + } catch (e) { + EasyLoading.showError('Gagal memperbarui data: $e'); + } finally { + EasyLoading.dismiss(); + } + } + + Future syncToMysql() async { + await SyncronizationTransferPetiData() + .fetchAllInfoTransferPeti() + .then((transferPetiList) async { + EasyLoading.show( + status: 'Jangan tutup aplikasi. Kami sedang menyinkronkan...'); + await Future.delayed(Duration(seconds: 3)); + + // Tambahkan penanganan pengunggahan + bool uploadSuccess = await SyncronizationTransferPetiData() + .saveTransferPetiServerWith(transferPetiList); + + // Jika pengunggahan berhasil, hapus data lokal + if (uploadSuccess) { + await SyncronizationTransferPetiData().deleteAllTransferPetiData(); + // Setelah selesai, tampilkan pesan sukses + EasyLoading.showSuccess('Berhasil disinkronkan dengan Server'); + // await datatablesAssetStatusList(); + await datatablesTransferPetiList(); + } else { + // Tampilkan pesan gagal jika pengunggahan tidak berhasil + EasyLoading.showError('Gagal disinkronkan dengan Server'); + } + }); + } + + // Future syncToMysql() async { + // await SyncronizationData().fetchAllInfo().then((assetList) async { + // EasyLoading.show(status: 'Don\'t close app. We are syncing...'); + // await SyncronizationData().saveToMysqlWith(assetList); + // await SyncronizationData().deleteAllAssetStatusData(); + // // EasyLoading.showSuccess('Successfully saved to MySQL'); + // }); + // } + + Future isInteret() async { + await SyncronizationPeminjamanData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); + } else { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); + } + }); + } + + // Datatables ------------------------------------------------------------------------ + Future datatablesTransferPetiList() async { + await ControllerTransferPeti() + .fetchTransferPetiLocalController() + .then((value) { + setState(() { + _data = (value as List) + .map((e) => TransferPetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesPetiList() async { + await Controller().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesTipePetiList() async { + await Controller().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesCustomerList() async { + await Controller().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + Future datatablesWarehouseList() async { + await Controller().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + + void _loadMoreData() { + if (mounted && !_isLoading) { + setState(() { + _currentPage++; + }); + // datatablesAssetStatusList(); + datatablesTransferPetiList(); + } + } + + @override + Widget build(BuildContext context) { + // Add this function outside the build method + void showSyncDialog(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + // Dialog shape and style + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: Colors.grey[100], + elevation: 0, + + // Dialog content + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Dialog title with close button + Container( + width: double.infinity, + color: Colors.indigo[700], // Indigo background + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Sync Server Transfer Peti", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); // Close dialog + }, + ), + ], + ), + ), + + // Divider + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + + // Re-init Button + Container( + width: double.infinity, + child: TextButton( + onPressed: () { + Navigator.pop(context); // Close dialog + fetchDataFromApiAndSync(); + }, + child: Text( + "Upload + Download", + style: TextStyle( + color: Colors.black, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), + ), + ), + + // Divider + // Divider( + // height: 1, + // thickness: 1, + // color: Colors.black, // Black divider + // ), + + // Upload Only Button + // Container( + // width: double.infinity, + // child: TextButton( + // onPressed: () { + // Navigator.pop(context); // Close dialog + // syncToMysql(); + // }, + // child: Text( + // "Upload Only", + // style: TextStyle( + // color: Colors.black, + // fontSize: 16.0, + // fontFamily: 'Poppins', + // ), + // ), + // ), + // ), + ], + ), + ); + }, + ); + } + + return DefaultTabController( + length: 1, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Data Transfer Peti', + style: TextStyle( + fontSize: 16, + )), + actions: [ + IconButton( + icon: Icon(Icons.backup), + onPressed: () async { + if (await SyncronizationPeminjamanData.isInternet()) { + // Display custom dialog when the IconButton is pressed + showSyncDialog(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("No internet connection")), + ); + } + }, + ), + ], + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + ), + bottom: TabBar( + indicator: BoxDecoration(color: Color.fromARGB(255, 50, 39, 122)), + tabs: [ + Tab(text: 'Transfer Peti Hari ini'), + ], + ), + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : TabBarView( + children: [ + SingleChildScrollView( + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: PaginatedDataTable( + // header: Text('Searching'), // Removed const + rowsPerPage: _pageSize, + availableRowsPerPage: [10, 25, 50], // Removed const + onRowsPerPageChanged: (value) { + setState(() { + _pageSize = value!; + }); + }, + columns: [ + DataColumn(label: Text('No')), + DataColumn(label: Text('Kode Peti')), + DataColumn(label: Text('Customer')), + DataColumn(label: Text('Tgl Transfer')), + DataColumn(label: Text('Asal Gudang')), + DataColumn(label: Text('Tujuan Gudang')), + ], + source: _DataSourceLokal( + // data: _data!, + data: _data != null ? _data! : [], + context: context, + petiData: _petiData != null ? _petiData : [], + tipePetiData: + _tipePetiData != null ? _tipePetiData : [], + customerData: + _customerData != null ? _customerData : [], + warehouseData: + _warehouseData != null ? _warehouseData : [], + ), + ), + ), + ], + ), + ), + ], + ), + bottomNavigationBar: BottomAppBar( + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Container( + height: 65.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + customBorder: CircleBorder(), + onTap: () { + // Aksi ketika ikon diklik + Navigator.pushNamed(context, '/transfer-peti/edit'); + }, + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.greenAccent[700], + ), + child: Icon( + Icons.add, + size: 30, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +class _DataSourceLokal extends DataTableSource { + final List data; + List? petiData; + List? tipePetiData; + List? customerData; + List? warehouseData; + final BuildContext context; + + _DataSourceLokal({ + required this.data, + required this.petiData, + required this.tipePetiData, + required this.customerData, + required this.warehouseData, + required this.context, + }); + @override + DataRow? getRow(int index) { + if (index >= data.length) { + return null; + } + + data.sort((a, b) { + if (a.created_at == null && b.created_at == null) { + return 0; // Both dates are null, consider them equal + } else if (a.created_at == null) { + return 1; // Null is considered greater than non-null + } else if (b.created_at == null) { + return -1; // Non-null is considered smaller than null + } else { + return b.created_at!.compareTo(a.created_at!); // Compare non-null dates + } + }); + + final item = data[index]; + + // Menemukan data peti yang sesuai dengan asset + PetiAssetModel? petiSqfliteApi; + if (item.peti_id != null) { + petiSqfliteApi = petiData!.firstWhere( + (peti) => peti.id == item.peti_id, + orElse: () => PetiAssetModel( + id: null, + tipe_peti_id: null, + warna: 'null', + packing_no: null, + customer_id: null, + warehouse_id: null, + kondisipeti_id: null, + jumlah: null, + date_pembuatan: DateTime.now(), + created_by: 'null', + updated_by: 'null', + fix_lot: '', + ), + ); + } + + TypePetiModel? tipePetiSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.tipe_peti_id != null) { + tipePetiSqfliteApi = tipePetiData?.firstWhere( + (tipePeti) => tipePeti.id == petiSqfliteApi?.tipe_peti_id, + orElse: () => TypePetiModel( + id: null, + type: 'null', + size_peti: 'null', + description: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + CustomerModel? customerSqfliteApi; + if (petiSqfliteApi != null && petiSqfliteApi.customer_id != null) { + customerSqfliteApi = customerData?.firstWhere( + (customer) => customer.id == petiSqfliteApi?.customer_id, + orElse: () => CustomerModel( + id: null, + name: 'null', + code_customer: 'null', + lot_no: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + WarehouseModel? warehouseAsalGudangSqfliteApi; + if (item.source_warehouse != null) { + warehouseAsalGudangSqfliteApi = warehouseData?.firstWhere( + (warehouse) => warehouse.id == item.source_warehouse, + orElse: () => WarehouseModel( + id: null, + name: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + WarehouseModel? warehouseTujuanGudangSqfliteApi; + if (item.destination_warehouse != null) { + warehouseTujuanGudangSqfliteApi = warehouseData?.firstWhere( + (warehouse) => warehouse.id == item.destination_warehouse, + orElse: () => WarehouseModel( + id: null, + name: 'null', + created_by: 'null', + updated_by: 'null', + ), + ); + } + + return DataRow(cells: [ + DataCell( + Text( + (index + 1).toString(), + ), + ), + DataCell( + Text( + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + ), + ), + DataCell( + Text( + customerSqfliteApi != null && customerSqfliteApi.name != null + ? customerSqfliteApi!.name.toString() + : '-', + ), + ), + DataCell( + Text( + item.date != null ? DateFormat('dd-MM-yyyy').format(item.date!) : '-', + ), + ), + DataCell( + Text( + warehouseAsalGudangSqfliteApi != null && + warehouseAsalGudangSqfliteApi.name != null + ? warehouseAsalGudangSqfliteApi!.name.toString() + : '-', + ), + ), + DataCell( + Text( + warehouseTujuanGudangSqfliteApi != null && + warehouseTujuanGudangSqfliteApi.name != null + ? warehouseTujuanGudangSqfliteApi!.name.toString() + : '-', + ), + ), + ]); + } + + @override + bool get isRowCountApproximate => false; + + @override + int get rowCount => data.length; + + @override + int get selectedRowCount => 0; +} diff --git a/lib/pages/transfer_peti/show.dart b/lib/pages/transfer_peti/show.dart deleted file mode 100644 index 08b4e12..0000000 --- a/lib/pages/transfer_peti/show.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:siopas/connection/connection.dart'; -import 'package:http/http.dart' as http; - -class DetailTransferPetiPage extends StatefulWidget { - final int petiId; - const DetailTransferPetiPage({Key? key, required this.petiId}) - : super(key: key); - - @override - State createState() => _DetailTransferPetiPageState(); -} - -class _DetailTransferPetiPageState extends State { - Map? petiStatusData; - String _formatDate(String date) { - DateTime parsedDate = DateTime.parse(date); - String formattedDate = - DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); - return formattedDate; - } - - @override - void initState() { - super.initState(); - _fetchAssetStatusDataPengembalian(); - } - - Future _fetchAssetStatusDataPengembalian() async { - try { - final response = await http.get( - Uri.parse('$baseUrl/peti-asset/show/${widget.petiId}'), - headers: { - 'Content-Type': 'application/json', - }, - ); - - if (response.statusCode == 200) { - setState(() { - petiStatusData = json.decode(response.body)['data']['peti']; - }); - } else { - throw Exception('Failed to load data'); - } - } catch (e) { - print('Error fetching data: $e'); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.grey[200], - appBar: AppBar( - backgroundColor: Colors.indigo[700], - elevation: 0, - title: Text('Detail Peti', - style: TextStyle( - color: Colors.white, - fontSize: 16, - )), - leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushNamed(context, '/transfer-peti'); - }, - ), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), - elevation: 5, - child: Column( - children: [ - Card( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.vertical(top: Radius.circular(15.0)), - ), - elevation: 0, - margin: EdgeInsets.all(0), - color: Colors.indigo[700], - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - children: [ - Icon(Icons.article, - size: 40, - color: Colors.white), // Ganti ikon sesuai kebutuhan - SizedBox(width: 10), - Text( - 'ID: ${widget.petiId}', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - ), - SizedBox(height: 10), - if (petiStatusData != null) ...[ - _buildDetailItem( - 'Tipe Peti', - petiStatusData!['tipe_peti']['type'], - ), - Divider(thickness: 1), - _buildDetailItem( - 'Warna Peti', - petiStatusData!['warna'] != null - ? petiStatusData!['warna'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Customer', - petiStatusData!['customer']['name'] != null - ? petiStatusData!['customer']['name'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Warehouse', - petiStatusData!['warehouse']['name'] != null - ? petiStatusData!['warehouse']['name'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Status Peti', - petiStatusData!['status_disposal'] != null - ? petiStatusData!['status_disposal'].toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Jumlah Peti', - petiStatusData!['jumlah'] != null - ? petiStatusData!['jumlah'].toString() - : '-', - ), - Divider(thickness: 1), - _buildDetailItem( - 'Tgl Pembuatan Peti', - petiStatusData!['created_at'] != null - ? _formatDate(petiStatusData!['created_at']) - : '-'), - ], - ], - ), - ), - ), - ); - } - - Widget _buildDetailItem(String label, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.bold), - ), - Text(value), - ], - ), - ); - } -} diff --git a/lib/pages/transfer_peti/transfer_peti_index.dart b/lib/pages/transfer_peti/transfer_peti_index.dart deleted file mode 100644 index f083edf..0000000 --- a/lib/pages/transfer_peti/transfer_peti_index.dart +++ /dev/null @@ -1,287 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; - -import 'package:flutter/material.dart'; -import 'package:data_table_2/data_table_2.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:siopas/models/asset_status_model.dart'; -import 'package:siopas/models/m_asset_status_model.dart'; -import 'package:siopas/pages/pengembalian_barang/show.dart'; -import 'package:siopas/pages/transfer_peti/show.dart'; -import 'package:siopas/providers/asset_status_provider.dart'; -import 'package:http/http.dart' as http; - -import '../../connection/connection.dart'; -import '../peminjaman_barang/show.dart'; - -class TransferPetiPage extends StatefulWidget { - const TransferPetiPage({super.key}); - - @override - State createState() => TransferPetiPageState(); -} - -class TransferPetiPageState extends State { - String? token; - int _currentPage = 1; - int _pageSize = 10; - List _data = []; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - _getUserToken(); - fetchData(); - } - - void _getUserToken() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - if (mounted) { - setState(() { - token = prefs.getString('token'); - }); - } - } - - Future fetchData() async { - if (mounted) { - setState(() { - _isLoading = true; - }); - - try { - final response = await http.get(Uri.parse('$baseUrl/peti-asset')); - - if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['petis']; - - final List newData = (jsonData as List) - .map((item) => PetiAssetModel.fromJson(item)) - .toList(); - - if (mounted) { - setState(() { - _data.addAll(newData); - _isLoading = false; - }); - } - } else { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - throw Exception('Failed to fetch data'); - } - } catch (e) { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - print('Error fetching data: $e'); - } - } - } - - void _loadMoreData() { - if (mounted && !_isLoading) { - setState(() { - _currentPage++; - }); - fetchData(); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.indigo[700], - elevation: 0, - title: Text('Data Peti (Transfer Peti)', - style: TextStyle( - fontSize: 16, - )), - leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushNamed(context, '/home'); - }, - ), - ), - body: _isLoading - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - child: SizedBox( - width: double.infinity, - child: PaginatedDataTable( - header: const Text('Menu Peti'), - rowsPerPage: _pageSize, - availableRowsPerPage: const [10, 25, 50], - onRowsPerPageChanged: (value) { - setState(() { - _pageSize = value!; - }); - }, - columns: const [ - DataColumn(label: Text('No')), - DataColumn(label: Text('')), - DataColumn(label: Text('Customer')), - DataColumn(label: Text('Gudang')), - DataColumn(label: Text('Fix Lot')), - DataColumn(label: Text('Tipe Peti')), - DataColumn(label: Text('Ukuran Peti')), - DataColumn(label: Text('Lot No')), - DataColumn(label: Text('Status Peti')), - DataColumn(label: Text('Packing No')), - ], - source: _DataSource(data: _data, context: context), - ), - ), - ), - bottomNavigationBar: BottomAppBar( - color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang - child: Container( - height: 65.0, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - customBorder: CircleBorder(), - onTap: () { - // Aksi ketika ikon diklik - Navigator.pushNamed(context, '/transfer-peti/edit'); - }, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.yellow[800], - ), - child: Icon( - Icons.local_shipping, - size: 30, - color: Colors.white, - ), - ), - ), - ], - ), - ), - ), - ); - } -} - -class _DataSource extends DataTableSource { - final List data; - final BuildContext context; - - _DataSource({required this.data, required this.context}); - @override - DataRow? getRow(int index) { - if (index >= data.length) { - return null; - } - - final item = data[index]; - - return DataRow(cells: [ - DataCell( - Text( - (index + 1).toString(), - ), - ), - DataCell( - GestureDetector( - onTap: () { - if (item.id != null) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => DetailTransferPetiPage( - petiId: item.id!, - ), - ), - ); - - print('asset id: ${item.id}'); - } - }, - child: Icon( - Icons.article_outlined, - size: 30, - color: Colors.indigo[700], - ), - ), - ), - DataCell( - Text( - item.customer!.name!.toString() != 'null' - ? item.customer!.name.toString() - : '-', - ), - ), - DataCell( - Text( - item.warehouse!.name!.toString() != 'null' - ? item.warehouse!.name.toString() - : '-', - ), - ), - DataCell( - Text( - item.fix_lot.toString() != 'null' ? item.fix_lot.toString() : '-', - ), - ), - DataCell( - Text( - item.tipe_peti!.type.toString() != 'null' - ? item.tipe_peti!.type.toString() - : '-', - ), - ), - DataCell( - Text(item.tipe_peti!.size_peti.toString() != 'null' - ? item.tipe_peti!.size_peti.toString() - : '-'), - ), - DataCell( - Text( - item.customer!.lot_no.toString() != 'null' - ? item.customer!.lot_no.toString() - : '-', - ), - ), - DataCell( - Text( - item.status_disposal.toString() != 'null' - ? item.status_disposal.toString() - : '-', - ), - ), - DataCell( - Text( - item.packing_no.toString() != 'null' - ? item.packing_no.toString() - : '-', - ), - ), - ]); - } - - @override - bool get isRowCountApproximate => false; - - @override - int get rowCount => data.length; - - @override - int get selectedRowCount => 0; -} diff --git a/lib/services/asset_status_service.dart b/lib/services/asset_status_service.dart index 3096ce7..e83be4a 100644 --- a/lib/services/asset_status_service.dart +++ b/lib/services/asset_status_service.dart @@ -12,7 +12,7 @@ import '../models/asset_status_model.dart'; class AssetStatusService { Future> getAssetStatus() async { // var url = Uri.parse('$baseUrl/products'); - var url = Uri.parse("$baseUrl/asset-status"); + var url = Uri.parse(await getBaseUrl() + "/asset-status"); var headers = {'Content-Type': 'application/json'}; var response = await http.get(url, headers: headers); @@ -43,7 +43,7 @@ class AssetStatusService { // int? exit_warehouse, String? token, }) async { - var url = Uri.parse('$baseUrl/asset-status/store'); + var url = Uri.parse(await getBaseUrl() + 'asset-status/store'); var headers = { 'Content-Type': 'application/json', 'Authorization': token!, diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 3c5b6d2..78044c3 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'dart:async'; -import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../connection/connection.dart'; @@ -8,7 +7,7 @@ import '../models/user_model.dart'; class AuthService { Future getUserInfoFromServer(String token) async { - var url = Uri.parse('$baseUrl/user'); + var url = Uri.parse(await getBaseUrl() + '/user'); var headers = { 'Content-Type': 'application/json', 'Authorization': token, @@ -30,7 +29,7 @@ class AuthService { String? email, String? password, }) async { - var url = Uri.parse('$baseUrl/register'); + var url = Uri.parse(await getBaseUrl() + '/register'); var headers = {'Content-Type': 'application/json'}; var body = jsonEncode({ 'name': name, @@ -59,7 +58,7 @@ class AuthService { String? email, String? password, }) async { - var url = Uri.parse('$baseUrl/login'); + var url = Uri.parse(await getBaseUrl() + '/login'); var headers = {'Content-Type': 'application/json'}; var body = jsonEncode({ 'email': email, @@ -85,7 +84,7 @@ class AuthService { return user; } else { - throw Exception('Gagal Login'); + throw Exception('Failed to login'); } } @@ -96,7 +95,7 @@ class AuthService { FutureOr logout(String token) async { try { - var url = Uri.parse('$baseUrl/logout'); + var url = Uri.parse(await getBaseUrl() + '/logout'); var headers = { 'Content-Type': 'application/json', 'Authorization': token, @@ -130,7 +129,7 @@ class AuthService { String? token, }) async { try { - var url = Uri.parse('$baseUrl/user'); + var url = Uri.parse(await getBaseUrl() + '/user'); var headers = { 'Content-Type': 'application/json', 'Authorization': token!, diff --git a/lib/services/controllerApi.dart b/lib/services/controllerApi.dart new file mode 100644 index 0000000..8dea81e --- /dev/null +++ b/lib/services/controllerApi.dart @@ -0,0 +1,372 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/disposal_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:http/http.dart' as http; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import 'package:sqflite/sqflite.dart'; + +import '../migrations/databasehelper.dart'; +import '../models/condition_peti_model.dart'; +import '../models/type_peti_model.dart'; + +class ControllerApi { + final conn = SqfliteDatabaseHelper.instance; + + static Future isInternetApi() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.mobile) { + if (await InternetConnectionChecker().hasConnection) { + print("Mobile data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else if (connectivityResult == ConnectivityResult.wifi) { + if (await InternetConnectionChecker().hasConnection) { + print("wifi data detected & internet connection confirmed."); + return true; + } else { + print('No internet :( Reason:'); + return false; + } + } else { + print( + "Neither mobile data or WIFI detected, not internet connection found."); + return false; + } + } + +// Asset Status ------------------------------------------------------------------------------------------------------------------ + + Future fetchAssetStatusLocalControllerApi() async { + var dbclient = await conn.db; + List assetStatusApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.asset_statusesTable, orderBy: 'id DESC'); + for (var item in maps) { + assetStatusApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return assetStatusApiList; + } + + Future deleteAllAssetStatusDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.asset_statusesTable); + } + + Future addAllAssetStatusDataAPI( + List assetStatusListApi) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var assetStatus in assetStatusListApi) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.asset_statusesTable, + assetStatus.toJson(), + ); + } + + await batch.commit(); + } +// End Asset Status ------------------------------------------------------------------------------------------------------------------ + +// Peti ------------------------------------------------------------------------------------------------------------------ + Future fetchPetiDataAPI() async { + var dbclient = await conn.db; + List petiApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.petiTable, orderBy: 'id DESC'); + for (var item in maps) { + petiApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return petiApiList; + } + + Future deleteAllPetiDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.petiTable); + } + + Future addAllPetiDataAPI(List petiListApi) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var peti in petiListApi) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.petiTable, + peti.toJson(), + ); + } + + await batch.commit(); + } + // End Peti ------------------------------------------------------------------------------------------------------------------ + +// Warehouse ------------------------------------------------------------------------------------------------------------------ + Future fetchWarehouseDataAPI() async { + var dbclient = await conn.db; + List warehouseApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.warehouseTable, orderBy: 'id DESC'); + for (var item in maps) { + warehouseApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return warehouseApiList; + } + + Future deleteAllWarehouseDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.warehouseTable); + } + + Future addAllWarehouseDataAPI( + List warehouseListApi) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var warehouse in warehouseListApi) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.warehouseTable, + warehouse.toJson(), + ); + } + + await batch.commit(); + } +// End Warehouse ------------------------------------------------------------------------------------------------------------------ + +// Customer ------------------------------------------------------------------------------------------------------------------ + Future fetchCustomerDataAPI() async { + var dbclient = await conn.db; + List customerApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.customerTable, orderBy: 'id DESC'); + for (var item in maps) { + customerApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return customerApiList; + } + + Future deleteAllCustomerDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.customerTable); + } + + Future addAllCustomerDataAPI( + List customerApiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var customer in customerApiList) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.customerTable, + customer.toJson(), + ); + } + + await batch.commit(); + } +// End Customer ------------------------------------------------------------------------------------------------------------------ + +// Tipe Peti ------------------------------------------------------------------------------------------------------------------ + Future fetchTipePetiDataAPI() async { + var dbclient = await conn.db; + List tipePetiApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.typePetiTable, orderBy: 'id DESC'); + for (var item in maps) { + tipePetiApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return tipePetiApiList; + } + + Future deleteAllTipePetiDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.typePetiTable); + } + + Future addAllTipePetiDataAPI( + List tipePetiApiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var tipePeti in tipePetiApiList) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.typePetiTable, + tipePeti.toJson(), + ); + } + + await batch.commit(); + } +// End Tipe Peti ------------------------------------------------------------------------------------------------------------------ + +// Tipe Kondisi ------------------------------------------------------------------------------------------------------------------ + // Future fetchKondisiPetiDataAPI() async { + // var dbclient = await conn.db; + // List kondisiPetiApiList = []; + // try { + // // Ensure that the table name is correct + // List> maps = await dbclient! + // .query(SqfliteDatabaseHelper.conditionPetiTable, orderBy: 'id DESC'); + // for (var item in maps) { + // kondisiPetiApiList.add(item); + // } + // } catch (e) { + // print('Error fetching data from SQLite: $e'); + // } + // return kondisiPetiApiList; + // } + + Future fetchKondisiPetiDataAPI() async { + var dbclient = await conn.db; + List conditionApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.conditionPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + conditionApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return conditionApiList; + } + + Future deleteAllKondisiPetiDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.conditionPetiTable); + } + + Future addAllKondisiPetiDataAPI( + List kondisiPetiApiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var kondisiPeti in kondisiPetiApiList) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.conditionPetiTable, + kondisiPeti.toJson(), + ); + } + + await batch.commit(); + } +// End Kondisi Peti ------------------------------------------------------------------------------------------------------------------ + +// Transfer Kondisi ------------------------------------------------------------------------------------------------------------------ + Future fetchTransferPetiDataAPI() async { + var dbclient = await conn.db; + List transferPetiApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.transferPetiTable, orderBy: 'id DESC'); + for (var item in maps) { + transferPetiApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return transferPetiApiList; + } + + Future deleteAllTransferPetiDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); + } + + Future addAllTransferPetiDataAPI( + List transferPetiApiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var transferPeti in transferPetiApiList) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.transferPetiTable, + transferPeti.toJson(), + ); + } + + await batch.commit(); + } +// End Transfer Peti ------------------------------------------------------------------------------------------------------------------ + +// Disposal ------------------------------------------------------------------------------------------------------------------ + Future fetchDisposalDataAPI() async { + var dbclient = await conn.db; + List disposalApiList = []; + try { + // Ensure that the table name is correct + List> maps = await dbclient! + .query(SqfliteDatabaseHelper.disposalTable, orderBy: 'id DESC'); + for (var item in maps) { + disposalApiList.add(item); + } + } catch (e) { + print('Error fetching data from SQLite: $e'); + } + return disposalApiList; + } + + Future deleteAllDisposalDataAPI() async { + var dbClient = await conn.db; + await dbClient!.delete(SqfliteDatabaseHelper.disposalTable); + } + + Future addAllDisposalDataAPI( + List disposalApiList) async { + var dbclient = await conn.db; + Batch batch = dbclient!.batch(); + + for (var disposal in disposalApiList) { + // Ensure that toJson() correctly converts the model to a map + batch.insert( + SqfliteDatabaseHelper.disposalTable, + disposal.toJson(), + ); + } + + await batch.commit(); + } +// End Disposal ------------------------------------------------------------------------------------------------------------------ +} diff --git a/lib/services/m_status_service.dart b/lib/services/m_status_service.dart index eb45143..117edc8 100644 --- a/lib/services/m_status_service.dart +++ b/lib/services/m_status_service.dart @@ -8,7 +8,7 @@ import 'dart:async'; class M_assetStatusService { Future> getAssetStatus() async { - var url = Uri.parse("$baseUrl/m-status"); + var url = Uri.parse("${await getBaseUrl()}/m-status"); var headers = {'Content-Type': 'application/json'}; var response = await http.get(url, headers: headers); diff --git a/lib/services/syncronizeAPI.dart b/lib/services/syncronizeAPI.dart new file mode 100644 index 0000000..89ae02f --- /dev/null +++ b/lib/services/syncronizeAPI.dart @@ -0,0 +1,224 @@ +import 'dart:convert'; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:siopas/connection/connection.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/condition_peti_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:siopas/models/type_peti_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:internet_connection_checker/internet_connection_checker.dart'; +import '../migrations/databasehelper.dart'; +import 'package:http/http.dart' as http; + +import '../models/disposal_model.dart'; +import '../models/m_asset_status_model.dart'; + +class SyncronizationDataAPI { + final conn = SqfliteDatabaseHelper.instance; + + Future> fetchAssetStatusFromApi() async { + final apiURL = '${await getBaseUrl()}/asset-status'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['asset_status']; + print('Success Fetch Data API Asset Status'); + List assetStatusApiList = data + .map( + (item) => AssetStatusModel.fromJson(item as Map)) + .toList(); + + return assetStatusApiList; + } else { + throw Exception('Failed to fetch data from API Peti'); + } + } + + Future> fetchPetiFromApi() async { + final apiURL = '${await getBaseUrl()}/peti-asset'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['petis']; + print('Success Fetch Data Peti'); + List petiDBList = data + .map((item) => PetiAssetModel.fromJson(item as Map)) + .toList(); + + return petiDBList; + } else { + throw Exception('Failed to fetch data from API Peti'); + } + } + + // Future> fetchPetiFromApi() async { + // final apiURL = 'http://192.168.0.18:8000/api/v1/peti-asset'; + + // final response = await http.get(Uri.parse(apiURL)); + + // if (response.statusCode == 200) { + // List data = json.decode(response.body)['data']['petis']; + // print('Success Fetch Data Peti'); + + // List petiList = data.map((item) { + // // Extracting and transforming data from JSON + // String id = item['id'].toString(); + // String tipePetiId = item['tipe_peti_id'].toString(); + // String warna = item['warna'].toString(); + // int? packingNo = item['packing_no'] != null + // ? int.parse(item['packing_no'].toString()) + // : null; + // String customerID = item['customer_id'].toString(); + // String warehouseID = item['warehouse_id'].toString(); + // String kondisiPetiID = item['kondisipeti_id'].toString(); + // int? jumlah = item['jumlah'] != null + // ? int.parse(item['jumlah'].toString()) + // : null; + // DateTime datePembuatan = DateTime.parse(item['date_pembuatan']); + + // // Creating an instance of PetiAssetModel + // PetiAssetModel peti = PetiAssetModel( + // id: id, + // tipe_peti_id: tipePetiId, + // warna: warna, + // packing_no: packingNo, + // customer_id: customerID, + // warehouse_id: warehouseID, + // kondisipeti_id: kondisiPetiID, + // jumlah: jumlah, + // date_pembuatan: datePembuatan, + // created_by: + // item['created_by'] != null ? item['created_by'].toString() : null, + // updated_by: + // item['updated_by'] != null ? item['updated_by'].toString() : null, + // ); + + // return peti; + // }).toList(); + + // return petiList; + // } else { + // throw Exception('Failed to fetch data from API Peti'); + // } + // } + + Future> fetchWarehouseFromApi() async { + final apiURL = '${await getBaseUrl()}/m-warehouse'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['warehouse']; + print('Success Fetch Data Warehouse'); + + List warehouseDBList = data + .map((item) => WarehouseModel.fromJson(item as Map)) + .toList(); + + return warehouseDBList; + } else { + throw Exception('Failed to fetch data from API Warehouse'); + } + } + + Future> fetchCustomerFromApi() async { + final apiURL = '${await getBaseUrl()}/m-customer'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['customers']; + print('Success Fetch Data Customer'); + + List customerDBList = data + .map((item) => CustomerModel.fromJson(item as Map)) + .toList(); + + return customerDBList; + } else { + throw Exception('Failed to fetch data from API Customer'); + } + } + + Future> fetchTipePetiFromApi() async { + final apiURL = '${await getBaseUrl()}/m-type-peti'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['tipe_peti']; + print('Success Fetch Data Tipe Peti'); + + List tipePetiDBList = data + .map((item) => TypePetiModel.fromJson(item as Map)) + .toList(); + + return tipePetiDBList; + } else { + throw Exception('Failed to fetch data from API Tipe Peti'); + } + } + + Future> fetchKondisiPetiFromApi() async { + final apiURL = '${await getBaseUrl()}/m-kondisi-peti'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['kondisi_peti']; + print('Success Fetch Data Master Kondisi Peti'); + + List kondisiPetiDBList = data + .map((item) => + ConditionPetiModel.fromJson(item as Map)) + .toList(); + + return kondisiPetiDBList; + } else { + throw Exception('Failed to fetch data from API Master Kondisi Peti'); + } + } + + Future> fetchTransferPetiFromApi() async { + final apiURL = '${await getBaseUrl()}/m-transfer-peti'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['transfer_peti']; + print('Success Fetch Data Transfer Peti'); + + List transferPetiDBList = data + .map((item) => + TransferPetiModel.fromJson(item as Map)) + .toList(); + + return transferPetiDBList; + } else { + throw Exception('Failed to fetch data from API Transfer Peti'); + } + } + + Future> fetchDisposalFromApi() async { + final apiURL = '${await getBaseUrl()}/m-disposal-peti'; + + final response = await http.get(Uri.parse(apiURL)); + + if (response.statusCode == 200) { + List data = json.decode(response.body)['data']['disposals']; + print('Success Fetch Data Disposal Peti'); + + List disposalPetiDBList = data + .map((item) => + DisposalPetiModel.fromJson(item as Map)) + .toList(); + + return disposalPetiDBList; + } else { + throw Exception('Failed to fetch data from API Disposal Peti'); + } + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index eefcc6d..4008a7f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,11 +5,13 @@ import FlutterMacOS import Foundation +import connectivity_plus import path_provider_foundation import shared_preferences_foundation import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) diff --git a/pubspec.lock b/pubspec.lock index 676a4d5..c268714 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" + url: "https://pub.dev" + source: hosted + version: "3.4.9" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -49,6 +65,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" clock: dependency: transitive description: @@ -65,6 +97,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.2" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: "224a77051d52a11fbad53dd57827594d3bd24f945af28bd70bab376d68d437f0" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" + source: hosted + version: "1.2.4" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" crypto: dependency: transitive description: @@ -89,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" fake_async: dependency: transitive description: @@ -126,6 +190,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.1" + flutter_easyloading: + dependency: "direct main" + description: + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c + url: "https://pub.dev" + source: hosted + version: "3.0.5" flutter_form_builder: dependency: "direct main" description: @@ -134,14 +206,22 @@ packages: url: "https://pub.dev" source: hosted version: "9.1.1" - flutter_lints: - dependency: "direct dev" + flutter_launcher_icons: + dependency: "direct main" description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "0.13.1" + flutter_spinkit: + dependency: transitive + description: + name: flutter_spinkit + sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + url: "https://pub.dev" + source: hosted + version: "5.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -176,6 +256,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + url: "https://pub.dev" + source: hosted + version: "4.1.3" + internet_connection_checker: + dependency: "direct main" + description: + name: internet_connection_checker + sha256: "1c683e63e89c9ac66a40748b1b20889fd9804980da732bf2b58d6d5456c8e876" + url: "https://pub.dev" + source: hosted + version: "1.0.0+1" intl: dependency: "direct main" description: @@ -192,14 +288,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - lints: + json_annotation: dependency: transitive description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "4.8.1" matcher: dependency: transitive description: @@ -232,6 +328,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" octo_image: dependency: transitive description: @@ -249,7 +353,7 @@ packages: source: hosted version: "1.8.3" path_provider: - dependency: transitive + dependency: "direct main" description: name: path_provider sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa @@ -296,6 +400,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" platform: dependency: transitive description: @@ -312,6 +424,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.6" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" provider: dependency: "direct main" description: @@ -430,7 +550,7 @@ packages: source: hosted version: "7.0.0" sqflite: - dependency: transitive + dependency: "direct main" description: name: sqflite sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" @@ -502,13 +622,13 @@ packages: source: hosted version: "1.3.2" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid - sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7 + sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.2.1" vector_math: dependency: transitive description: @@ -541,6 +661,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.1.3 <4.0.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 59747a1..407448f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: siopas -description: A new Flutter project. +description: Apps Siopas ISTW. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev @@ -45,13 +45,27 @@ dependencies: qr_code_scanner: ^1.0.1 data_table_2: ^2.5.8 flutter_form_builder: ^9.1.1 - # dropdown_button2: ^2.3.9 + uuid: ^4.2.1 + path_provider: ^2.1.1 + connectivity_plus: ^5.0.1 + internet_connection_checker: ^1.0.0+1 + flutter_easyloading: ^3.0.5 + sqflite: ^2.3.0 + flutter_launcher_icons: ^0.13.1 dev_dependencies: flutter_test: sdk: flutter +flutter_launcher_icons: + android: true + ios: true + image_path: "assets/img/siopas_apps.png" + adaptive_icon_background: "#ffffff" + adaptive_icon_foreground: "assets/img/siopas_apps.png" + adaptive_icon_mask: "assets/img/siopas_apps.png" + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..8777c93 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..cc1361d 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + connectivity_plus ) list(APPEND FLUTTER_FFI_PLUGIN_LIST