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

@@ -1,5 +1,9 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:kmobile/api/services/deposit_service.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';
class CreateDepositScreen extends StatefulWidget {
@@ -17,6 +21,7 @@ class CreateDepositScreen extends StatefulWidget {
class _CreateDepositScreenState extends State<CreateDepositScreen> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
// Controllers
late final _fromAcctNoController =
@@ -171,13 +176,245 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
void _handleCreate() {
if (_formKey.currentState!.validate()) {
// Implementation logic goes here
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Processing Deposit Creation...")),
Navigator.push(
context,
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
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
@@ -280,7 +517,8 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
mandatory: true),
_buildTextField(_termValueDepositedController,
"Term Value Deposited",
keyboardType: TextInputType.number, mandatory: true),
keyboardType: TextInputType.number,
mandatory: _productController.text != '28'),
_buildDropdownField(_interestFrequencyController,
"Interest Frequency", _interestFrequencyOptions),
_buildTextField(_termDaysController, "Term Days",
@@ -327,7 +565,7 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
const SizedBox(height: 24),
ElevatedButton(
onPressed: _handleCreate,
onPressed: _isLoading ? null : _handleCreate,
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.primaryContainer,
@@ -339,10 +577,18 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
"Proceed",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
child: _isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
: const Text(
"Proceed",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 32),
],
@@ -364,7 +610,7 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
padding: const EdgeInsets.only(bottom: 16.0),
child: DropdownButtonFormField<String>(
value: currentValue,
onChanged: readOnly
onChanged: readOnly || _isLoading
? null
: (newValue) {
if (newValue != null) {
@@ -407,8 +653,8 @@ class _CreateDepositScreenState extends State<CreateDepositScreen> {
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
readOnly: readOnly || onTap != null,
onTap: onTap,
readOnly: readOnly || onTap != null || _isLoading,
onTap: _isLoading ? null : onTap,
decoration: InputDecoration(
labelText: mandatory ? '$label *' : label,
border: const OutlineInputBorder(),