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
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,
|
|
});
|
|
}
|