FD/TD/RD integrated

This commit is contained in:
2026-03-23 16:41:05 +05:30
parent fc495eca09
commit 4e39cb8493
6 changed files with 482 additions and 33 deletions

View File

@@ -0,0 +1,175 @@
import 'dart:developer';
import 'package:dio/dio.dart';
class DepositService{
final Dio _dio;
DepositService(this._dio);
Future<dynamic> fetchaccountdetails({
required String accountno,
}) async {
try {
final response = await _dio.post(
"/api/deposit/req/deposit",
data: {
'accountNo': accountno,
},
options: Options(
headers: {
"Content-Type": "application/json",
},
),
);
log("PMY Details Response: ${response.data}");
if (response.statusCode == 200) {
return response.data;
} else {
throw Exception("INTERNAL SERVER ERROR");
}
} catch (e) {
log("Error fetching Account details: $e");
return null;
}
}
Future createFdTd({
String? fromacctno,
String? cifNo,
String? idno,
String? customername,
String? nationality,
String? addressline1,
String? addressline2,
String? pincode,
String? product,
String? type,
String? customercategory,
String? termlocation,
String? currency,
String? acctsgmtcode,
String? interestpaymentmethod,
String? taxfilenumberindicator,
String? termlenght,
String? termbasis,
String? termvaluedeposited,
String? interestfrequency,
String? termdays,
String? termmonths,
String? termyears,
String? nominationRequired,
String? printNomineename,
required String tpin,
}) async {
final response = await _dio.post(
'/api/deposit/create/fd-td',
options: Options(
validateStatus: (int? status) => true,
receiveDataWhenStatusError: true,
),
data: {
"fromacctno": fromacctno,
"cifNo": cifNo,
"idno": idno,
"customername": customername,
"nationality": nationality,
"addressline1": addressline1,
"addressline2": addressline2,
"pincode": pincode,
"product": product,
"type": type,
"customercategory": customercategory,
"termlocation": termlocation,
"currency": currency,
"acctsgmtcode": acctsgmtcode,
"interestpaymentmethod": interestpaymentmethod,
"taxfilenumberindicator": taxfilenumberindicator,
"termlenght": termlenght,
"termbasis": termbasis,
"termvaluedeposited": termvaluedeposited,
"interestfrequency": interestfrequency,
"termdays": termdays,
"termmonths": termmonths,
"termyears": termyears,
"nominationRequired": nominationRequired,
"printNomineename": printNomineename,
'tpin': tpin,
},
);
return response.data;
}
Future createRd({
String? fromacctno,
String? cifNo,
String? idno,
String? customername,
String? nationality,
String? addressline1,
String? addressline2,
String? pincode,
String? product,
String? type,
String? customercategory,
String? termlocation,
String? currency,
String? acctsgmtcode,
String? interestpaymentmethod,
String? taxfilenumberindicator,
String? termlenght,
String? termbasis,
String? termvaluedeposited,
String? interestfrequency,
String? termdays,
String? termmonths,
String? termyears,
String? nominationRequired,
String? printNomineename,
String? rdinstallmentvalue,
String? monthlyRDInstallmentdueday,
String? rdInstlFreq,
required String tpin,
}) async {
final response = await _dio.post(
'/api/deposit/create/rd',
options: Options(
validateStatus: (int? status) => true,
receiveDataWhenStatusError: true,
),
data: {
"fromacctno": fromacctno,
"cifNo": cifNo,
"idno": idno,
"customername": customername,
"nationality": nationality,
"addressline1": addressline1,
"addressline2": addressline2,
"pincode": pincode,
"product": product,
"type": type,
"customercategory": customercategory,
"termlocation": termlocation,
"currency": currency,
"acctsgmtcode": acctsgmtcode,
"interestpaymentmethod": interestpaymentmethod,
"taxfilenumberindicator": taxfilenumberindicator,
"termlenght": termlenght,
"termbasis": termbasis,
"termvaluedeposited": termvaluedeposited,
"interestfrequency": interestfrequency,
"termdays": termdays,
"termmonths": termmonths,
"termyears": termyears,
"nominationRequired": nominationRequired,
"printNomineename": printNomineename,
"rdinstallmentvalue": rdinstallmentvalue,
"monthlyRDInstallmentdueday": monthlyRDInstallmentdueday,
"rdInstlFreq": rdInstlFreq,
'tpin': tpin,
},
);
return response.data;
}
}

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/branch_service.dart'; import 'package:kmobile/api/services/branch_service.dart';
import 'package:kmobile/api/services/cheque_service.dart'; import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/api/services/deposit_service.dart';
import 'package:kmobile/api/services/limit_service.dart'; import 'package:kmobile/api/services/limit_service.dart';
import 'package:kmobile/api/services/rtgs_service.dart'; import 'package:kmobile/api/services/rtgs_service.dart';
import 'package:kmobile/api/services/neft_service.dart'; import 'package:kmobile/api/services/neft_service.dart';
@@ -60,6 +61,7 @@ Future<void> setupDependencies() async {
getIt.registerSingleton<BranchService>(BranchService(getIt<Dio>())); getIt.registerSingleton<BranchService>(BranchService(getIt<Dio>()));
getIt.registerSingleton<ChequeService>(ChequeService(getIt<Dio>())); getIt.registerSingleton<ChequeService>(ChequeService(getIt<Dio>()));
getIt.registerSingleton<YojnaService>(YojnaService(getIt<Dio>())); getIt.registerSingleton<YojnaService>(YojnaService(getIt<Dio>()));
getIt.registerSingleton<DepositService>(DepositService(getIt<Dio>()));
getIt.registerLazySingleton<ChangePasswordService>( getIt.registerLazySingleton<ChangePasswordService>(
() => ChangePasswordService(getIt<Dio>()), () => ChangePasswordService(getIt<Dio>()),
); );

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/deposit_service.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart';
import 'package:kmobile/l10n/app_localizations.dart'; import 'package:kmobile/l10n/app_localizations.dart';
import 'package:kmobile/features/account_opening/screens/create_deposit_screen.dart'; import 'package:kmobile/features/account_opening/screens/create_deposit_screen.dart';
@@ -117,27 +119,51 @@ class _AccountOpeningScreenState extends State<AccountOpeningScreen> {
: () async { : () async {
if (_formKey.currentState!.validate() && if (_formKey.currentState!.validate() &&
_selectedAccount != null) { _selectedAccount != null) {
// Simulating API response setState(() {
final mockResponse = { _isLoading = true;
"addressline1": "DATA CENTRE KCCB CIVIL BAZAR D/SHALA DHA", });
"addressline2": "RAMSHALA KANGRA",
"cifNo": "30022497139",
"customername": "Mr. RAJAT KUMAR MAHARANA",
"idno": "536652226333 61",
"nationality": "IN",
"pincode": "176047"
};
try {
final response = await getIt<DepositService>()
.fetchaccountdetails(
accountno:
_selectedAccount!.accountNo.toString());
if (response != null) {
if (mounted) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => CreateDepositScreen( builder: (context) => CreateDepositScreen(
selectedAccount: _selectedAccount!, selectedAccount: _selectedAccount!,
initialData: mockResponse, initialData: response,
), ),
), ),
); );
} }
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
"Failed to fetch account details")),
);
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error: $e")),
);
}
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor:

