Files
tripz-llc/apps/driver/lib/controller/home/payment/captain_wallet_controller.dart
T
2026-08-11 00:11:23 +03:00

485 lines
17 KiB
Dart
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'package:tripz_driver/constant/style.dart';
import 'package:tripz_driver/controller/firebase/local_notification.dart';
import 'package:tripz_driver/views/widgets/elevated_btn.dart';
import 'package:tripz_driver/views/widgets/error_snakbar.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tripz_driver/constant/box_name.dart';
import 'package:tripz_driver/constant/links.dart';
import 'package:tripz_driver/controller/functions/crud.dart';
import 'package:tripz_driver/main.dart';
import 'package:tripz_driver/print.dart';
import 'package:tripz_driver/views/widgets/mycircular.dart';
import '../../../views/home/my_wallet/payment_screen_mtn.dart';
import '../../../views/home/my_wallet/payment_screen_cliq.dart';
class CaptainWalletController extends GetxController {
bool isLoading = false;
final formKeyTransfer = GlobalKey<FormState>();
final formKeyAccount = GlobalKey<FormState>();
Map walletDate = {};
Map walletDateVisa = {};
Map walletDriverPointsDate = {};
final formKey = GlobalKey<FormState>();
String totalAmount = '0';
double kazan = 0;
String totalAmountVisa = '0';
String totalPoints = '0';
final amountFromBudgetController = TextEditingController();
final newDriverPhoneController = TextEditingController();
final phoneWallet = TextEditingController();
final cardBank = TextEditingController();
final bankCode = TextEditingController();
double get transferFee {
String country = box.read(BoxName.countryCode) ?? 'Jordan';
if (country == 'Egypt') return 5.0;
if (country == 'Syria') return 10.0;
if (country == 'Jordan') return 0.25;
return 5.0;
}
double get minTransferAmount {
String country = box.read(BoxName.countryCode) ?? 'Jordan';
if (country == 'Egypt') return 10.0;
if (country == 'Syria') return 100.0;
if (country == 'Jordan') return 1.0;
return 10.0;
}
payFromBudget() async {
if (formKey.currentState!.validate()) {
var pointFromBudget = int.parse((amountFromBudgetController.text));
Get.dialog(const Center(child: MyCircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD()
.postWallet(link: AppLink.convertBudgetToPoints, payload: {
'amount': pointFromBudget.toString(),
'driverID': box.read(BoxName.driverID).toString(),
});
Get.back(); // close loading
if (res != 'failure') {
late Map<String, dynamic> mapRes;
if (res is String) {
mapRes = json.decode(res);
} else {
mapRes = res;
}
if (mapRes['status'] == 'success') {
update();
Get.back();
await refreshCaptainWallet();
NotificationController().showNotification(
'You have successfully charged your account'.tr,
'$pointFromBudget ${'has been added to your budget'.tr}',
'tone1',
'',
);
} else {
mySnackbarError(mapRes['message']?.toString() ?? 'Error');
}
} else {
mySnackbarError('Error processing request'.tr);
}
}
}
Future refreshCaptainWallet() async {
// ═══════════════════════════════════════════════════════════════
// ‏isLoading كان يُطفأ في نهاية الدالة الثانية فقط. أي استثناء قبلها
// ‏— وأشهره سائق بلا أي دفعات، إذ يعود message = [] فيرمي فهرسه
// ‏[0] خطأ نطاق — كان يترك الشاشة تدور بلا نهاية بلا رسالة.
// ‏finally يضمن إطفاءه مهما حدث.
// ═══════════════════════════════════════════════════════════════
isLoading = true;
update();
try {
await getCaptainWalletFromRide();
await getCaptainWalletFromBuyPoints();
// await checkAccountCaptainBank();
} catch (e) {
Log.print('❌ refreshCaptainWallet: $e');
mySnackbarError('Connection problem, please try again'.tr);
} finally {
isLoading = false;
update();
}
}
/// ‏يقرأ رقماً من ردّ المحفظة بأمان: الردّ قد يكون خريطة بلا `message`،
/// ‏أو قائمة فارغة (سائق جديد بلا دفعات) — وكلاهما كان يُسقط الشاشة.
static String _readWalletNumber(dynamic decoded, String key) {
if (decoded is! Map) return '0';
final message = decoded['message'];
if (message is! List || message.isEmpty) return '0';
final first = message.first;
if (first is! Map) return '0';
return first[key]?.toString() ?? '0';
}
List amountToNewDriverMap = [];
bool isNewTransfer = false;
Future detectNewDriverFromMyBudget() async {
if (formKeyTransfer.currentState!.validate()) {
if (int.parse(amountFromBudgetController.text) <
double.parse(totalAmountVisa) &&
int.parse(amountFromBudgetController.text) > 10) {
//get new driver details
isNewTransfer = true;
update();
var res = await CRUD().get(
link: AppLink.getDriverDetails,
payload: {'driver_phone': '+2${newDriverPhoneController.text}'});
isNewTransfer = false;
update();
if (res != 'failure') {
var d = jsonDecode(res);
amountToNewDriverMap = d['data'];
// update();
} else {
mySnackbarError("This driver is not registered".tr);
}
} else {
mySnackbarError('Your Budget less than needed'.tr);
}
}
}
Future getCaptainWalletFromRide() async {
var res = await CRUD().getWallet(
link: AppLink.getAllPaymentFromRide,
payload: {'driverID': box.read(BoxName.driverID).toString()},
);
if (res != 'failure') {
final decoded = jsonDecode(res);
walletDate = decoded is Map ? decoded : {};
totalAmount = _readWalletNumber(decoded, 'total_amount');
update();
var res1 = await CRUD().getWallet(
link: AppLink.getAllPaymentVisa,
payload: {'driverID': box.read(BoxName.driverID).toString()});
if (res1 != 'failure') {
final decodedVisa = jsonDecode(res1);
walletDateVisa = decodedVisa is Map ? decodedVisa : {};
totalAmountVisa = _readWalletNumber(decodedVisa, 'diff');
} else {
totalAmountVisa = '0';
}
update();
} else {
totalAmount = "0";
totalAmountVisa = "0";
}
}
Future getCaptainWalletFromBuyPoints() async {
var res = await CRUD().getWallet(
link: AppLink.getDriverPaymentPoints,
payload: {'driverID': box.read(BoxName.driverID).toString()},
);
if (res != 'failure') {
final decoded = jsonDecode(res);
walletDriverPointsDate = decoded is Map ? decoded : {};
final raw = _readWalletNumber(decoded, 'total_amount');
totalPoints = (double.tryParse(raw) ?? 0).toStringAsFixed(0);
} else {
totalPoints = '0';
}
update();
}
String paymentToken = '';
Future<String> generateToken(String amount) async {
var res =
await CRUD().postWallet(link: AppLink.addPaymentTokenDriver, payload: {
'driverID': box.read(BoxName.driverID).toString(),
'amount': amount.toString(),
});
var d = (res);
return d['message'];
}
// late String paymentID;
Future<String> getPaymentId(String paymentMethod, amount) async {
// paymentToken = await generateToken(amount);
var res =
await CRUD().postWallet(link: AppLink.addDriverPaymentPoints, payload: {
'driverID': box.read(BoxName.driverID).toString(),
'amount': amount.toString(),
'payment_method': paymentMethod.toString(),
});
var d = (res);
// paymentID = d['message'].toString();
return d['message'];
}
Future addDriverWallet(String paymentMethod, point, count) async {
paymentToken = await generateToken(count);
var paymentID = await getPaymentId(paymentMethod, point.toString());
await CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'driverID': box.read(BoxName.driverID).toString(),
'paymentID': paymentID.toString(),
'amount': point,
'token': paymentToken,
'paymentMethod': paymentMethod.toString(),
});
}
Future addDriverPayment(String paymentMethod, point, wayPay) async {
paymentToken = await generateToken(point);
var paymentID = await getPaymentId(paymentMethod, point.toString());
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'amount': point.toString(),
'rideId': paymentID.toString(),
'payment_method': paymentMethod,
'passengerID': wayPay,
'token': paymentToken,
'driverID': box.read(BoxName.driverID).toString(),
});
}
Future addDriverWalletFromPromo(String paymentMethod, point) async {
var resPromotion =
await CRUD().postWallet(link: AppLink.addpromotionDriver, payload: {
'driver_id': box.read(BoxName.driverID).toString(),
'payment_amount': point,
'timePromo': paymentMethod,
});
if (resPromotion != 'failure') {
paymentToken = await generateToken(point);
var paymentID = await getPaymentId(paymentMethod, point.toString());
var res =
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'amount': point,
'rideId': paymentID.toString(),
'payment_method': paymentMethod.toString(),
'passengerID': paymentMethod,
'token': paymentToken,
'driverID': box.read(BoxName.driverID).toString(),
});
if (res != 'failure') {
String title = 'wallet_updated'.tr; // Notification title
String message = '${'wallet_credited_message'.tr} $point';
String tone = 'default_tone'.tr; // Notification tone or sound
String payLoad =
'wallet_updated'; // Additional data payload for the notification
Get.find<NotificationController>()
.showNotification(title, message, tone, payLoad);
}
} else {
Get.back();
mySnackbarError(
"A promotion record for this driver already exists for today.".tr);
}
}
Future addDriverWalletToInvitor(String paymentMethod, driverID, point) async {
paymentToken = await generateToken(point);
var paymentID = await getPaymentId(paymentMethod, point.toString());
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'driverID': driverID,
'amount': point,
'token': paymentToken,
'rideId': paymentID.toString(),
'payment_method': paymentMethod.toString(),
'passengerID': paymentMethod,
});
await addSeferWallet(paymentMethod,
(double.parse(point) * -2).toString()); // deduct 2 from sefer wallet
}
Future addSeferWallet(String paymentMethod, String point) async {
var seferToken = await generateToken(point.toString());
await CRUD().postWallet(link: AppLink.addSeferWallet, payload: {
'amount': point.toString(),
'paymentMethod': paymentMethod,
'passengerId': 'driver',
'token': seferToken,
'driverId': box.read(BoxName.driverID).toString(),
});
}
Future addTransferDriversWallet(String paymentMethod1, paymentMethod2) async {
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res =
await CRUD().postWallet(link: AppLink.transferWalletDriver, payload: {
'amount': amountFromBudgetController.text,
'receiverPhone': amountToNewDriverMap[0]['phone'].toString(),
'country': box.read(BoxName.countryCode) ?? 'Egypt',
'driverID': box.read(BoxName.driverID).toString(),
});
Get.back();
if (res != 'failure') {
late Map<String, dynamic> mapRes;
if (res is String) {
mapRes = json.decode(res);
} else {
mapRes = res;
}
if (mapRes['status'] == 'success') {
Get.defaultDialog(
title: 'transfer Successful'.tr,
middleText: '',
titleStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'Ok'.tr,
onPressed: () async {
Get.back();
Get.back();
await refreshCaptainWallet();
}));
} else {
mySnackbarError(mapRes['message']?.toString() ?? 'Error');
}
} else {
mySnackbarError('Error processing request'.tr);
}
}
getKazanPercent() async {
var res = await CRUD().get(
link: AppLink.getKazanPercent,
payload: {'country': box.read(BoxName.countryCode).toString()},
);
if (res != 'failure') {
var json = jsonDecode(res);
kazan = double.parse(json['message'][0]['kazan'].toString());
// naturePrice = double.parse(json['message'][0]['naturePrice']);
// heavyPrice = double.parse(json['message'][0]['heavyPrice']);
// latePrice = double.parse(json['message'][0]['latePrice']);
// comfortPrice = double.parse(json['message'][0]['comfortPrice']);
// speedPrice = double.parse(json['message'][0]['speedPrice']);
// deliveryPrice = double.parse(json['message'][0]['deliveryPrice']);
// mashwariPrice = double.parse(json['message'][0]['freePrice']);
// fuelPrice = double.parse(json['message'][0]['fuelPrice']);
}
update();
}
@override
void onInit() async {
// getKazanPercent();
await refreshCaptainWallet();
super.onInit();
}
Future<void> payWithMTNWallet(
BuildContext context, String amount, String currency) async {
try {
final phone = phoneWallet.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(
title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createMtnInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.driverID).toString(),
"user_type": "driver",
"mtn_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenMtn(
invoiceNumber: resMap['invoice_number'],
mtnNumber: resMap['mtn_payment_number'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(
resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
Future<void> payWithClickWallet(
BuildContext context, String amount, String currency) async {
try {
final phone = phoneWallet.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(
title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createCliqInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.driverID).toString(),
"user_type": "driver",
"click_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenCliq(
invoiceNumber: resMap['invoice_number'],
cliqAlias: resMap['cliq_alias'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(
resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
}