You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
9.2 KiB

import 'dart:convert';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:bookatanker/common/settings.dart';
import 'package:bookatanker/supplier/paymnets/credit_accounts_details.dart';
class CreditAccountsScreen extends StatefulWidget {
const CreditAccountsScreen({super.key});
@override
State<CreditAccountsScreen> createState() => _CreditAccountsScreenState();
}
class _CreditAccountsScreenState extends State<CreditAccountsScreen> {
bool isLoading = true;
List<Supplier> suppliers = [];
Razorpay? _razorpay;
Supplier? _currentPaySupplier;
@override
void initState() {
super.initState();
fetchCreditAccounts();
_razorpay = Razorpay();
_razorpay?.on(
Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay?.on(
Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay?.on(
Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
}
@override
void dispose() {
_razorpay?.clear();
_razorpay = null;
super.dispose();
}
// ================= FETCH CREDIT ACCOUNTS =================
Future<void> fetchCreditAccounts() async {
try {
final response =
await AppSettings.getAdvanceTransactionsByCustomer();
final decoded = jsonDecode(response);
final List data = decoded["data"] ?? [];
final List<Supplier> list = data.map<Supplier>((e) {
final status = (e["status"] ?? "").toString().toLowerCase();
final amount =
double.tryParse(e["advance_amount"].toString()) ?? 0;
double balance = 0;
if (status == "approved") balance = amount;
if (status == "pending") {
balance = -amount;
}
if (status == "completed") {
balance = amount;
}
if (status == "paid_by_customer") balance = amount;
return Supplier(
name: e["supplierName"] ?? "Supplier",
supplierId:e["supplierId"] ?? "***",
monthlyAmount: amount,
balance: balance,
status: status,
raw: e,
);
}).toList();
setState(() {
suppliers = list;
isLoading = false;
});
} catch (e) {
setState(() => isLoading = false);
}
}
// ================= RAZORPAY =================
void _openRazorpay(Supplier supplier) {
_currentPaySupplier = supplier;
var options = {
'key': 'rzp_test_1VCCWqEXUHdINz', // 🔑 replace in prod
'amount': (supplier.monthlyAmount * 100).toInt(),
'name': 'Advance Payment',
'description': 'Water Credit Top Up',
/*'prefill': {
'contact': AppSettings.userMobile,
'email': AppSettings.userEmail,
}*/
};
try {
_razorpay?.open(options);
} catch (e) {
debugPrint("Razorpay error: $e");
}
}
Future<void> _handlePaymentSuccess(
PaymentSuccessResponse response) async {
if (_currentPaySupplier == null) return;
AppSettings.preLoaderDialog(context);
final success = await AppSettings.payAdvance(
transactionId:
_currentPaySupplier!.raw["transactionId"],
payload: {
"advance_amount": _currentPaySupplier!.monthlyAmount,
"payment_type": "razorpay",
"ref_number": response.paymentId,
},
);
Navigator.of(context, rootNavigator: true).pop();
if (success) {
AppSettings.longSuccessToast("Payment successful");
fetchCreditAccounts();
} else {
AppSettings.longFailedToast("Payment failed");
}
_currentPaySupplier = null;
}
void _handlePaymentError(
PaymentFailureResponse response) {
AppSettings.longFailedToast("Payment failed");
}
void _handleExternalWallet(
ExternalWalletResponse response) {}
// ================= UI =================
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0XFFFFFFFF),
appBar: AppSettings.supplierAppBarWithoutActions(
"Credit Accounts", context),
body: Padding(
padding: const EdgeInsets.all(16),
child: isLoading
? const Center(child: CircularProgressIndicator())
: ListView(
children: [
_addSupplierCard(),
const SizedBox(height: 20),
...suppliers.map(_supplierCard).toList(),
],
),
),
);
}
Widget _addSupplierCard() {
return InkWell(
onTap: () {},
child: Row(
children: [
DottedBorder(
borderType: BorderType.Circle,
dashPattern: const [6, 3],
color: const Color(0XFF444444),
strokeWidth: 1,
child: Container(
width: 48,
height: 48,
alignment: Alignment.center,
child: Image.asset(
'images/plus.png',
width: 24,
height: 24,
color: const Color(0XFF444444),
),
),
),
const SizedBox(width: 12),
Text(
"Add Supplier",
style: fontTextStyle(
12, const Color(0XFF232527), FontWeight.w600),
),
],
),
);
}
Widget _supplierCard(Supplier supplier) {
return GestureDetector(
onTap: () {
if (supplier.status == "pending" ||
supplier.status == "paid_by_customer") {
return; // 🚫 no navigation
}
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
CreditAccountsDetails(details: supplier),
),
);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
children: [
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: const Color(0xFFE8F2FF),
borderRadius: BorderRadius.circular(28),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(28),
child: Image.asset("images/profile_user.png"),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
supplier.supplierId,
style: fontTextStyle(
12, const Color(0XFF232527), FontWeight.w600),
),
/* RichText(
text: TextSpan(children: [
TextSpan(
text:
"₹${supplier.monthlyAmount.toStringAsFixed(0)} ",
style: fontTextStyle(
10,
const Color(0xFF515253),
FontWeight.w400),
),
TextSpan(
text: "/month",
style: fontTextStyle(
10,
const Color(0xFF939495),
FontWeight.w400),
),
]),
),*/
// ===== STATUS MESSAGES =====
if (supplier.status == "pending")
Padding(
padding: const EdgeInsets.only(top: 4),
child: InkWell(
onTap: () => _openRazorpay(supplier),
child: Text(
"Please top up",
style: fontTextStyle(
10,
const Color(0XFFE2483D),
FontWeight.w600),
),
),
),
if (supplier.status == "paid_by_customer")
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
"Confirmation needed from supplier",
style: fontTextStyle(
10,
const Color(0XFF939495),
FontWeight.w600),
),
),
],
),
),
Text(
"${AppSettings.formDouble(supplier.balance.toStringAsFixed(2))}",
style: fontTextStyle(
16,
supplier.balance < 0
? const Color(0XFFE2483D)
: const Color(0XFF0A9E04),
FontWeight.w600,
),
),
],
),
),
);
}
}
// ================= MODEL =================
class Supplier {
final String name;
final double monthlyAmount;
final double balance;
final String status;
final String supplierId;
final Map<String, dynamic> raw;
Supplier({
required this.name,
required this.monthlyAmount,
required this.balance,
required this.status,
required this.supplierId,
required this.raw,
});
}