View File

@@ -1,5 +1,9 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/deposit_service.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart'; import 'package:kmobile/l10n/app_localizations.dart';
class CreateDepositScreen extends StatefulWidget { class CreateDepositScreen extends StatefulWidget {
@@ -17,6 +21,7 @@ class CreateDepositScreen extends StatefulWidget {
class _CreateDepositScreenState extends State<CreateDepositScreen> { class _CreateDepositScreenState extends State<CreateDepositScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
// Controllers // Controllers
late final _fromAcctNoController = late final _fromAcctNoController =
@@ -171,13 +176,245 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
void _handleCreate() { void _handleCreate() {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// Implementation logic goes here Navigator.push(
ScaffoldMessenger.of(context).showSnackBar( context,
const SnackBar(content: Text("Processing Deposit Creation...")), MaterialPageRoute(
builder: (context) => TransactionPinScreen(
onPinCompleted: (ctx, pin) async {
Navigator.pop(context);
_executeCreation(pin);
},
),
),
); );
} }
} }
void _executeCreation(String pin) async {
setState(() {
_isLoading = true;
});
try {
final product = _productController.text;
dynamic response;
if (product == '20' || product == '25') {
response = await getIt<DepositService>().createFdTd(
fromacctno: _fromAcctNoController.text,
cifNo: _cifNoController.text,
idno: _idNoController.text,
customername: _customerNameController.text,
nationality: _nationalityController.text,
addressline1: _addressLine1Controller.text,
addressline2: _addressLine2Controller.text,
pincode: _pincodeController.text,
product: _productController.text,
type: _typeController.text,
customercategory: _customerCategoryController.text,
termlocation: _termLocationController.text,
currency: _currencyController.text,
acctsgmtcode: _acctSgmtCodeController.text,
interestpaymentmethod: _interestPaymentMethodController.text,
taxfilenumberindicator: _taxFileNumberIndicatorController.text,
termlenght: _termLengthController.text,
termbasis: _termBasisController.text,
termvaluedeposited: _termValueDepositedController.text,
interestfrequency: _interestFrequencyController.text,
termdays: _termDaysController.text,
termmonths: _termMonthsController.text,
termyears: _termYearsController.text,
nominationRequired: _nominationRequiredController.text,
printNomineename: _printNomineeNameController.text,
tpin: pin,
);
} else if (product == '28') {
response = await getIt<DepositService>().createRd(
fromacctno: _fromAcctNoController.text,
cifNo: _cifNoController.text,
idno: _idNoController.text,
customername: _customerNameController.text,
nationality: _nationalityController.text,
addressline1: _addressLine1Controller.text,
addressline2: _addressLine2Controller.text,
pincode: _pincodeController.text,
product: _productController.text,
type: _typeController.text,
customercategory: _customerCategoryController.text,
termlocation: _termLocationController.text,
currency: _currencyController.text,
acctsgmtcode: _acctSgmtCodeController.text,
interestpaymentmethod: _interestPaymentMethodController.text,
taxfilenumberindicator: _taxFileNumberIndicatorController.text,
termlenght: _termLengthController.text,
termbasis: _termBasisController.text,
termvaluedeposited: _termValueDepositedController.text,
interestfrequency: _interestFrequencyController.text,
termdays: _termDaysController.text,
termmonths: _termMonthsController.text,
termyears: _termYearsController.text,
nominationRequired: _nominationRequiredController.text,
printNomineename: _printNomineeNameController.text,
rdinstallmentvalue: _rdInstallmentValueController.text,
monthlyRDInstallmentdueday: _monthlyRDInstallmentDueDayController.text,
rdInstlFreq: _rdInstlFreqController.text,
tpin: pin,
);
}
if (response != null && response is Map<String, dynamic>) {
if (mounted) {
if (response['error'] == 'INCORRECT_TPIN' || response['message'] == 'INCORRECT_TPIN') {
_showSimpleDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.');
} else if (response['status'] == 'FAILED') {
_showFailureDialog(response['message']?.toString());
} else if (response.containsKey('accountno')) {
_showResponseDialog(response);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Unexpected response from server")),
);
}
}
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Failed to create deposit")),
);
}
}
} on DioException catch (e) {
if (mounted) {
try {
final errorBody = e.response?.data;
if (errorBody is Map && (errorBody['error'] == 'INCORRECT_TPIN' || errorBody['message'] == 'INCORRECT_TPIN')) {
_showSimpleDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.');
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error: ${e.message}")),
);
}
} catch (_) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Internal Server Error")),
);
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error: $e")),
);
}
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
Future<void> _showSimpleDialog(String title, String message) async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(title),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(message),
],
),
),
actions: <Widget>[
TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _showFailureDialog(String? apiMessage) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Row(
children: [
Icon(Icons.error_outline, color: Theme.of(context).colorScheme.error),
const SizedBox(width: 8),
const Text("Creation Failed"),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Account creation could not be completed at this time.",
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
if (apiMessage != null) ...[
Text("Reason: $apiMessage"),
const SizedBox(height: 12),
],
const Text(
"Please ensure that the provided details (term length, basis, interest frequency, etc.) are correct and compatible with the selected product. If the issue persists, please contact the branch.",
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("OK"),
),
],
),
);
}
void _showResponseDialog(Map<String, dynamic> response) {
final accountNo = response['accountno']?.toString() ?? 'N/A';
final accountTypeRaw = response['accounttype']?.toString() ?? '';
final accountTypeText = _productOptions[accountTypeRaw] ?? accountTypeRaw;
final amount = response['amount']?.toString() ?? '0.0';
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Text("Deposit Created Successfully"),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Account No: $accountNo"),
const SizedBox(height: 8),
Text("Account Type: $accountTypeText"),
const SizedBox(height: 8),
Text("Amount: $amount"),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).popUntil((route) => route.isFirst);
},
child: const Text("OK"),
),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context); final l10n = AppLocalizations.of(context);
@@ -280,7 +517,8 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
mandatory: true), mandatory: true),
_buildTextField(_termValueDepositedController, _buildTextField(_termValueDepositedController,
"Term Value Deposited", "Term Value Deposited",
keyboardType: TextInputType.number, mandatory: true), keyboardType: TextInputType.number,
mandatory: _productController.text != '28'),
_buildDropdownField(_interestFrequencyController, _buildDropdownField(_interestFrequencyController,
"Interest Frequency", _interestFrequencyOptions), "Interest Frequency", _interestFrequencyOptions),
_buildTextField(_termDaysController, "Term Days", _buildTextField(_termDaysController, "Term Days",
@@ -327,7 +565,7 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
const SizedBox(height: 24), const SizedBox(height: 24),
ElevatedButton( ElevatedButton(
onPressed: _handleCreate, onPressed: _isLoading ? null : _handleCreate,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor:
Theme.of(context).colorScheme.primaryContainer, Theme.of(context).colorScheme.primaryContainer,
@@ -339,7 +577,15 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
child: const Text( child: _isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
: const Text(
"Proceed", "Proceed",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
), ),
@@ -364,7 +610,7 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
padding: const EdgeInsets.only(bottom: 16.0), padding: const EdgeInsets.only(bottom: 16.0),
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
value: currentValue, value: currentValue,
onChanged: readOnly onChanged: readOnly || _isLoading
? null ? null
: (newValue) { : (newValue) {
if (newValue != null) { if (newValue != null) {
@@ -407,8 +653,8 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
padding: const EdgeInsets.only(bottom: 16.0), padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField( child: TextFormField(
controller: controller, controller: controller,
readOnly: readOnly || onTap != null, readOnly: readOnly || onTap != null || _isLoading,
onTap: onTap, onTap: _isLoading ? null : onTap,
decoration: InputDecoration( decoration: InputDecoration(
labelText: mandatory ? '$label *' : label, labelText: mandatory ? '$label *' : label,
border: const OutlineInputBorder(), border: const OutlineInputBorder(),

View File

@@ -36,7 +36,7 @@
"accountStatement": "Account \n Statement", "accountStatement": "Account \n Statement",
"handleCheque": "Handle \n Cheque", "handleCheque": "Handle \n Cheque",
"manageBeneficiary": "Manage \n Beneficiary", "manageBeneficiary": "Manage \n Beneficiary",
"contactUs": "Contact \n Us", "contactUs": "Contact Us",
"addBeneficiary": "Add Beneficiary", "addBeneficiary": "Add Beneficiary",
"confirmAccountNumber": "Confirm Account Number", "confirmAccountNumber": "Confirm Account Number",
"name": "Name", "name": "Name",

View File

@@ -36,7 +36,7 @@
"accountStatement": "खाता \n विवरण", "accountStatement": "खाता \n विवरण",
"handleCheque": "चेक \n संभालें", "handleCheque": "चेक \n संभालें",
"manageBeneficiary": "लाभार्थी \n प्रबंधन", "manageBeneficiary": "लाभार्थी \n प्रबंधन",
"contactUs": "संपर्क \n करें", "contactUs": "संपर्क करें",
"addBeneficiary": "लाभार्थी जोड़ें", "addBeneficiary": "लाभार्थी जोड़ें",
"confirmAccountNumber": "खाता संख्या की पुष्टि करें", "confirmAccountNumber": "खाता संख्या की पुष्टि करें",
"name": "नाम", "name": "नाम",