update saving product code
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from http.client import HTTPConnection, HTTPException
|
||||
from pathlib import Path
|
||||
import traceback
|
||||
from contextlib import closing
|
||||
from typing import Optional
|
||||
|
||||
WEBSERVER_HOST = "localhost"
|
||||
WEBSERVER_ENDPOINT = "/api/provenance/call"
|
||||
PORT_FILE_SUFFIX = "-provenance-port.txt"
|
||||
|
||||
class ProvenanceHookError(RuntimeError):
|
||||
pass
|
||||
|
||||
def http_request(method, host, port, location, *, body: Optional[bytes] = None, headers={}, timeout=None) -> bytes:
|
||||
with closing(HTTPConnection(host, port, timeout=timeout)) as connection:
|
||||
connection.request(method, location, body=body, headers=headers)
|
||||
|
||||
def get_server_port():
|
||||
claude_root = os.getenv("CLAUDE_PROJECT_DIR")
|
||||
path_hash = hashlib.md5(claude_root.encode('utf-8')).hexdigest()
|
||||
port_file = Path(tempfile.gettempdir()) / (path_hash + PORT_FILE_SUFFIX)
|
||||
|
||||
return int(port_file.read_text("utf-8").strip())
|
||||
|
||||
|
||||
def send_diff_to_webserver(file_path, timestamp_ms):
|
||||
try:
|
||||
port = get_server_port()
|
||||
except FileNotFoundError as e:
|
||||
raise ProvenanceHookError(
|
||||
f"Could not determine API port: {e.filename} does not exist") from e
|
||||
except Exception as e:
|
||||
raise ProvenanceHookError("Could not determine API port") from e
|
||||
|
||||
url = f"http://{WEBSERVER_HOST}:{port}{WEBSERVER_ENDPOINT}"
|
||||
|
||||
try:
|
||||
payload = {"file_path": file_path, "timestamp": timestamp_ms}
|
||||
return http_request(
|
||||
"POST",
|
||||
WEBSERVER_HOST,
|
||||
port=port,
|
||||
location=WEBSERVER_ENDPOINT,
|
||||
body=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
|
||||
headers={'Content-Type': 'application/json'},
|
||||
timeout=0.5
|
||||
)
|
||||
|
||||
except (HTTPException, OSError, ConnectionError) as e:
|
||||
raise ProvenanceHookError(
|
||||
f"Network error while sending diff to {url}") from e
|
||||
except Exception as e:
|
||||
raise ProvenanceHookError(
|
||||
f"Unknown error while sending diff to {url}") from e
|
||||
|
||||
|
||||
def extract_file_path(tool_name, tool_input):
|
||||
if tool_name in ["Write", "Edit", "MultiEdit"]:
|
||||
return tool_input.get('file_path', 'unknown')
|
||||
if tool_name == "NotebookEdit":
|
||||
return tool_input.get('notebook_path', 'unknown')
|
||||
return 'unknown'
|
||||
|
||||
|
||||
def excepthook(type, value, traceback_):
|
||||
traceback.print_exception(type, value, traceback_, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
data = json.load(sys.stdin)
|
||||
tool_name = data.get('tool_name', 'unknown')
|
||||
|
||||
modification_tools = [
|
||||
"Write", "Edit", "MultiEdit", "NotebookEdit"
|
||||
]
|
||||
|
||||
if tool_name in modification_tools:
|
||||
tool_input = data.get('tool_input', {})
|
||||
file_path = extract_file_path(tool_name, tool_input)
|
||||
if file_path:
|
||||
timestamp_ms = int(datetime.now(timezone.utc).timestamp() * 1000)
|
||||
send_diff_to_webserver(file_path, timestamp_ms)
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.excepthook = excepthook
|
||||
sys.exit(main())
|
||||
@@ -41,5 +41,18 @@
|
||||
"additionalDirectories": [
|
||||
"c:\\Users\\adity\\Music\\CBS\\cfcfrms-bank-api"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Write|Edit|MultiEdit|NotebookEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python3 \"%CLAUDE_PROJECT_DIR%/.claude/hooks/post-tool-call.py\""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(type *)",
|
||||
"mcp__idea__get_symbol_info",
|
||||
"Bash(gradlew *)",
|
||||
"Bash(select-string *)",
|
||||
"Bash(select-object *)",
|
||||
"Bash(dir *)",
|
||||
"Bash(findstr *)",
|
||||
"Bash(./gradlew *)",
|
||||
"Bash(gradlew.bat *)",
|
||||
"Bash(taskkill *)",
|
||||
"Bash(timeout *)",
|
||||
"Bash(.\\gradlew.bat *)",
|
||||
"Bash(get-content *)",
|
||||
"Bash(tasklist)",
|
||||
"Bash(curl *)",
|
||||
"Bash(netstat *)",
|
||||
"Bash(curl.exe *)",
|
||||
"Bash(rmdir *)",
|
||||
"mcp__idea__build_project",
|
||||
"Bash(.\\gradlew *)",
|
||||
"Bash(.\\clean_build.bat)",
|
||||
"mcp__idea__find_files_by_name_keyword",
|
||||
"mcp__idea__search_in_files_by_text",
|
||||
"mcp__idea__get_file_text_by_path",
|
||||
"mcp__idea__search_in_files_by_regex",
|
||||
"Bash(powershell *)"
|
||||
]
|
||||
},
|
||||
"$version": 3
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(type *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
# SavingsProduct Custom Fields - Implementation Summary
|
||||
|
||||
## ✅ Completed Changes
|
||||
|
||||
### 1. **Validator Updates**
|
||||
**File:** `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java`
|
||||
|
||||
**Changes:**
|
||||
- Added `balanceFrequency` to `SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS` whitelist
|
||||
- Added `accountClosedZeroBalanceInDayClosing` to `SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS` whitelist
|
||||
|
||||
### 2. **API Constants**
|
||||
**File:** `fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java`
|
||||
|
||||
**Changes:**
|
||||
```java
|
||||
public static final String balanceFrequencyParamName = "balanceFrequency";
|
||||
public static final String accountClosedZeroBalanceInDayClosingParamName = "accountClosedZeroBalanceInDayClosing";
|
||||
```
|
||||
|
||||
### 3. **Entity (Domain Model)**
|
||||
**File:** `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java`
|
||||
|
||||
**Changes:**
|
||||
- Added field: `@Column(name = "balance_frequency", length = 50) private String balanceFrequency;`
|
||||
- Added field: `@Column(name = "account_closed_zero_balance_in_day_closing") private Boolean accountClosedZeroBalanceInDayClosing = false;`
|
||||
- Added getters: `getBalanceFrequency()`, `getAccountClosedZeroBalanceInDayClosing()`
|
||||
- Added setters: `setBalanceFrequency()`, `setAccountClosedZeroBalanceInDayClosing()`
|
||||
- Added update logic in `update()` method to handle changes to these fields
|
||||
|
||||
### 4. **Assembler**
|
||||
**File:** `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java`
|
||||
|
||||
**Changes:**
|
||||
```java
|
||||
if (command.parameterExists("balanceFrequency")) {
|
||||
product.setBalanceFrequency(command.stringValueOfParameterNamed("balanceFrequency"));
|
||||
}
|
||||
if (command.parameterExists("accountClosedZeroBalanceInDayClosing")) {
|
||||
product.setAccountClosedZeroBalanceInDayClosing(command.booleanObjectValueOfParameterNamed("accountClosedZeroBalanceInDayClosing"));
|
||||
}
|
||||
```
|
||||
|
||||
### 5. **DTO (Data Transfer Object)**
|
||||
**File:** `fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java`
|
||||
|
||||
**Changes:**
|
||||
```java
|
||||
@Getter @Setter private String balanceFrequency;
|
||||
@Getter @Setter private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
```
|
||||
|
||||
### 6. **Read Platform Service**
|
||||
**File:** `fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java`
|
||||
|
||||
**Changes:**
|
||||
- SQL Query: Added `sp.balance_frequency as balanceFrequency`
|
||||
- SQL Query: Added `sp.account_closed_zero_balance_in_day_closing as accountClosedZeroBalanceInDayClosing`
|
||||
- ResultSet mapping: Added extraction of both fields
|
||||
|
||||
### 7. **Database Migration**
|
||||
**File:** `database_migration_add_custom_fields.sql`
|
||||
|
||||
```sql
|
||||
ALTER TABLE m_savings_product
|
||||
ADD COLUMN balance_frequency VARCHAR(50) DEFAULT NULL,
|
||||
ADD COLUMN account_closed_zero_balance_in_day_closing BOOLEAN DEFAULT FALSE;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 What These Fields Do
|
||||
|
||||
### **balanceFrequency** (String)
|
||||
- **Purpose:** Defines how often balance is calculated/checked
|
||||
- **Example Values:** "Daily", "Monthly", "Quarterly", "Yearly"
|
||||
- **Database Column:** `m_savings_product.balance_frequency`
|
||||
- **Type:** VARCHAR(50)
|
||||
|
||||
### **accountClosedZeroBalanceInDayClosing** (Boolean)
|
||||
- **Purpose:** Flag to automatically close accounts when balance reaches zero at day end
|
||||
- **Example Values:** `true` or `false`
|
||||
- **Default:** `false`
|
||||
- **Database Column:** `m_savings_product.account_closed_zero_balance_in_day_closing`
|
||||
- **Type:** BOOLEAN
|
||||
|
||||
---
|
||||
|
||||
## 🎯 API Usage
|
||||
|
||||
### **POST /v1/savingsproducts** (Create)
|
||||
```json
|
||||
{
|
||||
"name": "Saving Product",
|
||||
"shortName": "SD22",
|
||||
// ... other fields ...
|
||||
"balanceFrequency": "Monthly",
|
||||
"accountClosedZeroBalanceInDayClosing": true,
|
||||
// ... rest of fields ...
|
||||
}
|
||||
```
|
||||
|
||||
### **GET /v1/savingsproducts/{productId}** (Read)
|
||||
Response will include:
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Saving Product",
|
||||
// ... other fields ...
|
||||
"balanceFrequency": "Monthly",
|
||||
"accountClosedZeroBalanceInDayClosing": true,
|
||||
// ... rest of fields ...
|
||||
}
|
||||
```
|
||||
|
||||
### **PUT /v1/savingsproducts/{productId}** (Update)
|
||||
```json
|
||||
{
|
||||
"balanceFrequency": "Quarterly",
|
||||
"accountClosedZeroBalanceInDayClosing": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Database Migration Steps
|
||||
|
||||
Run this SQL script to add the columns:
|
||||
|
||||
```bash
|
||||
mysql -u root -p your_database < database_migration_add_custom_fields.sql
|
||||
```
|
||||
|
||||
Or manually execute:
|
||||
```sql
|
||||
ALTER TABLE m_savings_product
|
||||
ADD COLUMN balance_frequency VARCHAR(50) DEFAULT NULL,
|
||||
ADD COLUMN account_closed_zero_balance_in_day_closing BOOLEAN DEFAULT FALSE;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Validation
|
||||
|
||||
The fields are now:
|
||||
- ✅ **Accepted** in CREATE request (POST)
|
||||
- ✅ **Saved** to database
|
||||
- ✅ **Returned** in GET response
|
||||
- ✅ **Updatable** via PUT request
|
||||
- ✅ **Validated** (no longer rejected as unsupported)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. **Run Database Migration:** Execute the SQL script
|
||||
2. **Rebuild Application:** `./gradlew clean build`
|
||||
3. **Restart Server:** Apply the changes
|
||||
4. **Test API:** Use your payload to create a savings product
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
- Both fields are **optional** (nullable)
|
||||
- `balanceFrequency` accepts any string value (you can add validation later if needed)
|
||||
- `accountClosedZeroBalanceInDayClosing` defaults to `false` if not provided
|
||||
- Both fields support **partial updates** (you can update just one of them)
|
||||
@@ -0,0 +1,668 @@
|
||||
# Savings Product Payload Implementation Guide
|
||||
|
||||
## Overview
|
||||
Your UI has been updated to send a comprehensive new payload with additional fields for the `/savingsproducts` POST endpoint. This document outlines **all changes required** in the backend to support these new fields.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 New Fields in Your Payload
|
||||
|
||||
### **Simple Fields (Direct Columns in m_savings_product table)**
|
||||
| Field | Type | Example | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| accountType | String | "Small Saving Account" | Type of savings account |
|
||||
| customerSegment | String | "Individual" | Customer classification |
|
||||
| productCode | String | "SB-IND-001" | Product identifier code |
|
||||
| effectiveDate | Date | "10 April 2026" | When the product becomes effective |
|
||||
| effectiveTo | Date | "10 April 2026" | Validity end date |
|
||||
| endDate | Date | "10 April 2026" | Product end date |
|
||||
| introducerRequired | Boolean | true | If introducer/referrer is mandatory |
|
||||
| shareLinkingEnabled | Boolean | true | If share account linking allowed |
|
||||
| nominationFacility | Boolean | true | If nomination facility available |
|
||||
| dormancyAlert | Boolean | true | If dormancy alerts enabled |
|
||||
| interestCalculateSelector | Integer | 2 | Interest calculation method selector |
|
||||
| averagePeriod | String | "Monthly" | Period for averaging balance |
|
||||
| autoPost | Boolean | true | Auto-post interest |
|
||||
| frequencyFixDay | Integer | 30 | Fixed day for frequency |
|
||||
| lastInterestDate | Date | "10 April 2026" | Last interest posting date |
|
||||
| enableLockinPeriod | Boolean | true | If lock-in period enforced |
|
||||
|
||||
### **Complex Objects (Require Separate Tables)**
|
||||
|
||||
#### 1️⃣ **accountFacilityConfig** (Single object with facility booleans)
|
||||
```json
|
||||
{
|
||||
"atmFacility": true,
|
||||
"atmWithdrawalFacility": true,
|
||||
"upiFacility": true,
|
||||
"posTransactionsFacility": true,
|
||||
"chequeBook": true,
|
||||
"impsFacility": true,
|
||||
"smsAlerts": true,
|
||||
"bbpsFacility": true,
|
||||
"insuranceCover": true,
|
||||
"bepgFacility": true,
|
||||
"neftFacility": true,
|
||||
"rtgsFacility": true,
|
||||
"interBankTotalCapFacility": true,
|
||||
"withdrawalFacility": true,
|
||||
"depositFacilityKyc": true,
|
||||
"virtualDebitCard": true
|
||||
}
|
||||
```
|
||||
→ **Table:** `m_savings_product_facility_config` (One-to-One relationship)
|
||||
|
||||
#### 2️⃣ **accountFacilityLimits** (Array of limit objects)
|
||||
```json
|
||||
[
|
||||
{"limitType": "ATM Withdrawal", "generalLimit": 40000, "minorAccountLimit": 5000, "smallSavingLimit": 10000},
|
||||
{"limitType": "POS Transactions", "generalLimit": 100000, "minorAccountLimit": 2000, "smallSavingLimit": 10000},
|
||||
...
|
||||
]
|
||||
```
|
||||
→ **Table:** `m_savings_product_facility_limits` (One-to-Many relationship)
|
||||
|
||||
#### 3️⃣ **depositLimitKyc** (Nested KYC limit rules)
|
||||
```json
|
||||
{
|
||||
"general": {"kycType": "Full KYC", "limit": "No Limit"},
|
||||
"minor": {"kycType": "Guardian KYC", "limit": 100000},
|
||||
"smallSaving": {"kycType": "Min KYC", "limit": 50000}
|
||||
}
|
||||
```
|
||||
→ **Table:** `m_savings_product_deposit_limit_kyc` (One-to-One relationship, or JSON column)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Database Changes Required
|
||||
|
||||
### **1. Alter m_savings_product table**
|
||||
```sql
|
||||
ALTER TABLE m_savings_product ADD COLUMN (
|
||||
account_type VARCHAR(50),
|
||||
customer_segment VARCHAR(50),
|
||||
product_code VARCHAR(20) UNIQUE,
|
||||
effective_date DATE,
|
||||
effective_to DATE,
|
||||
end_date DATE,
|
||||
introducer_required BOOLEAN DEFAULT FALSE,
|
||||
share_linking_enabled BOOLEAN DEFAULT FALSE,
|
||||
nomination_facility BOOLEAN DEFAULT FALSE,
|
||||
dormancy_alert BOOLEAN DEFAULT FALSE,
|
||||
interest_calculate_selector INT,
|
||||
average_period VARCHAR(20),
|
||||
auto_post BOOLEAN DEFAULT FALSE,
|
||||
frequency_fix_day INT,
|
||||
last_interest_date DATE,
|
||||
enable_lockin_period BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
```
|
||||
|
||||
### **2. Create m_savings_product_facility_config table** (One-to-One)
|
||||
```sql
|
||||
CREATE TABLE m_savings_product_facility_config (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
savings_product_id BIGINT NOT NULL UNIQUE,
|
||||
atm_facility BOOLEAN DEFAULT FALSE,
|
||||
atm_withdrawal_facility BOOLEAN DEFAULT FALSE,
|
||||
upi_facility BOOLEAN DEFAULT FALSE,
|
||||
pos_transactions_facility BOOLEAN DEFAULT FALSE,
|
||||
cheque_book BOOLEAN DEFAULT FALSE,
|
||||
imps_facility BOOLEAN DEFAULT FALSE,
|
||||
sms_alerts BOOLEAN DEFAULT FALSE,
|
||||
bbps_facility BOOLEAN DEFAULT FALSE,
|
||||
insurance_cover BOOLEAN DEFAULT FALSE,
|
||||
bepg_facility BOOLEAN DEFAULT FALSE,
|
||||
neft_facility BOOLEAN DEFAULT FALSE,
|
||||
rtgs_facility BOOLEAN DEFAULT FALSE,
|
||||
inter_bank_total_cap_facility BOOLEAN DEFAULT FALSE,
|
||||
withdrawal_facility BOOLEAN DEFAULT FALSE,
|
||||
deposit_facility_kyc BOOLEAN DEFAULT FALSE,
|
||||
virtual_debit_card BOOLEAN DEFAULT FALSE,
|
||||
created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (savings_product_id) REFERENCES m_savings_product(id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
### **3. Create m_savings_product_facility_limits table** (One-to-Many)
|
||||
```sql
|
||||
CREATE TABLE m_savings_product_facility_limits (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
savings_product_id BIGINT NOT NULL,
|
||||
limit_type VARCHAR(100) NOT NULL,
|
||||
general_limit VARCHAR(50), -- Can be decimal or "N/A", "UNLIMITED"
|
||||
minor_account_limit VARCHAR(50),
|
||||
small_saving_limit VARCHAR(50),
|
||||
created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (savings_product_id) REFERENCES m_savings_product(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_product_limit_type (savings_product_id, limit_type)
|
||||
);
|
||||
```
|
||||
|
||||
### **4. Create m_savings_product_deposit_limit_kyc table** (One-to-One)
|
||||
```sql
|
||||
CREATE TABLE m_savings_product_deposit_limit_kyc (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
savings_product_id BIGINT NOT NULL UNIQUE,
|
||||
general_kyc_type VARCHAR(50),
|
||||
general_limit VARCHAR(50), -- "No Limit" or numeric
|
||||
minor_kyc_type VARCHAR(50),
|
||||
minor_limit BIGINT,
|
||||
small_saving_kyc_type VARCHAR(50),
|
||||
small_saving_limit BIGINT,
|
||||
created_date DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (savings_product_id) REFERENCES m_savings_product(id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Java Entity Classes to Create/Update
|
||||
|
||||
### **1. Update SavingsProduct Entity**
|
||||
Add these fields to `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java`:
|
||||
|
||||
```java
|
||||
@Column(name = "account_type", length = 50)
|
||||
private String accountType;
|
||||
|
||||
@Column(name = "customer_segment", length = 50)
|
||||
private String customerSegment;
|
||||
|
||||
@Column(name = "product_code", length = 20, unique = true)
|
||||
private String productCode;
|
||||
|
||||
@Column(name = "effective_date")
|
||||
private LocalDate effectiveDate;
|
||||
|
||||
@Column(name = "effective_to")
|
||||
private LocalDate effectiveTo;
|
||||
|
||||
@Column(name = "end_date")
|
||||
private LocalDate endDate;
|
||||
|
||||
@Column(name = "introducer_required")
|
||||
private boolean introducerRequired;
|
||||
|
||||
@Column(name = "share_linking_enabled")
|
||||
private boolean shareLinkingEnabled;
|
||||
|
||||
@Column(name = "nomination_facility")
|
||||
private boolean nominationFacility;
|
||||
|
||||
@Column(name = "dormancy_alert")
|
||||
private boolean dormancyAlert;
|
||||
|
||||
@Column(name = "interest_calculate_selector")
|
||||
private Integer interestCalculateSelector;
|
||||
|
||||
@Column(name = "average_period", length = 20)
|
||||
private String averagePeriod;
|
||||
|
||||
@Column(name = "auto_post")
|
||||
private boolean autoPost;
|
||||
|
||||
@Column(name = "frequency_fix_day")
|
||||
private Integer frequencyFixDay;
|
||||
|
||||
@Column(name = "last_interest_date")
|
||||
private LocalDate lastInterestDate;
|
||||
|
||||
@Column(name = "enable_lockin_period")
|
||||
private boolean enableLockinPeriod;
|
||||
|
||||
// One-to-One relationship
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private SavingsProductFacilityConfig facilityConfig;
|
||||
|
||||
// One-to-Many relationship
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private Set<SavingsProductFacilityLimit> facilityLimits = new HashSet<>();
|
||||
|
||||
// One-to-One relationship
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private SavingsProductDepositLimitKyc depositLimitKyc;
|
||||
```
|
||||
|
||||
### **2. Create SavingsProductFacilityConfig Entity**
|
||||
`fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductFacilityConfig.java`:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_facility_config")
|
||||
public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "atm_facility")
|
||||
private Boolean atmFacility = false;
|
||||
|
||||
@Column(name = "atm_withdrawal_facility")
|
||||
private Boolean atmWithdrawalFacility = false;
|
||||
|
||||
@Column(name = "upi_facility")
|
||||
private Boolean upiFacility = false;
|
||||
|
||||
@Column(name = "pos_transactions_facility")
|
||||
private Boolean posTransactionsFacility = false;
|
||||
|
||||
@Column(name = "cheque_book")
|
||||
private Boolean chequeBook = false;
|
||||
|
||||
@Column(name = "imps_facility")
|
||||
private Boolean impsFacility = false;
|
||||
|
||||
@Column(name = "sms_alerts")
|
||||
private Boolean smsAlerts = false;
|
||||
|
||||
@Column(name = "bbps_facility")
|
||||
private Boolean bbpsFacility = false;
|
||||
|
||||
@Column(name = "insurance_cover")
|
||||
private Boolean insuranceCover = false;
|
||||
|
||||
@Column(name = "bepg_facility")
|
||||
private Boolean bepgFacility = false;
|
||||
|
||||
@Column(name = "neft_facility")
|
||||
private Boolean neftFacility = false;
|
||||
|
||||
@Column(name = "rtgs_facility")
|
||||
private Boolean rtgsFacility = false;
|
||||
|
||||
@Column(name = "inter_bank_total_cap_facility")
|
||||
private Boolean interBankTotalCapFacility = false;
|
||||
|
||||
@Column(name = "withdrawal_facility")
|
||||
private Boolean withdrawalFacility = false;
|
||||
|
||||
@Column(name = "deposit_facility_kyc")
|
||||
private Boolean depositFacilityKyc = false;
|
||||
|
||||
@Column(name = "virtual_debit_card")
|
||||
private Boolean virtualDebitCard = false;
|
||||
|
||||
// Getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
### **3. Create SavingsProductFacilityLimit Entity**
|
||||
`fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductFacilityLimit.java`:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_facility_limits")
|
||||
public class SavingsProductFacilityLimit extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "limit_type", length = 100, nullable = false)
|
||||
private String limitType;
|
||||
|
||||
@Column(name = "general_limit", length = 50)
|
||||
private String generalLimit; // Can be "UNLIMITED", "N/A", or numeric value
|
||||
|
||||
@Column(name = "minor_account_limit", length = 50)
|
||||
private String minorAccountLimit;
|
||||
|
||||
@Column(name = "small_saving_limit", length = 50)
|
||||
private String smallSavingLimit;
|
||||
|
||||
// Getters and setters
|
||||
|
||||
public static SavingsProductFacilityLimit create(
|
||||
SavingsProduct savingsProduct,
|
||||
String limitType,
|
||||
String generalLimit,
|
||||
String minorAccountLimit,
|
||||
String smallSavingLimit) {
|
||||
|
||||
SavingsProductFacilityLimit limit = new SavingsProductFacilityLimit();
|
||||
limit.savingsProduct = savingsProduct;
|
||||
limit.limitType = limitType;
|
||||
limit.generalLimit = generalLimit;
|
||||
limit.minorAccountLimit = minorAccountLimit;
|
||||
limit.smallSavingLimit = smallSavingLimit;
|
||||
return limit;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **4. Create SavingsProductDepositLimitKyc Entity**
|
||||
`fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductDepositLimitKyc.java`:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_deposit_limit_kyc")
|
||||
public class SavingsProductDepositLimitKyc extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "general_kyc_type", length = 50)
|
||||
private String generalKycType;
|
||||
|
||||
@Column(name = "general_limit", length = 50)
|
||||
private String generalLimit; // "No Limit" or numeric
|
||||
|
||||
@Column(name = "minor_kyc_type", length = 50)
|
||||
private String minorKycType;
|
||||
|
||||
@Column(name = "minor_limit")
|
||||
private Long minorLimit;
|
||||
|
||||
@Column(name = "small_saving_kyc_type", length = 50)
|
||||
private String smallSavingKycType;
|
||||
|
||||
@Column(name = "small_saving_limit")
|
||||
private Long smallSavingLimit;
|
||||
|
||||
// Getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔑 API Constants to Add
|
||||
|
||||
Update `fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java`:
|
||||
|
||||
```java
|
||||
// New Savings Product Fields
|
||||
public static final String accountTypeParamName = "accountType";
|
||||
public static final String customerSegmentParamName = "customerSegment";
|
||||
public static final String productCodeParamName = "productCode";
|
||||
public static final String effectiveDateParamName = "effectiveDate";
|
||||
public static final String effectiveToParamName = "effectiveTo";
|
||||
public static final String endDateParamName = "endDate";
|
||||
public static final String introducerRequiredParamName = "introducerRequired";
|
||||
public static final String shareLinkingEnabledParamName = "shareLinkingEnabled";
|
||||
public static final String nominationFacilityParamName = "nominationFacility";
|
||||
public static final String dormancyAlertParamName = "dormancyAlert";
|
||||
public static final String interestCalculateSelectorParamName = "interestCalculateSelector";
|
||||
public static final String averagePeriodParamName = "averagePeriod";
|
||||
public static final String autoPostParamName = "autoPost";
|
||||
public static final String frequencyFixDayParamName = "frequencyFixDay";
|
||||
public static final String lastInterestDateParamName = "lastInterestDate";
|
||||
public static final String enableLockinPeriodParamName = "enableLockinPeriod";
|
||||
|
||||
// Complex objects
|
||||
public static final String accountFacilityConfigParamName = "accountFacilityConfig";
|
||||
public static final String accountFacilityLimitsParamName = "accountFacilityLimits";
|
||||
public static final String depositLimitKycParamName = "depositLimitKyc";
|
||||
|
||||
// Facility config fields
|
||||
public static final String atmFacilityParamName = "atmFacility";
|
||||
public static final String atmWithdrawalFacilityParamName = "atmWithdrawalFacility";
|
||||
public static final String upiFacilityParamName = "upiFacility";
|
||||
// ... etc for all facility fields
|
||||
|
||||
// Limit fields
|
||||
public static final String limitTypeParamName = "limitType";
|
||||
public static final String generalLimitParamName = "generalLimit";
|
||||
public static final String minorAccountLimitParamName = "minorAccountLimit";
|
||||
public static final String smallSavingLimitParamName = "smallSavingLimit";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Validator Updates
|
||||
|
||||
Update `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java`:
|
||||
|
||||
1. **Add to parameter whitelist:**
|
||||
```java
|
||||
private static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS =
|
||||
new HashSet<>(Arrays.asList(
|
||||
// ... existing parameters ...
|
||||
"accountType",
|
||||
"customerSegment",
|
||||
"productCode",
|
||||
"effectiveDate",
|
||||
"effectiveTo",
|
||||
"endDate",
|
||||
"introducerRequired",
|
||||
"shareLinkingEnabled",
|
||||
"nominationFacility",
|
||||
"dormancyAlert",
|
||||
"interestCalculateSelector",
|
||||
"averagePeriod",
|
||||
"autoPost",
|
||||
"frequencyFixDay",
|
||||
"lastInterestDate",
|
||||
"enableLockinPeriod",
|
||||
"accountFacilityConfig",
|
||||
"accountFacilityLimits",
|
||||
"depositLimitKyc"
|
||||
));
|
||||
```
|
||||
|
||||
2. **Add validation logic in validateForCreate() and validateForUpdate():**
|
||||
```java
|
||||
if (command.stringValueOfParameterNamedAllowingNull("productCode") != null) {
|
||||
final String productCode = command.stringValueOfParameterNamed("productCode");
|
||||
if (StringUtils.isBlank(productCode)) {
|
||||
baseDataValidator.reset().parameter("productCode").value(productCode).notBlank();
|
||||
}
|
||||
}
|
||||
|
||||
if (command.hasParameter("effectiveDate")) {
|
||||
final LocalDate effectiveDate = command.localDateValueOfParameterNamed("effectiveDate");
|
||||
baseDataValidator.reset().parameter("effectiveDate").value(effectiveDate).notNull();
|
||||
}
|
||||
|
||||
// Similar for other date fields
|
||||
if (command.hasParameter("effectiveTo") && command.hasParameter("effectiveDate")) {
|
||||
final LocalDate effectiveDate = command.localDateValueOfParameterNamed("effectiveDate");
|
||||
final LocalDate effectiveTo = command.localDateValueOfParameterNamed("effectiveTo");
|
||||
if (effectiveTo.isBefore(effectiveDate)) {
|
||||
baseDataValidator.reset().parameter("effectiveTo").value(effectiveTo)
|
||||
.failWithCode("error.msg.effectiveto.cannot.be.before.effectivedate");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Assembler Updates
|
||||
|
||||
Update `fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java`:
|
||||
|
||||
Add helper methods to extract and assemble nested objects:
|
||||
|
||||
```java
|
||||
public SavingsProductFacilityConfig assembleAccountFacilityConfig(final JsonCommand command, final SavingsProduct product) {
|
||||
final JsonObject jsonObject = command.parsedJson();
|
||||
|
||||
if (!jsonObject.has("accountFacilityConfig")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonObject facilityConfigJson = jsonObject.getAsJsonObject("accountFacilityConfig");
|
||||
SavingsProductFacilityConfig config = new SavingsProductFacilityConfig();
|
||||
config.setSavingsProduct(product);
|
||||
config.setAtmFacility(facilityConfigJson.has("atmFacility") ?
|
||||
facilityConfigJson.getAsJsonPrimitive("atmFacility").getAsBoolean() : false);
|
||||
config.setAtmWithdrawalFacility(facilityConfigJson.has("atmWithdrawalFacility") ?
|
||||
facilityConfigJson.getAsJsonPrimitive("atmWithdrawalFacility").getAsBoolean() : false);
|
||||
// ... set other facilities ...
|
||||
return config;
|
||||
}
|
||||
|
||||
public Set<SavingsProductFacilityLimit> assembleAccountFacilityLimits(final JsonCommand command, final SavingsProduct product) {
|
||||
final JsonObject jsonObject = command.parsedJson();
|
||||
final Set<SavingsProductFacilityLimit> limits = new HashSet<>();
|
||||
|
||||
if (!jsonObject.has("accountFacilityLimits")) {
|
||||
return limits;
|
||||
}
|
||||
|
||||
final JsonArray limitsArray = jsonObject.getAsJsonArray("accountFacilityLimits");
|
||||
for (JsonElement element : limitsArray) {
|
||||
final JsonObject limitJson = element.getAsJsonObject();
|
||||
SavingsProductFacilityLimit limit = SavingsProductFacilityLimit.create(
|
||||
product,
|
||||
limitJson.has("limitType") ? limitJson.getAsJsonPrimitive("limitType").getAsString() : null,
|
||||
limitJson.has("generalLimit") ? limitJson.getAsJsonPrimitive("generalLimit").getAsString() : null,
|
||||
limitJson.has("minorAccountLimit") ? limitJson.getAsJsonPrimitive("minorAccountLimit").getAsString() : null,
|
||||
limitJson.has("smallSavingLimit") ? limitJson.getAsJsonPrimitive("smallSavingLimit").getAsString() : null
|
||||
);
|
||||
limits.add(limit);
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
||||
public SavingsProductDepositLimitKyc assembleDepositLimitKyc(final JsonCommand command, final SavingsProduct product) {
|
||||
final JsonObject jsonObject = command.parsedJson();
|
||||
|
||||
if (!jsonObject.has("depositLimitKyc")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonObject kycJson = jsonObject.getAsJsonObject("depositLimitKyc");
|
||||
SavingsProductDepositLimitKyc kyc = new SavingsProductDepositLimitKyc();
|
||||
kyc.setSavingsProduct(product);
|
||||
|
||||
if (kycJson.has("general")) {
|
||||
final JsonObject generalJson = kycJson.getAsJsonObject("general");
|
||||
kyc.setGeneralKycType(generalJson.has("kycType") ?
|
||||
generalJson.getAsJsonPrimitive("kycType").getAsString() : null);
|
||||
kyc.setGeneralLimit(generalJson.has("limit") ?
|
||||
generalJson.getAsJsonPrimitive("limit").getAsString() : null);
|
||||
}
|
||||
|
||||
// ... handle minor and smallSaving similarly ...
|
||||
|
||||
return kyc;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Repository Classes to Create
|
||||
|
||||
### **SavingsProductFacilityConfigRepository.java**
|
||||
```java
|
||||
@Repository
|
||||
public interface SavingsProductFacilityConfigRepository extends
|
||||
JpaRepository<SavingsProductFacilityConfig, Long> {
|
||||
SavingsProductFacilityConfig findBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
```
|
||||
|
||||
### **SavingsProductFacilityLimitRepository.java**
|
||||
```java
|
||||
@Repository
|
||||
public interface SavingsProductFacilityLimitRepository extends
|
||||
JpaRepository<SavingsProductFacilityLimit, Long> {
|
||||
List<SavingsProductFacilityLimit> findBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
```
|
||||
|
||||
### **SavingsProductDepositLimitKycRepository.java**
|
||||
```java
|
||||
@Repository
|
||||
public interface SavingsProductDepositLimitKycRepository extends
|
||||
JpaRepository<SavingsProductDepositLimitKyc, Long> {
|
||||
SavingsProductDepositLimitKyc findBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Service Updates
|
||||
|
||||
Update `SavingsProductWritePlatformServiceImpl.create()` method:
|
||||
|
||||
```java
|
||||
public CommandProcessingResult create(final JsonCommand command) {
|
||||
try {
|
||||
this.savingsProductDataValidator.validateForCreate(command.json());
|
||||
|
||||
// ... existing code ...
|
||||
|
||||
// Assemble new objects
|
||||
final SavingsProductFacilityConfig facilityConfig =
|
||||
this.savingsProductAssembler.assembleAccountFacilityConfig(command, product);
|
||||
final Set<SavingsProductFacilityLimit> facilityLimits =
|
||||
this.savingsProductAssembler.assembleAccountFacilityLimits(command, product);
|
||||
final SavingsProductDepositLimitKyc depositLimitKyc =
|
||||
this.savingsProductAssembler.assembleDepositLimitKyc(command, product);
|
||||
|
||||
if (facilityConfig != null) {
|
||||
product.setFacilityConfig(facilityConfig);
|
||||
facilityConfigRepository.saveAndFlush(facilityConfig);
|
||||
}
|
||||
|
||||
if (!facilityLimits.isEmpty()) {
|
||||
product.setFacilityLimits(facilityLimits);
|
||||
facilityLimitRepository.saveAll(facilityLimits);
|
||||
}
|
||||
|
||||
if (depositLimitKyc != null) {
|
||||
product.setDepositLimitKyc(depositLimitKyc);
|
||||
depositLimitKycRepository.saveAndFlush(depositLimitKyc);
|
||||
}
|
||||
|
||||
// Save main product
|
||||
final SavingsProduct productSaved = this.savingProductRepository.saveAndFlush(product);
|
||||
|
||||
return new CommandProcessingResultBuilder()
|
||||
.withCommandId(command.commandId())
|
||||
.withEntityId(productSaved.getId())
|
||||
.build();
|
||||
|
||||
} catch (final DataAccessException e) {
|
||||
// error handling
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Read Service Updates
|
||||
|
||||
Update `SavingsProductReadPlatformService` to include new fields in queries and DTO.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Summary of Changes
|
||||
|
||||
| Component | Type | Files to Modify/Create |
|
||||
|-----------|------|----------------------|
|
||||
| Database | Migration | SQL scripts |
|
||||
| Entities | Create/Modify | 4 entity classes |
|
||||
| Constants | Modify | SavingsApiConstants.java |
|
||||
| Validator | Modify | SavingsProductDataValidator.java |
|
||||
| Assembler | Modify | SavingsProductAssembler.java |
|
||||
| Repositories | Create | 3 repository interfaces |
|
||||
| Services | Modify | SavingsProductWrite/ReadPlatformService |
|
||||
| DAO | Modify | SQL queries in read service |
|
||||
|
||||
---
|
||||
|
||||
## 📌 Implementation Priority
|
||||
|
||||
1. **Phase 1:** Create database tables
|
||||
2. **Phase 2:** Create entity classes
|
||||
3. **Phase 3:** Add API constants and validator rules
|
||||
4. **Phase 4:** Create repositories and update service layer
|
||||
5. **Phase 5:** Update read service and DTOs
|
||||
6. **Phase 6:** Test with your POST endpoint
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
- ✅ Fields like `otherGlMappings`, `isDormancyTrackingActive`, etc. **already exist** in the system
|
||||
- ✅ Ensure backward compatibility - make all new fields optional in the validator
|
||||
- ✅ Use cascade = CascadeType.ALL and orphanRemoval = true for nested entities
|
||||
- ✅ Add unique constraints where needed (e.g., productCode, limit combinations)
|
||||
- ✅ Consider adding indexes on frequently queried fields
|
||||
- ✅ Update DTO classes to include these new fields in API responses
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "savings-products-collection",
|
||||
"name": "Fineract - Savings Products",
|
||||
"description": "Postman collection for Savings Product APIs.\n\nThis resource exposes 6 endpoints:\n1. POST /v1/savingsproducts\n2. PUT /v1/savingsproducts/{productId}\n3. GET /v1/savingsproducts\n4. GET /v1/savingsproducts/{productId}\n5. GET /v1/savingsproducts/template\n6. DELETE /v1/savingsproducts/{productId}\n\nThe create request below uses the mandatory fields required by the backend validator. If you switch accountingRule to cash-based or accrual-periodic, you must also supply the corresponding accounting mappings.",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"auth": {
|
||||
"type": "basic",
|
||||
"basic": [
|
||||
{
|
||||
"key": "username",
|
||||
"value": "{{username}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "{{password}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"variable": [
|
||||
{
|
||||
"key": "base_url",
|
||||
"value": "https://localhost:8443/fineract-provider/api/v1",
|
||||
"description": "Fineract API base URL"
|
||||
},
|
||||
{
|
||||
"key": "tenant_id",
|
||||
"value": "default",
|
||||
"description": "Tenant identifier"
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"value": "mifos",
|
||||
"description": "API username"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "password",
|
||||
"description": "API password"
|
||||
},
|
||||
{
|
||||
"key": "product_id",
|
||||
"value": "1",
|
||||
"description": "Savings product id returned by the create request"
|
||||
}
|
||||
],
|
||||
"item": [
|
||||
{
|
||||
"name": "Savings Products",
|
||||
"item": [
|
||||
{
|
||||
"name": "Create Savings Product",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"type": "text/javascript",
|
||||
"exec": [
|
||||
"pm.test('Status code is 200', function () {",
|
||||
" pm.response.to.have.status(200);",
|
||||
"});",
|
||||
"",
|
||||
"pm.test('Resource id returned', function () {",
|
||||
" var json = pm.response.json();",
|
||||
" pm.expect(json).to.have.property('resourceId');",
|
||||
" pm.collectionVariables.set('product_id', json.resourceId);",
|
||||
"});"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"Passbook Savings\",\n \"shortName\": \"PBSV\",\n \"description\": \"Daily compounding savings product\",\n \"currencyCode\": \"USD\",\n \"digitsAfterDecimal\": 2,\n \"inMultiplesOf\": 0,\n \"locale\": \"en\",\n \"nominalAnnualInterestRate\": 5.0,\n \"interestCompoundingPeriodType\": 1,\n \"interestPostingPeriodType\": 4,\n \"interestCalculationType\": 1,\n \"interestCalculationDaysInYearType\": 365,\n \"accountingRule\": 1,\n \"withdrawalFeeForTransfers\": false,\n \"enforceMinRequiredBalance\": false,\n \"allowOverdraft\": false,\n \"withHoldTax\": false,\n \"isDormancyTrackingActive\": false,\n \"charges\": [\n {\n \"id\": 1\n }\n ]\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts"
|
||||
]
|
||||
},
|
||||
"description": "Create a savings product.\n\nRequired by backend validator:\n- name\n- shortName\n- currencyCode\n- digitsAfterDecimal\n- nominalAnnualInterestRate\n- interestCompoundingPeriodType\n- interestPostingPeriodType\n- interestCalculationType\n- interestCalculationDaysInYearType\n- accountingRule\n\nIf accountingRule = 2 or 3, the backend also expects accounting mappings."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Update Savings Product",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"description\": \"Updated savings product description\",\n \"locale\": \"en\",\n \"nominalAnnualInterestRate\": 5.75\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts/{{product_id}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts",
|
||||
"{{product_id}}"
|
||||
]
|
||||
},
|
||||
"description": "Update an existing savings product by product id."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "List Savings Products",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts"
|
||||
]
|
||||
},
|
||||
"description": "Lists all savings products."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Savings Product By ID",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts/{{product_id}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts",
|
||||
"{{product_id}}"
|
||||
]
|
||||
},
|
||||
"description": "Retrieves a savings product by id. You can also call the same endpoint with ?template=true."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get Savings Product Template",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts/template",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts",
|
||||
"template"
|
||||
]
|
||||
},
|
||||
"description": "Returns template data with dropdown options and default values for savings product creation."
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Delete Savings Product",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Fineract-Platform-TenantId",
|
||||
"value": "{{tenant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/savingsproducts/{{product_id}}",
|
||||
"host": [
|
||||
"{{base_url}}"
|
||||
],
|
||||
"path": [
|
||||
"savingsproducts",
|
||||
"{{product_id}}"
|
||||
]
|
||||
},
|
||||
"description": "Deletes a savings product by id."
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
],
|
||||
"description": "Savings product master APIs."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
@echo off
|
||||
echo Stopping any running Gradle daemons...
|
||||
call gradlew.bat --stop
|
||||
echo.
|
||||
echo Deleting corrupted build folders...
|
||||
if exist fineract-provider\build (
|
||||
echo Deleting fineract-provider\build...
|
||||
rmdir /s /q fineract-provider\build
|
||||
)
|
||||
if exist fineract-command\build (
|
||||
echo Deleting fineract-command\build...
|
||||
rmdir /s /q fineract-command\build
|
||||
)
|
||||
if exist fineract-core\build (
|
||||
echo Deleting fineract-core\build...
|
||||
rmdir /s /q fineract-core\build
|
||||
)
|
||||
if exist fineract-accounting\build (
|
||||
echo Deleting fineract-accounting\build...
|
||||
rmdir /s /q fineract-accounting\build
|
||||
)
|
||||
if exist fineract-charge\build (
|
||||
echo Deleting fineract-charge\build...
|
||||
rmdir /s /q fineract-charge\build
|
||||
)
|
||||
if exist fineract-cob\build (
|
||||
echo Deleting fineract-cob\build...
|
||||
rmdir /s /q fineract-cob\build
|
||||
)
|
||||
if exist fineract-document\build (
|
||||
echo Deleting fineract-document\build...
|
||||
rmdir /s /q fineract-document\build
|
||||
)
|
||||
if exist fineract-branch\build (
|
||||
echo Deleting fineract-branch\build...
|
||||
rmdir /s /q fineract-branch\build
|
||||
)
|
||||
if exist fineract-avro-schemas\build (
|
||||
echo Deleting fineract-avro-schemas\build...
|
||||
rmdir /s /q fineract-avro-schemas\build
|
||||
)
|
||||
echo.
|
||||
echo Build folders deleted successfully.
|
||||
echo Now you can run: .\gradlew devRun
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,116 @@
|
||||
> Task :buildSrc:extractPluginRequests UP-TO-DATE
|
||||
> Task :buildSrc:generatePluginAdapters UP-TO-DATE
|
||||
> Task :buildSrc:compileJava UP-TO-DATE
|
||||
> Task :buildSrc:compileGroovy UP-TO-DATE
|
||||
> Task :buildSrc:compileGroovyPlugins UP-TO-DATE
|
||||
> Task :buildSrc:pluginDescriptors UP-TO-DATE
|
||||
> Task :buildSrc:processResources UP-TO-DATE
|
||||
> Task :buildSrc:classes UP-TO-DATE
|
||||
> Task :buildSrc:jar UP-TO-DATE
|
||||
|
||||
> Configure project :
|
||||
matching ref: COMMIT - 011239f3995f9ea94a893ed4a60251a3b154564c
|
||||
ref configuration: COMMIT - pattern: null
|
||||
version: ${describe.tag.version.major}.${describe.tag.version.minor.next}.0-SNAPSHOT
|
||||
describeTagPattern: .*(\d+\.\d+\.\d+).*
|
||||
describeTagFirstParent: false
|
||||
|
||||
project version: 0.1.0-SNAPSHOT
|
||||
|
||||
> Task :fineract-core:processResources UP-TO-DATE
|
||||
> Task :fineract-tax:processResources UP-TO-DATE
|
||||
> Task :fineract-accounting:processResources UP-TO-DATE
|
||||
> Task :spotlessInternalRegisterDependencies UP-TO-DATE
|
||||
> Task :fineract-document:processResources NO-SOURCE
|
||||
> Task :fineract-avro-schemas:preprocessAvroSchemas UP-TO-DATE
|
||||
> Task :fineract-charge:processResources UP-TO-DATE
|
||||
> Task :fineract-branch:processResources UP-TO-DATE
|
||||
> Task :fineract-cob:processResources UP-TO-DATE
|
||||
> Task :fineract-rates:processResources UP-TO-DATE
|
||||
> Task :fineract-investor:processResources UP-TO-DATE
|
||||
> Task :fineract-mix:processResources NO-SOURCE
|
||||
> Task :fineract-loan:processResources UP-TO-DATE
|
||||
> Task :fineract-loan-origination:processResources UP-TO-DATE
|
||||
> Task :fineract-progressive-loan:processResources UP-TO-DATE
|
||||
> Task :fineract-security:processResources NO-SOURCE
|
||||
> Task :fineract-report:processResources UP-TO-DATE
|
||||
> Task :fineract-savings:processResources UP-TO-DATE
|
||||
> Task :fineract-working-capital-loan:processResources UP-TO-DATE
|
||||
> Task :fineract-validation:compileJava UP-TO-DATE
|
||||
> Task :fineract-command:compileJava UP-TO-DATE
|
||||
> Task :fineract-validation:processResources UP-TO-DATE
|
||||
> Task :fineract-command:processResources UP-TO-DATE
|
||||
> Task :fineract-command:classes UP-TO-DATE
|
||||
> Task :fineract-validation:classes UP-TO-DATE
|
||||
> Task :fineract-command:jar UP-TO-DATE
|
||||
> Task :fineract-validation:jar UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:spotlessJson UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:spotlessJsonApply UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:buildJavaSdk UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:compileJava UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:processResources UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:classes UP-TO-DATE
|
||||
> Task :fineract-avro-schemas:jar UP-TO-DATE
|
||||
> Task :fineract-working-capital-loan:compileJava UP-TO-DATE
|
||||
> Task :fineract-working-capital-loan:classes UP-TO-DATE
|
||||
> Task :fineract-working-capital-loan:jar UP-TO-DATE
|
||||
> Task :fineract-core:compileJava UP-TO-DATE
|
||||
> Task :fineract-core:classes UP-TO-DATE
|
||||
> Task :fineract-core:jar UP-TO-DATE
|
||||
> Task :fineract-mix:compileJava UP-TO-DATE
|
||||
> Task :fineract-mix:classes UP-TO-DATE
|
||||
> Task :fineract-mix:jar UP-TO-DATE
|
||||
> Task :fineract-cob:compileJava UP-TO-DATE
|
||||
> Task :fineract-cob:classes UP-TO-DATE
|
||||
> Task :fineract-report:compileJava UP-TO-DATE
|
||||
> Task :fineract-tax:compileJava UP-TO-DATE
|
||||
> Task :fineract-rates:compileJava UP-TO-DATE
|
||||
> Task :fineract-tax:classes UP-TO-DATE
|
||||
> Task :fineract-rates:classes UP-TO-DATE
|
||||
> Task :fineract-cob:jar UP-TO-DATE
|
||||
> Task :fineract-report:classes UP-TO-DATE
|
||||
> Task :fineract-tax:jar UP-TO-DATE
|
||||
> Task :fineract-rates:jar UP-TO-DATE
|
||||
> Task :fineract-report:jar UP-TO-DATE
|
||||
> Task :fineract-charge:compileJava UP-TO-DATE
|
||||
> Task :fineract-charge:classes UP-TO-DATE
|
||||
> Task :fineract-security:compileJava UP-TO-DATE
|
||||
> Task :fineract-charge:jar UP-TO-DATE
|
||||
> Task :fineract-security:classes UP-TO-DATE
|
||||
> Task :fineract-document:compileJava UP-TO-DATE
|
||||
> Task :fineract-document:classes UP-TO-DATE
|
||||
> Task :fineract-security:jar UP-TO-DATE
|
||||
> Task :fineract-document:jar UP-TO-DATE
|
||||
> Task :fineract-accounting:compileJava UP-TO-DATE
|
||||
> Task :fineract-accounting:classes UP-TO-DATE
|
||||
> Task :fineract-accounting:jar UP-TO-DATE
|
||||
> Task :fineract-branch:compileJava UP-TO-DATE
|
||||
> Task :fineract-branch:classes UP-TO-DATE
|
||||
> Task :fineract-branch:jar UP-TO-DATE
|
||||
> Task :fineract-savings:compileJava UP-TO-DATE
|
||||
> Task :fineract-loan:compileJava UP-TO-DATE
|
||||
> Task :fineract-loan:classes UP-TO-DATE
|
||||
> Task :fineract-savings:classes UP-TO-DATE
|
||||
> Task :fineract-loan:jar UP-TO-DATE
|
||||
> Task :fineract-savings:jar UP-TO-DATE
|
||||
> Task :fineract-progressive-loan:compileJava UP-TO-DATE
|
||||
> Task :fineract-progressive-loan:classes UP-TO-DATE
|
||||
> Task :fineract-loan-origination:compileJava UP-TO-DATE
|
||||
> Task :fineract-loan-origination:classes UP-TO-DATE
|
||||
> Task :fineract-investor:compileJava UP-TO-DATE
|
||||
> Task :fineract-investor:classes UP-TO-DATE
|
||||
> Task :fineract-loan-origination:jar UP-TO-DATE
|
||||
> Task :fineract-investor:jar UP-TO-DATE
|
||||
> Task :fineract-progressive-loan:jar UP-TO-DATE
|
||||
> Task :fineract-provider:compileJava UP-TO-DATE
|
||||
|
||||
[Incubating] Problems report is available at: file:///D:/CompanyProject/GitCBS/JAVA-Backend-CBS-MAIN/build/reports/problems/problems-report.html
|
||||
|
||||
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
|
||||
|
||||
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
|
||||
|
||||
For more on this, please refer to https://docs.gradle.org/8.14.3/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
|
||||
|
||||
BUILD SUCCESSFUL in 23s
|
||||
71 actionable tasks: 71 up-to-date
|
||||
@@ -0,0 +1,4 @@
|
||||
# Netscape HTTP Cookie File
|
||||
# https://curl.se/docs/http-cookies.html
|
||||
# This file was generated by libcurl! Edit at your own risk.
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
-- Complete migration: Add all custom/enhanced fields to m_savings_product table
|
||||
-- Uses IF NOT EXISTS to safely handle columns that may already exist
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Scalar custom columns
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='account_type') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN account_type VARCHAR(50) DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='customer_segment') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN customer_segment VARCHAR(50) DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='product_code') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN product_code VARCHAR(20) DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='effective_date') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN effective_date DATE DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='effective_to') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN effective_to DATE DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='end_date') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN end_date DATE DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='introducer_required') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN introducer_required BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='share_linking_enabled') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN share_linking_enabled BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='nomination_facility') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN nomination_facility BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='dormancy_alert') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN dormancy_alert BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='interest_calculate_selector') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN interest_calculate_selector INT DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='average_period') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN average_period VARCHAR(20) DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='auto_post') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN auto_post BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='frequency_fix_day') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN frequency_fix_day INT DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='last_interest_date') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN last_interest_date DATE DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='enable_lockin_period') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN enable_lockin_period BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='balance_frequency') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN balance_frequency VARCHAR(50) DEFAULT NULL;
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='m_savings_product' AND column_name='account_closed_zero_balance_in_day_closing') THEN
|
||||
ALTER TABLE m_savings_product ADD COLUMN account_closed_zero_balance_in_day_closing BOOLEAN DEFAULT FALSE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Add comments for documentation (safe to run multiple times)
|
||||
COMMENT ON COLUMN m_savings_product.account_type IS 'Account type classification';
|
||||
COMMENT ON COLUMN m_savings_product.customer_segment IS 'Customer segment classification';
|
||||
COMMENT ON COLUMN m_savings_product.product_code IS 'Unique product code identifier';
|
||||
COMMENT ON COLUMN m_savings_product.effective_date IS 'Date from which the product becomes effective';
|
||||
COMMENT ON COLUMN m_savings_product.effective_to IS 'Date until which the product is effective';
|
||||
COMMENT ON COLUMN m_savings_product.end_date IS 'Product end/expiry date';
|
||||
COMMENT ON COLUMN m_savings_product.introducer_required IS 'Whether an introducer is required for this product';
|
||||
COMMENT ON COLUMN m_savings_product.share_linking_enabled IS 'Whether share linking is enabled for this product';
|
||||
COMMENT ON COLUMN m_savings_product.nomination_facility IS 'Whether nomination facility is available';
|
||||
COMMENT ON COLUMN m_savings_product.dormancy_alert IS 'Whether dormancy alerts are enabled';
|
||||
COMMENT ON COLUMN m_savings_product.interest_calculate_selector IS 'Interest calculation selector type';
|
||||
COMMENT ON COLUMN m_savings_product.average_period IS 'Average period for calculations';
|
||||
COMMENT ON COLUMN m_savings_product.auto_post IS 'Whether auto posting of interest is enabled';
|
||||
COMMENT ON COLUMN m_savings_product.frequency_fix_day IS 'Fixed day for frequency calculations';
|
||||
COMMENT ON COLUMN m_savings_product.last_interest_date IS 'Last date interest was calculated';
|
||||
COMMENT ON COLUMN m_savings_product.enable_lockin_period IS 'Whether lock-in period is enabled';
|
||||
COMMENT ON COLUMN m_savings_product.balance_frequency IS 'Frequency for balance calculation (e.g., Daily, Monthly, Quarterly)';
|
||||
COMMENT ON COLUMN m_savings_product.account_closed_zero_balance_in_day_closing IS 'Flag to indicate if account should be closed when balance reaches zero at day end';
|
||||
+65
@@ -25,6 +25,11 @@ public class SavingsApiConstants {
|
||||
public static final String SAVINGS_ACCOUNT_RESOURCE_NAME = "savingsaccount";
|
||||
public static final String SAVINGS_ACCOUNT_TRANSACTION_RESOURCE_NAME = "savingsaccount.transaction";
|
||||
public static final String SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME = "savingsaccountcharge";
|
||||
public static final String YES_NO = "YesNo";
|
||||
public static final String SAVINGS_PRODUCT_ACCOUNT_TYPE = "SavingsProductAccountType";
|
||||
public static final String SAVINGS_PRODUCT_CUSTOMER_SEGMENT = "SavingsProductCustomerSegment";
|
||||
public static final String PERIOD_FREQUENCY = "PeriodFrequency";
|
||||
public static final String INTEREST_CALCULATION_TYPE_OPTION = "InterestCalculationTypeOption";
|
||||
|
||||
// actions
|
||||
public static final String postInterestValidationOnClosure = "postInterestValidationOnClosure";
|
||||
@@ -195,6 +200,7 @@ public class SavingsApiConstants {
|
||||
public static final String daysToInactiveParamName = "daysToInactive";
|
||||
public static final String daysToDormancyParamName = "daysToDormancy";
|
||||
public static final String daysToEscheatParamName = "daysToEscheat";
|
||||
public static final String otherGlMappingsParamName = "otherGlMappings";
|
||||
|
||||
public static final String datatables = "datatables";
|
||||
|
||||
@@ -203,4 +209,63 @@ public class SavingsApiConstants {
|
||||
public static final String ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE = "not.in.active.state";
|
||||
|
||||
public static final String accountMappingForPaymentParamName = "accountMappingForPayment";
|
||||
|
||||
// Enhanced Savings Product Fields
|
||||
public static final String accountTypeParamName = "accountType";
|
||||
public static final String customerSegmentParamName = "customerSegment";
|
||||
public static final String productCodeParamName = "productCode";
|
||||
public static final String effectiveDateParamName = "effectiveDate";
|
||||
public static final String effectiveToParamName = "effectiveTo";
|
||||
public static final String endDateParamName = "endDate";
|
||||
public static final String introducerRequiredParamName = "introducerRequired";
|
||||
public static final String shareLinkingEnabledParamName = "shareLinkingEnabled";
|
||||
public static final String nominationFacilityParamName = "nominationFacility";
|
||||
public static final String dormancyAlertParamName = "dormancyAlert";
|
||||
public static final String interestCalculateSelectorParamName = "interestCalculateSelector";
|
||||
public static final String averagePeriodParamName = "averagePeriod";
|
||||
public static final String autoPostParamName = "autoPost";
|
||||
public static final String frequencyFixDayParamName = "frequencyFixDay";
|
||||
public static final String lastInterestDateParamName = "lastInterestDate";
|
||||
public static final String enableLockinPeriodParamName = "enableLockinPeriod";
|
||||
|
||||
// Complex objects
|
||||
public static final String accountFacilityConfigParamName = "accountFacilityConfig";
|
||||
public static final String accountFacilityLimitsParamName = "accountFacilityLimits";
|
||||
public static final String depositLimitKycParamName = "depositLimitKyc";
|
||||
|
||||
// Facility config fields
|
||||
public static final String atmFacilityParamName = "atmFacility";
|
||||
public static final String atmWithdrawalFacilityParamName = "atmWithdrawalFacility";
|
||||
public static final String upiFacilityParamName = "upiFacility";
|
||||
public static final String posTransactionsFacilityParamName = "posTransactionsFacility";
|
||||
public static final String chequeBookParamName = "chequeBook";
|
||||
public static final String impsFacilityParamName = "impsFacility";
|
||||
public static final String smsAlertsParamName = "smsAlerts";
|
||||
public static final String bbpsFacilityParamName = "bbpsFacility";
|
||||
public static final String insuranceCoverParamName = "insuranceCover";
|
||||
public static final String bepgFacilityParamName = "bepgFacility";
|
||||
public static final String neftFacilityParamName = "neftFacility";
|
||||
public static final String rtgsFacilityParamName = "rtgsFacility";
|
||||
public static final String interBankTotalCapFacilityParamName = "interBankTotalCapFacility";
|
||||
public static final String withdrawalFacilityParamName = "withdrawalFacility";
|
||||
public static final String depositFacilityKycParamName = "depositFacilityKyc";
|
||||
public static final String virtualDebitCardParamName = "virtualDebitCard";
|
||||
|
||||
// Limit fields
|
||||
public static final String limitTypeParamName = "limitType";
|
||||
public static final String generalLimitParamName = "generalLimit";
|
||||
public static final String minorAccountLimitParamName = "minorAccountLimit";
|
||||
public static final String smallSavingLimitParamName = "smallSavingLimit";
|
||||
|
||||
// Deposit limit KYC fields
|
||||
public static final String generalKycTypeParamName = "generalKycType";
|
||||
public static final String generalKycLimitParamName = "generalLimit";
|
||||
public static final String minorKycTypeParamName = "minorKycType";
|
||||
public static final String minorLimitParamName = "minorLimit";
|
||||
public static final String smallSavingKycTypeParamName = "smallSavingKycType";
|
||||
public static final String smallSavingKycLimitParamName = "smallSavingLimit";
|
||||
|
||||
// Additional custom fields
|
||||
public static final String balanceFrequencyParamName = "balanceFrequency";
|
||||
public static final String accountClosedZeroBalanceInDayClosingParamName = "accountClosedZeroBalanceInDayClosing";
|
||||
}
|
||||
|
||||
+185
-43
@@ -29,6 +29,7 @@ import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
@@ -101,19 +102,50 @@ public final class SavingsProductData implements Serializable {
|
||||
private final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions;
|
||||
private final Collection<EnumOptionData> interestPostingPeriodTypeOptions;
|
||||
private final Collection<EnumOptionData> interestCalculationTypeOptions;
|
||||
private final Collection<EnumOptionData> interestCalculationTypeOption;
|
||||
private final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions;
|
||||
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
||||
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
private final Collection<EnumOptionData> periodFrequencyOptions;
|
||||
private final Collection<PaymentTypeData> paymentTypeOptions;
|
||||
private final Collection<EnumOptionData> accountingRuleOptions;
|
||||
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
private final Collection<ChargeData> penaltyOptions;
|
||||
private final Collection<TaxGroupData> taxGroupOptions;
|
||||
private final Collection<CodeValueData> yesNoOptions;
|
||||
private final Collection<CodeValueData> accountTypeOptions;
|
||||
private final Collection<CodeValueData> customerSegmentOptions;
|
||||
private final Boolean isDormancyTrackingActive;
|
||||
private final Long daysToInactive;
|
||||
private final Long daysToDormancy;
|
||||
private final Long daysToEscheat;
|
||||
private final List<Map<String, Object>> otherGlMappings;
|
||||
|
||||
// Enhanced Savings Product Fields
|
||||
@Getter @Setter private String accountType;
|
||||
@Getter @Setter private String customerSegment;
|
||||
@Getter @Setter private String productCode;
|
||||
@Getter @Setter private java.time.LocalDate effectiveDate;
|
||||
@Getter @Setter private java.time.LocalDate effectiveTo;
|
||||
@Getter @Setter private java.time.LocalDate endDate;
|
||||
@Getter @Setter private Boolean introducerRequired;
|
||||
@Getter @Setter private Boolean shareLinkingEnabled;
|
||||
@Getter @Setter private Boolean nominationFacility;
|
||||
@Getter @Setter private Boolean dormancyAlert;
|
||||
@Getter @Setter private Integer interestCalculateSelector;
|
||||
@Getter @Setter private String averagePeriod;
|
||||
@Getter @Setter private Boolean autoPost;
|
||||
@Getter @Setter private Integer frequencyFixDay;
|
||||
@Getter @Setter private java.time.LocalDate lastInterestDate;
|
||||
@Getter @Setter private Boolean enableLockinPeriod;
|
||||
@Getter @Setter private String balanceFrequency;
|
||||
@Getter @Setter private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
|
||||
// Complex objects wrapped as Maps/Lists so Jackson converts them into the exact JSON your UI expects
|
||||
@Getter @Setter private Map<String, Object> accountFacilityConfig;
|
||||
@Getter @Setter private Collection<Map<String, Object>> accountFacilityLimits;
|
||||
@Getter @Setter private Map<String, Object> depositLimitKyc;
|
||||
|
||||
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
@@ -121,12 +153,16 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final Collection<TaxGroupData> taxGroupOptions,
|
||||
final String accountMappingForPayment) {
|
||||
final Collection<CodeValueData> yesNoOptions,
|
||||
final Collection<CodeValueData> accountTypeOptions, final Collection<CodeValueData> customerSegmentOptions,
|
||||
final String accountMappingForPayment, final List<Map<String, Object>> otherGlMappings) {
|
||||
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
@@ -157,35 +193,66 @@ public final class SavingsProductData implements Serializable {
|
||||
final Long daysToInactive = null;
|
||||
final Long daysToDormancy = null;
|
||||
final Long daysToEscheat = null;
|
||||
final List<Map<String, Object>> otherGlMappingsTemplate = null;
|
||||
|
||||
return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
|
||||
minRequiredBalance, enforceMinRequiredBalance, maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions,
|
||||
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, accountMappingForPayment);
|
||||
yesNoOptions, accountTypeOptions, customerSegmentOptions, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat,
|
||||
accountMappingForPayment, otherGlMappingsTemplate);
|
||||
}
|
||||
|
||||
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, final Collection<TaxGroupData> taxGroupOptions,
|
||||
final Collection<CodeValueData> yesNoOptions,
|
||||
final Collection<CodeValueData> accountTypeOptions, final Collection<CodeValueData> customerSegmentOptions,
|
||||
final String accountMappingForPayment) {
|
||||
return template(currency, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, accountingRule, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationTypeOption,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions,
|
||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, yesNoOptions,
|
||||
accountTypeOptions, customerSegmentOptions, accountMappingForPayment, null);
|
||||
}
|
||||
|
||||
public static SavingsProductData withCharges(final SavingsProductData product, final Collection<ChargeData> charges) {
|
||||
return new SavingsProductData(product.id, product.name, product.shortName, product.description, product.currency,
|
||||
SavingsProductData newData = new SavingsProductData(product.id, product.name, product.shortName, product.description, product.currency,
|
||||
product.nominalAnnualInterestRate, product.interestCompoundingPeriodType, product.interestPostingPeriodType,
|
||||
product.interestCalculationType, product.interestCalculationDaysInYearType, product.minRequiredOpeningBalance,
|
||||
product.lockinPeriodFrequency, product.lockinPeriodFrequencyType, product.withdrawalFeeForTransfers, product.accountingRule,
|
||||
product.accountingMappings, product.paymentChannelToFundSourceMappings, product.currencyOptions,
|
||||
product.interestCompoundingPeriodTypeOptions, product.interestPostingPeriodTypeOptions,
|
||||
product.interestCalculationTypeOptions, product.interestCalculationDaysInYearTypeOptions,
|
||||
product.lockinPeriodFrequencyTypeOptions, product.withdrawalFeeTypeOptions, product.paymentTypeOptions,
|
||||
product.interestCalculationTypeOptions, product.interestCalculationTypeOption, product.interestCalculationDaysInYearTypeOptions,
|
||||
product.lockinPeriodFrequencyTypeOptions, product.withdrawalFeeTypeOptions, product.periodFrequencyOptions,
|
||||
product.paymentTypeOptions,
|
||||
product.accountingRuleOptions, product.accountingMappingOptions, charges, product.chargeOptions, product.penaltyOptions,
|
||||
product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings, product.allowOverdraft, product.overdraftLimit,
|
||||
product.minRequiredBalance, product.enforceMinRequiredBalance, product.maxAllowedLienLimit, product.lienAllowed,
|
||||
product.minBalanceForInterestCalculation, product.nominalAnnualInterestRateOverdraft,
|
||||
product.minOverdraftForInterestCalculation, product.withHoldTax, product.taxGroup, product.taxGroupOptions,
|
||||
product.isDormancyTrackingActive, product.daysToInactive, product.daysToDormancy, product.daysToEscheat,
|
||||
product.accountMappingForPayment);
|
||||
product.yesNoOptions, product.accountTypeOptions, product.customerSegmentOptions, product.isDormancyTrackingActive,
|
||||
product.daysToInactive,
|
||||
product.daysToDormancy, product.daysToEscheat, product.accountMappingForPayment, product.otherGlMappings);
|
||||
// Copy enhanced custom fields
|
||||
copyCustomFields(product, newData);
|
||||
return newData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,27 +263,57 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, Collection<TaxGroupData> taxGroupOptions, final String accountMappingForPayment) {
|
||||
final Collection<ChargeData> penaltyOptions, Collection<TaxGroupData> taxGroupOptions,
|
||||
final Collection<CodeValueData> yesNoOptions,
|
||||
final Collection<CodeValueData> accountTypeOptions, final Collection<CodeValueData> customerSegmentOptions,
|
||||
final String accountMappingForPayment, final List<Map<String, Object>> otherGlMappings) {
|
||||
|
||||
return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
SavingsProductData newData = new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeForTransfers,
|
||||
existingProduct.accountingRule, existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings,
|
||||
currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, existingProduct.charges,
|
||||
chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings, existingProduct.allowOverdraft,
|
||||
existingProduct.overdraftLimit, existingProduct.minRequiredBalance, existingProduct.enforceMinRequiredBalance,
|
||||
existingProduct.maxAllowedLienLimit, existingProduct.lienAllowed, existingProduct.minBalanceForInterestCalculation,
|
||||
existingProduct.nominalAnnualInterestRateOverdraft, existingProduct.minOverdraftForInterestCalculation,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, taxGroupOptions, existingProduct.isDormancyTrackingActive,
|
||||
existingProduct.daysToInactive, existingProduct.daysToDormancy, existingProduct.daysToEscheat, accountMappingForPayment);
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, taxGroupOptions, yesNoOptions, accountTypeOptions,
|
||||
customerSegmentOptions, existingProduct.isDormancyTrackingActive, existingProduct.daysToInactive, existingProduct.daysToDormancy,
|
||||
existingProduct.daysToEscheat, accountMappingForPayment, existingProduct.otherGlMappings);
|
||||
copyCustomFields(existingProduct, newData);
|
||||
return newData;
|
||||
}
|
||||
|
||||
public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection<CurrencyData> currencyOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
|
||||
final Collection<ChargeData> penaltyOptions, Collection<TaxGroupData> taxGroupOptions,
|
||||
final Collection<CodeValueData> yesNoOptions,
|
||||
final Collection<CodeValueData> accountTypeOptions, final Collection<CodeValueData> customerSegmentOptions,
|
||||
final String accountMappingForPayment) {
|
||||
return withTemplate(existingProduct, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions,
|
||||
customerSegmentOptions, accountMappingForPayment, existingProduct.otherGlMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData withAccountingDetails(final SavingsProductData existingProduct,
|
||||
@@ -228,31 +325,42 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
|
||||
return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeForTransfers,
|
||||
existingProduct.accountingRule, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, existingProduct.allowOverdraft, existingProduct.overdraftLimit,
|
||||
existingProduct.minRequiredBalance, existingProduct.enforceMinRequiredBalance, existingProduct.maxAllowedLienLimit,
|
||||
existingProduct.lienAllowed, existingProduct.minBalanceForInterestCalculation,
|
||||
existingProduct.nominalAnnualInterestRateOverdraft, existingProduct.minOverdraftForInterestCalculation,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions,
|
||||
existingProduct.isDormancyTrackingActive, existingProduct.daysToInactive, existingProduct.daysToDormancy,
|
||||
existingProduct.daysToEscheat, existingProduct.accountMappingForPayment);
|
||||
SavingsProductData newData = new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance, existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeForTransfers, existingProduct.accountingRule, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, existingProduct.allowOverdraft, existingProduct.overdraftLimit, existingProduct.minRequiredBalance, existingProduct.enforceMinRequiredBalance, existingProduct.maxAllowedLienLimit, existingProduct.lienAllowed, existingProduct.minBalanceForInterestCalculation, existingProduct.nominalAnnualInterestRateOverdraft, existingProduct.minOverdraftForInterestCalculation, existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions, existingProduct.yesNoOptions, existingProduct.accountTypeOptions, existingProduct.customerSegmentOptions, existingProduct.isDormancyTrackingActive, existingProduct.daysToInactive, existingProduct.daysToDormancy, existingProduct.daysToEscheat, existingProduct.accountMappingForPayment, existingProduct.otherGlMappings); copyCustomFields(existingProduct, newData); return newData;
|
||||
}
|
||||
|
||||
private static void copyCustomFields(SavingsProductData source, SavingsProductData target) {
|
||||
target.setAccountType(source.getAccountType());
|
||||
target.setCustomerSegment(source.getCustomerSegment());
|
||||
target.setProductCode(source.getProductCode());
|
||||
target.setEffectiveDate(source.getEffectiveDate());
|
||||
target.setEffectiveTo(source.getEffectiveTo());
|
||||
target.setEndDate(source.getEndDate());
|
||||
target.setIntroducerRequired(source.getIntroducerRequired());
|
||||
target.setShareLinkingEnabled(source.getShareLinkingEnabled());
|
||||
target.setNominationFacility(source.getNominationFacility());
|
||||
target.setDormancyAlert(source.getDormancyAlert());
|
||||
target.setInterestCalculateSelector(source.getInterestCalculateSelector());
|
||||
target.setAveragePeriod(source.getAveragePeriod());
|
||||
target.setAutoPost(source.getAutoPost());
|
||||
target.setFrequencyFixDay(source.getFrequencyFixDay());
|
||||
target.setLastInterestDate(source.getLastInterestDate());
|
||||
target.setEnableLockinPeriod(source.getEnableLockinPeriod());
|
||||
target.setBalanceFrequency(source.getBalanceFrequency());
|
||||
target.setAccountClosedZeroBalanceInDayClosing(source.getAccountClosedZeroBalanceInDayClosing());
|
||||
target.setAccountFacilityConfig(source.getAccountFacilityConfig());
|
||||
target.setAccountFacilityLimits(source.getAccountFacilityLimits());
|
||||
target.setDepositLimitKyc(source.getDepositLimitKyc());
|
||||
}
|
||||
|
||||
public static SavingsProductData instance(final Long id, final String name, final String shortName, final String description,
|
||||
@@ -264,8 +372,10 @@ public final class SavingsProductData implements Serializable {
|
||||
final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance, final BigDecimal maxAllowedLienLimit,
|
||||
final boolean lienAllowed, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation,
|
||||
final boolean withHoldTax, final TaxGroupData taxGroup, final Boolean isDormancyTrackingActive, final Long daysToInactive,
|
||||
final Long daysToDormancy, final Long daysToEscheat) {
|
||||
final boolean withHoldTax, final TaxGroupData taxGroup, final Collection<CodeValueData> yesNoOptions,
|
||||
final Collection<CodeValueData> accountTypeOptions, final Collection<CodeValueData> customerSegmentOptions,
|
||||
final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat,
|
||||
final List<Map<String, Object>> otherGlMappings) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
@@ -274,9 +384,11 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
@@ -292,12 +404,14 @@ public final class SavingsProductData implements Serializable {
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingType, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions,
|
||||
charges, chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
|
||||
minRequiredBalance, enforceMinRequiredBalance, maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions,
|
||||
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, accountMappingForPayment);
|
||||
yesNoOptions, accountTypeOptions, customerSegmentOptions, isDormancyTrackingActive, daysToInactive, daysToDormancy,
|
||||
daysToEscheat, accountMappingForPayment, otherGlMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData lookup(final Long id, final String name) {
|
||||
@@ -333,9 +447,11 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = null;
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = null;
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
@@ -345,22 +461,28 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
final Collection<TaxGroupData> taxGroupOptions = null;
|
||||
final Collection<CodeValueData> yesNoOptions = null;
|
||||
final Collection<CodeValueData> accountTypeOptions = null;
|
||||
final Collection<CodeValueData> customerSegmentOptions = null;
|
||||
final Boolean isDormancyTrackingActive = null;
|
||||
final Long daysToInactive = null;
|
||||
final Long daysToDormancy = null;
|
||||
final Long daysToEscheat = null;
|
||||
final String accountMappingForPayment = null;
|
||||
final List<Map<String, Object>> otherGlMappings = null;
|
||||
|
||||
return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingType, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges,
|
||||
chargeOptions,
|
||||
penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
|
||||
minRequiredBalance, enforceMinRequiredBalance, maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions,
|
||||
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, accountMappingForPayment);
|
||||
yesNoOptions, accountTypeOptions, customerSegmentOptions, isDormancyTrackingActive, daysToInactive, daysToDormancy,
|
||||
daysToEscheat, accountMappingForPayment, otherGlMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData createForInterestPosting(final Long id, final EnumOptionData accountingRule) {
|
||||
@@ -388,9 +510,11 @@ public final class SavingsProductData implements Serializable {
|
||||
this.interestCompoundingPeriodTypeOptions = null;
|
||||
this.interestPostingPeriodTypeOptions = null;
|
||||
this.interestCalculationTypeOptions = null;
|
||||
this.interestCalculationTypeOption = null;
|
||||
this.interestCalculationDaysInYearTypeOptions = null;
|
||||
this.lockinPeriodFrequencyTypeOptions = null;
|
||||
this.withdrawalFeeTypeOptions = null;
|
||||
this.periodFrequencyOptions = null;
|
||||
|
||||
this.paymentTypeOptions = null;
|
||||
this.accountingMappingOptions = null;
|
||||
@@ -419,10 +543,14 @@ public final class SavingsProductData implements Serializable {
|
||||
this.taxGroup = null;
|
||||
this.withHoldTax = false;
|
||||
this.taxGroupOptions = null;
|
||||
this.yesNoOptions = null;
|
||||
this.accountTypeOptions = null;
|
||||
this.customerSegmentOptions = null;
|
||||
this.isDormancyTrackingActive = null;
|
||||
this.daysToInactive = null;
|
||||
this.daysToDormancy = null;
|
||||
this.daysToEscheat = null;
|
||||
this.otherGlMappings = null;
|
||||
this.accountMappingForPayment = null;
|
||||
}
|
||||
|
||||
@@ -436,9 +564,11 @@ public final class SavingsProductData implements Serializable {
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||
final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
@@ -447,8 +577,10 @@ public final class SavingsProductData implements Serializable {
|
||||
final BigDecimal maxAllowedLienLimit, final boolean lienAllowed, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation,
|
||||
final boolean withHoldTax, final TaxGroupData taxGroup, final Collection<TaxGroupData> taxGroupOptions,
|
||||
final Collection<CodeValueData> yesNoOptions, final Collection<CodeValueData> accountTypeOptions,
|
||||
final Collection<CodeValueData> customerSegmentOptions,
|
||||
final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat,
|
||||
final String accountMappingForPayment) {
|
||||
final String accountMappingForPayment, final List<Map<String, Object>> otherGlMappings) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -469,9 +601,11 @@ public final class SavingsProductData implements Serializable {
|
||||
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
|
||||
this.interestCalculationTypeOption = interestCalculationTypeOption;
|
||||
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
|
||||
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
||||
this.periodFrequencyOptions = periodFrequencyOptions;
|
||||
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.accountingMappingOptions = accountingMappingOptions;
|
||||
@@ -503,11 +637,15 @@ public final class SavingsProductData implements Serializable {
|
||||
this.taxGroup = taxGroup;
|
||||
this.withHoldTax = withHoldTax;
|
||||
this.taxGroupOptions = taxGroupOptions;
|
||||
this.yesNoOptions = yesNoOptions;
|
||||
this.accountTypeOptions = accountTypeOptions;
|
||||
this.customerSegmentOptions = customerSegmentOptions;
|
||||
this.isDormancyTrackingActive = isDormancyTrackingActive;
|
||||
this.daysToInactive = daysToInactive;
|
||||
this.daysToDormancy = daysToDormancy;
|
||||
this.daysToEscheat = daysToEscheat;
|
||||
this.accountMappingForPayment = accountMappingForPayment;
|
||||
this.otherGlMappings = otherGlMappings;
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
@@ -547,4 +685,8 @@ public final class SavingsProductData implements Serializable {
|
||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().toString().equals(this.accountingRule.getValue());
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getOtherGlMappings() {
|
||||
return this.otherGlMappings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ tasks.register('devRun', org.springframework.boot.gradle.tasks.run.BootRun) {
|
||||
description = 'Runs the application quickly for development by skipping quality checks'
|
||||
group = 'Application'
|
||||
|
||||
// Configure the build to skip quality checks
|
||||
// Configure the build to skip quality checks and resolve tasks
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
if (graph.hasTask(devRun)) {
|
||||
tasks.matching { task ->
|
||||
@@ -377,7 +377,10 @@ tasks.register('devRun', org.springframework.boot.gradle.tasks.run.BootRun) {
|
||||
'spotbugsMain', 'spotbugsTest',
|
||||
'javadoc', 'javadocJar',
|
||||
'modernizer',
|
||||
'testClasses']
|
||||
'testClasses',
|
||||
'compileTestJava',
|
||||
'test',
|
||||
'resolve']
|
||||
}.configureEach {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1523
-5199
File diff suppressed because it is too large
Load Diff
+30
-6
@@ -36,6 +36,7 @@ import jakarta.ws.rs.core.UriInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
|
||||
@@ -49,6 +50,8 @@ import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
@@ -62,6 +65,7 @@ import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService;
|
||||
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
|
||||
@@ -94,6 +98,7 @@ public class CurrentProductsApiResource {
|
||||
private final PaymentTypeReadService paymentTypeReadPlatformService;
|
||||
private final TaxReadPlatformService taxReadPlatformService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@@ -181,6 +186,21 @@ public class CurrentProductsApiResource {
|
||||
return toApiJsonSerializer.serialize(settings, savingProduct, SavingsApiSetConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrievePeriodFrequencyOptions() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.PERIOD_FREQUENCY).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"periodFrequencyType." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'), codeValue.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrieveInterestCalculationTypeOption() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.INTEREST_CALCULATION_TYPE_OPTION).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"interestCalculationTypeOption." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'),
|
||||
codeValue.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{productId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@@ -221,11 +241,13 @@ public class CurrentProductsApiResource {
|
||||
.retrieveInterestPostingPeriodTypeOptions();
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestCalculationTypeOptions();
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = retrieveInterestCalculationTypeOption();
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestCalculationDaysInYearTypeOptions();
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = dropdownReadPlatformService
|
||||
.retrieveLockinPeriodFrequencyTypeOptions();
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = retrievePeriodFrequencyOptions();
|
||||
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
|
||||
@@ -247,16 +269,18 @@ public class CurrentProductsApiResource {
|
||||
SavingsProductData savingsProductToReturn = null;
|
||||
if (savingsProduct != null) {
|
||||
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, accountMappingForPayment);
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationTypeOption,
|
||||
interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, null, null, null,
|
||||
accountMappingForPayment);
|
||||
} else {
|
||||
savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, accountingRule, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions,
|
||||
accountMappingForPayment);
|
||||
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
||||
penaltyOptions, taxGroupOptions, null, null, null, accountMappingForPayment);
|
||||
}
|
||||
|
||||
return savingsProductToReturn;
|
||||
|
||||
+36
-5
@@ -40,6 +40,7 @@ import jakarta.ws.rs.core.UriInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
|
||||
@@ -56,6 +57,8 @@ import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDoma
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
@@ -91,6 +94,7 @@ public class SavingsProductsApiResource {
|
||||
private final CurrencyReadPlatformService currencyReadPlatformService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final DefaultToApiJsonSerializer<SavingsProductData> toApiJsonSerializer;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
@@ -242,6 +246,7 @@ public class SavingsProductsApiResource {
|
||||
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = this.dropdownReadPlatformService
|
||||
.retrieveInterestCalculationTypeOptions();
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = retrieveInterestCalculationTypeOption();
|
||||
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = this.dropdownReadPlatformService
|
||||
.retrieveInterestCalculationDaysInYearTypeOptions();
|
||||
@@ -250,6 +255,7 @@ public class SavingsProductsApiResource {
|
||||
.retrieveLockinPeriodFrequencyTypeOptions();
|
||||
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = retrievePeriodFrequencyOptions();
|
||||
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
|
||||
@@ -268,24 +274,49 @@ public class SavingsProductsApiResource {
|
||||
Collection<ChargeData> penaltyOptions = this.chargeReadPlatformService.retrieveSavingsApplicablePenalties();
|
||||
penaltyOptions = CollectionUtils.isEmpty(penaltyOptions) ? null : penaltyOptions;
|
||||
final Collection<TaxGroupData> taxGroupOptions = this.taxReadPlatformService.retrieveTaxGroupsForLookUp();
|
||||
final List<CodeValueData> yesNoOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.YES_NO));
|
||||
final List<CodeValueData> accountTypeOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.SAVINGS_PRODUCT_ACCOUNT_TYPE));
|
||||
final List<CodeValueData> customerSegmentOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.SAVINGS_PRODUCT_CUSTOMER_SEGMENT));
|
||||
SavingsProductData savingsProductToReturn = null;
|
||||
if (savingsProduct != null) {
|
||||
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, accountMappingForPayment);
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationTypeOption,
|
||||
interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, periodFrequencyOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, yesNoOptions,
|
||||
accountTypeOptions, customerSegmentOptions,
|
||||
accountMappingForPayment);
|
||||
} else {
|
||||
savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, accountingRule, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions,
|
||||
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
||||
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions,
|
||||
accountMappingForPayment);
|
||||
}
|
||||
|
||||
return savingsProductToReturn;
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrievePeriodFrequencyOptions() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.PERIOD_FREQUENCY).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"periodFrequencyType." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'), codeValue.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrieveInterestCalculationTypeOption() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.INTEREST_CALCULATION_TYPE_OPTION).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"interestCalculationTypeOption." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'),
|
||||
codeValue.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{productId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
|
||||
+51
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.api;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -82,6 +83,7 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public Boolean withHoldTax;
|
||||
@Schema(example = "false")
|
||||
public Boolean isDormancyTrackingActive;
|
||||
public List<Map<String, Object>> otherGlMappings;
|
||||
}
|
||||
|
||||
@Schema(description = "PostSavingsProductsResponse")
|
||||
@@ -128,6 +130,25 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public PutSavingsChanges changes;
|
||||
}
|
||||
|
||||
@Schema(description = "GetSavingsProductsProductClassificationOptions")
|
||||
static final class GetSavingsProductsProductClassificationOptions {
|
||||
|
||||
private GetSavingsProductsProductClassificationOptions() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long id;
|
||||
@Schema(example = "Savings Account Minor")
|
||||
public String name;
|
||||
@Schema(example = "1")
|
||||
public Integer position;
|
||||
@Schema(example = "Savings Account Minor")
|
||||
public String description;
|
||||
@Schema(example = "true")
|
||||
public Boolean active;
|
||||
@Schema(example = "false")
|
||||
public Boolean mandatory;
|
||||
}
|
||||
|
||||
@Schema(description = "GetSavingsProductsResponse")
|
||||
public static final class GetSavingsProductsResponse {
|
||||
|
||||
@@ -377,6 +398,7 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public Set<GetSavingsProductsPenaltyToIncomeAccountMappings> penaltyToIncomeAccountMappings;
|
||||
@Schema(example = "[]")
|
||||
public List<Long> charges;
|
||||
public List<Map<String, Object>> otherGlMappings;
|
||||
}
|
||||
|
||||
@Schema(description = "GetSavingsProductsTemplateResponse")
|
||||
@@ -408,6 +430,30 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public String value;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsPeriodFrequencyOptions {
|
||||
|
||||
private GetSavingsProductsPeriodFrequencyOptions() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Integer id;
|
||||
@Schema(example = "periodFrequencyType.monthly")
|
||||
public String code;
|
||||
@Schema(example = "Monthly")
|
||||
public String value;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsInterestCalculationTypeOption {
|
||||
|
||||
private GetSavingsProductsInterestCalculationTypeOption() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Integer id;
|
||||
@Schema(example = "interestCalculationTypeOption.compounding")
|
||||
public String code;
|
||||
@Schema(example = "Compounding")
|
||||
public String value;
|
||||
}
|
||||
|
||||
static final class GetSavingsProductsWithdrawalFeeTypeOptions {
|
||||
|
||||
private GetSavingsProductsWithdrawalFeeTypeOptions() {}
|
||||
@@ -677,13 +723,18 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public Set<GetSavingsProductsResponse.GetSavingsProductsInterestCompoundingPeriodType> interestCompoundingPeriodTypeOptions;
|
||||
public Set<GetSavingsProductsResponse.GetSavingsProductsInterestPostingPeriodType> interestPostingPeriodTypeOptions;
|
||||
public Set<GetSavingsProductsResponse.GetSavingsProductsInterestCalculationType> interestCalculationTypeOptions;
|
||||
public Set<GetSavingsProductsInterestCalculationTypeOption> interestCalculationTypeOption;
|
||||
public Set<GetSavingsProductsResponse.GetSavingsProductsInterestCalculationDaysInYearType> interestCalculationDaysInYearTypeOptions;
|
||||
public Set<GetSavingsProductsLockinPeriodFrequencyTypeOptions> lockinPeriodFrequencyTypeOptions;
|
||||
public Set<GetSavingsProductsWithdrawalFeeTypeOptions> withdrawalFeeTypeOptions;
|
||||
public Set<GetSavingsProductsPeriodFrequencyOptions> periodFrequencyOptions;
|
||||
public Set<GetSavingsProductsPaymentTypeOptions> paymentTypeOptions;
|
||||
public Set<GetSavingsProductsTemplateAccountingRule> accountingRuleOptions;
|
||||
public GetSavingsProductsAccountingMappingOptions accountingMappingOptions;
|
||||
public Set<GetSavingsProductsChargeOptions> chargeOptions;
|
||||
public Set<GetSavingsProductsProductClassificationOptions> yesNoOptions;
|
||||
public Set<GetSavingsProductsProductClassificationOptions> accountTypeOptions;
|
||||
public Set<GetSavingsProductsProductClassificationOptions> customerSegmentOptions;
|
||||
public GetSavingsProductsResponse.GetSavingsCurrency accountMapping;
|
||||
|
||||
}
|
||||
|
||||
+124
-5
@@ -18,10 +18,16 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.service;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.math.BigDecimal;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingEnumerations;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
@@ -32,6 +38,12 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductData;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKyc;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKycRepository;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
@@ -46,6 +58,11 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
private final SavingProductMapper savingsProductRowMapper = new SavingProductMapper();
|
||||
private final SavingProductLookupMapper savingsProductLookupsRowMapper = new SavingProductLookupMapper();
|
||||
private final FineractEntityAccessUtil fineractEntityAccessUtil;
|
||||
private final SavingsProductFacilityConfigRepository facilityConfigRepository;
|
||||
private final SavingsProductFacilityLimitRepository facilityLimitRepository;
|
||||
private final SavingsProductDepositLimitKycRepository depositLimitKycRepository;
|
||||
private static final Gson GSON = new Gson();
|
||||
private static final Type OTHER_GL_MAPPINGS_TYPE = new TypeToken<List<Map<String, Object>>>() {}.getType();
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductData> retrieveAll() {
|
||||
@@ -87,8 +104,66 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
final String sql = "select " + this.savingsProductRowMapper.schema() + " where sp.id = ? and sp.deposit_type_enum = ?";
|
||||
return this.jdbcTemplate.queryForObject(sql, this.savingsProductRowMapper, // NOSONAR
|
||||
SavingsProductData product = this.jdbcTemplate.queryForObject(sql, this.savingsProductRowMapper, // NOSONAR
|
||||
new Object[] { savingProductId, DepositAccountType.SAVINGS_DEPOSIT.getValue() });
|
||||
|
||||
// Fetch related data using repositories
|
||||
if (product != null) {
|
||||
// Fetch Facility Config using repository
|
||||
SavingsProductFacilityConfig facilityConfig = facilityConfigRepository.findBySavingsProductId(savingProductId);
|
||||
if (facilityConfig != null) {
|
||||
Map<String, Object> facilityConfigMap = new HashMap<>();
|
||||
facilityConfigMap.put("atmFacility", facilityConfig.getAtmFacility());
|
||||
facilityConfigMap.put("atmWithdrawalFacility", facilityConfig.getAtmWithdrawalFacility());
|
||||
facilityConfigMap.put("upiFacility", facilityConfig.getUpiFacility());
|
||||
facilityConfigMap.put("posTransactionsFacility", facilityConfig.getPosTransactionsFacility());
|
||||
facilityConfigMap.put("chequeBook", facilityConfig.getChequeBook());
|
||||
facilityConfigMap.put("impsFacility", facilityConfig.getImpsFacility());
|
||||
facilityConfigMap.put("smsAlerts", facilityConfig.getSmsAlerts());
|
||||
facilityConfigMap.put("bbpsFacility", facilityConfig.getBbpsFacility());
|
||||
facilityConfigMap.put("insuranceCover", facilityConfig.getInsuranceCover());
|
||||
facilityConfigMap.put("bepgFacility", facilityConfig.getBepgFacility());
|
||||
facilityConfigMap.put("neftFacility", facilityConfig.getNeftFacility());
|
||||
facilityConfigMap.put("rtgsFacility", facilityConfig.getRtgsFacility());
|
||||
facilityConfigMap.put("interBankTotalCapFacility", facilityConfig.getInterBankTotalCapFacility());
|
||||
facilityConfigMap.put("withdrawalFacility", facilityConfig.getWithdrawalFacility());
|
||||
facilityConfigMap.put("depositFacilityKyc", facilityConfig.getDepositFacilityKyc());
|
||||
facilityConfigMap.put("virtualDebitCard", facilityConfig.getVirtualDebitCard());
|
||||
product.setAccountFacilityConfig(facilityConfigMap);
|
||||
}
|
||||
|
||||
// Fetch Facility Limits using repository (1-to-Many Array)
|
||||
List<SavingsProductFacilityLimit> facilityLimits = facilityLimitRepository.findBySavingsProductId(savingProductId);
|
||||
if (facilityLimits != null && !facilityLimits.isEmpty()) {
|
||||
List<Map<String, Object>> limits = facilityLimits.stream().map(limit -> {
|
||||
Map<String, Object> limitMap = new HashMap<>();
|
||||
limitMap.put("limitType", limit.getLimitType());
|
||||
limitMap.put("generalLimit", limit.getGeneralLimit());
|
||||
limitMap.put("minorAccountLimit", limit.getMinorAccountLimit());
|
||||
limitMap.put("smallSavingLimit", limit.getSmallSavingLimit());
|
||||
return limitMap;
|
||||
}).toList();
|
||||
product.setAccountFacilityLimits(limits);
|
||||
}
|
||||
|
||||
// Fetch Deposit Limit KYC using repository
|
||||
SavingsProductDepositLimitKyc depositLimitKyc = depositLimitKycRepository.findBySavingsProductId(savingProductId);
|
||||
if (depositLimitKyc != null) {
|
||||
Map<String, Object> depositLimitKycMap = new HashMap<>();
|
||||
depositLimitKycMap.put("general", Map.of(
|
||||
"kycType", depositLimitKyc.getGeneralKycType() != null ? depositLimitKyc.getGeneralKycType() : "",
|
||||
"limit", depositLimitKyc.getGeneralLimit() != null ? depositLimitKyc.getGeneralLimit() : ""));
|
||||
depositLimitKycMap.put("minor", Map.of(
|
||||
"kycType", depositLimitKyc.getMinorKycType() != null ? depositLimitKyc.getMinorKycType() : "",
|
||||
"limit", depositLimitKyc.getMinorLimit()));
|
||||
depositLimitKycMap.put("smallSaving", Map.of(
|
||||
"kycType", depositLimitKyc.getSmallSavingKycType() != null ? depositLimitKyc.getSmallSavingKycType() : "",
|
||||
"limit", depositLimitKyc.getSmallSavingLimit()));
|
||||
product.setDepositLimitKyc(depositLimitKycMap);
|
||||
}
|
||||
}
|
||||
|
||||
return product;
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new SavingsProductNotFoundException(savingProductId, e);
|
||||
}
|
||||
@@ -99,7 +174,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
private final String schemaSql;
|
||||
|
||||
SavingProductMapper() {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||
final StringBuilder sqlBuilder = new StringBuilder(1000);
|
||||
sqlBuilder.append("sp.id as id, sp.name as name, sp.short_name as shortName, sp.description as description, ");
|
||||
sqlBuilder.append(
|
||||
"sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, sp.currency_multiplesof as inMultiplesOf, ");
|
||||
@@ -129,7 +204,20 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
sqlBuilder.append("sp.is_dormancy_tracking_active as isDormancyTrackingActive,");
|
||||
sqlBuilder.append("sp.days_to_inactive as daysToInactive,");
|
||||
sqlBuilder.append("sp.days_to_dormancy as daysToDormancy,");
|
||||
sqlBuilder.append("sp.days_to_escheat as daysToEscheat ");
|
||||
sqlBuilder.append("sp.days_to_escheat as daysToEscheat, ");
|
||||
sqlBuilder.append("sp.other_gl_mappings as otherGlMappings, ");
|
||||
|
||||
// Enhanced Field Selections
|
||||
sqlBuilder.append("sp.account_type as accountType, sp.customer_segment as customerSegment, sp.product_code as productCode, ");
|
||||
sqlBuilder.append("sp.effective_date as effectiveDate, sp.effective_to as effectiveTo, sp.end_date as endDate, ");
|
||||
sqlBuilder.append("sp.introducer_required as introducerRequired, sp.share_linking_enabled as shareLinkingEnabled, ");
|
||||
sqlBuilder.append("sp.nomination_facility as nominationFacility, sp.dormancy_alert as dormancyAlert, ");
|
||||
sqlBuilder.append("sp.interest_calculate_selector as interestCalculateSelector, sp.average_period as averagePeriod, ");
|
||||
sqlBuilder.append("sp.auto_post as autoPost, sp.frequency_fix_day as frequencyFixDay, sp.last_interest_date as lastInterestDate, ");
|
||||
sqlBuilder.append("sp.enable_lockin_period as enableLockinPeriod, ");
|
||||
sqlBuilder.append("sp.balance_frequency as balanceFrequency, ");
|
||||
sqlBuilder.append("sp.account_closed_zero_balance_in_day_closing as accountClosedZeroBalanceInDayClosing ");
|
||||
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
|
||||
sqlBuilder.append("left join m_tax_group tg on tg.id = sp.tax_group_id ");
|
||||
@@ -212,13 +300,37 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
final Long daysToInactive = JdbcSupport.getLong(rs, "daysToInactive");
|
||||
final Long daysToDormancy = JdbcSupport.getLong(rs, "daysToDormancy");
|
||||
final Long daysToEscheat = JdbcSupport.getLong(rs, "daysToEscheat");
|
||||
final List<Map<String, Object>> otherGlMappings = parseOtherGlMappings(rs.getString("otherGlMappings"));
|
||||
|
||||
return SavingsProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
SavingsProductData productData = SavingsProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
|
||||
accountingRuleType, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, maxAllowedLienLimit,
|
||||
lienAllowed, minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation,
|
||||
withHoldTax, taxGroupData, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
|
||||
withHoldTax, taxGroupData, null, null, null, isDormancyTrackingActive, daysToInactive, daysToDormancy,
|
||||
daysToEscheat, otherGlMappings);
|
||||
|
||||
// Populate Enhanced Fields
|
||||
productData.setAccountType(rs.getString("accountType"));
|
||||
productData.setCustomerSegment(rs.getString("customerSegment"));
|
||||
productData.setProductCode(rs.getString("productCode"));
|
||||
productData.setEffectiveDate(JdbcSupport.getLocalDate(rs, "effectiveDate"));
|
||||
productData.setEffectiveTo(JdbcSupport.getLocalDate(rs, "effectiveTo"));
|
||||
productData.setEndDate(JdbcSupport.getLocalDate(rs, "endDate"));
|
||||
productData.setIntroducerRequired(rs.getBoolean("introducerRequired"));
|
||||
productData.setShareLinkingEnabled(rs.getBoolean("shareLinkingEnabled"));
|
||||
productData.setNominationFacility(rs.getBoolean("nominationFacility"));
|
||||
productData.setDormancyAlert(rs.getBoolean("dormancyAlert"));
|
||||
productData.setInterestCalculateSelector(JdbcSupport.getInteger(rs, "interestCalculateSelector"));
|
||||
productData.setAveragePeriod(rs.getString("averagePeriod"));
|
||||
productData.setAutoPost(rs.getBoolean("autoPost"));
|
||||
productData.setFrequencyFixDay(JdbcSupport.getInteger(rs, "frequencyFixDay"));
|
||||
productData.setLastInterestDate(JdbcSupport.getLocalDate(rs, "lastInterestDate"));
|
||||
productData.setEnableLockinPeriod(rs.getBoolean("enableLockinPeriod"));
|
||||
productData.setBalanceFrequency(rs.getString("balanceFrequency"));
|
||||
productData.setAccountClosedZeroBalanceInDayClosing(rs.getBoolean("accountClosedZeroBalanceInDayClosing"));
|
||||
|
||||
return productData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +350,13 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> parseOtherGlMappings(final String otherGlMappingsJson) {
|
||||
if (otherGlMappingsJson == null || otherGlMappingsJson.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return GSON.fromJson(otherGlMappingsJson, OTHER_GL_MAPPINGS_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductData> retrieveAllForLookupByType(Boolean isOverdraftType) {
|
||||
String sql = "select " + this.savingsProductLookupsRowMapper.schema();
|
||||
|
||||
+95
-1
@@ -28,6 +28,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
@@ -46,11 +47,18 @@ import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductDataValidator;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKyc;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKycRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductAssembler;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductAssembler;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -64,6 +72,9 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final SavingsProductAssembler savingsProductAssembler;
|
||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||
private final FineractEntityAccessUtil fineractEntityAccessUtil;
|
||||
private final SavingsProductFacilityConfigRepository facilityConfigRepository;
|
||||
private final SavingsProductFacilityLimitRepository facilityLimitRepository;
|
||||
private final SavingsProductDepositLimitKycRepository depositLimitKycRepository;
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
||||
@@ -86,8 +97,15 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
msg = "Savings product with short name `" + shortName + "` already exists";
|
||||
param = "shortName";
|
||||
msgArgs = new Object[] { shortName, dae };
|
||||
} else if (checkEx.getMessage().contains("product_code") || checkEx.getMessage().contains("sp_unq_product_code")) {
|
||||
final String productCode = command.stringValueOfParameterNamed("productCode");
|
||||
msgCode += ".duplicate.product.code";
|
||||
msg = "Savings product with product code `" + productCode + "` already exists";
|
||||
param = "productCode";
|
||||
msgArgs = new Object[] { productCode, dae };
|
||||
} else {
|
||||
msgCode += ".unknown.data.integrity.issue";
|
||||
msg = "Unknown data integrity issue with savings product. Details: " + checkEx.getMessage();
|
||||
msgArgs = new Object[] { dae };
|
||||
}
|
||||
log.error("Error occured.", dae);
|
||||
@@ -103,8 +121,29 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsProduct product = this.savingsProductAssembler.assemble(command);
|
||||
|
||||
// Assemble and save new complex objects
|
||||
final SavingsProductFacilityConfig facilityConfig =
|
||||
this.savingsProductAssembler.assembleAccountFacilityConfig(command, product);
|
||||
final Set<SavingsProductFacilityLimit> facilityLimits =
|
||||
this.savingsProductAssembler.assembleAccountFacilityLimits(command, product);
|
||||
final SavingsProductDepositLimitKyc depositLimitKyc =
|
||||
this.savingsProductAssembler.assembleDepositLimitKyc(command, product);
|
||||
|
||||
this.savingProductRepository.saveAndFlush(product);
|
||||
|
||||
// Save related entities
|
||||
if (facilityConfig != null) {
|
||||
this.facilityConfigRepository.saveAndFlush(facilityConfig);
|
||||
}
|
||||
|
||||
if (!facilityLimits.isEmpty()) {
|
||||
this.facilityLimitRepository.saveAll(facilityLimits);
|
||||
}
|
||||
|
||||
if (depositLimitKyc != null) {
|
||||
this.depositLimitKycRepository.saveAndFlush(depositLimitKyc);
|
||||
}
|
||||
|
||||
// save accounting mappings
|
||||
this.accountMappingWritePlatformService.createSavingProductToGLAccountMapping(product.getId(), command,
|
||||
DepositAccountType.SAVINGS_DEPOSIT);
|
||||
@@ -162,6 +201,61 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
}
|
||||
}
|
||||
|
||||
// Update facility config
|
||||
final SavingsProductFacilityConfig existingFacilityConfig = product.getFacilityConfig();
|
||||
final SavingsProductFacilityConfig newFacilityConfig =
|
||||
this.savingsProductAssembler.assembleAccountFacilityConfig(command, product);
|
||||
|
||||
if (newFacilityConfig != null) {
|
||||
if (existingFacilityConfig != null) {
|
||||
// Update existing config
|
||||
existingFacilityConfig.updateFrom(newFacilityConfig);
|
||||
this.facilityConfigRepository.saveAndFlush(existingFacilityConfig);
|
||||
} else {
|
||||
// Create new config
|
||||
this.facilityConfigRepository.saveAndFlush(newFacilityConfig);
|
||||
}
|
||||
} else if (existingFacilityConfig != null) {
|
||||
// Delete existing config if not provided in update
|
||||
this.facilityConfigRepository.delete(existingFacilityConfig);
|
||||
}
|
||||
|
||||
// Update facility limits (delete old, insert new)
|
||||
final Set<SavingsProductFacilityLimit> newFacilityLimits =
|
||||
this.savingsProductAssembler.assembleAccountFacilityLimits(command, product);
|
||||
|
||||
if (!newFacilityLimits.isEmpty() || command.hasParameter("accountFacilityLimits")) {
|
||||
// Delete existing limits
|
||||
if (product.getFacilityLimits() != null && !product.getFacilityLimits().isEmpty()) {
|
||||
this.facilityLimitRepository.deleteAll(product.getFacilityLimits());
|
||||
product.getFacilityLimits().clear();
|
||||
}
|
||||
// Save new limits
|
||||
if (!newFacilityLimits.isEmpty()) {
|
||||
this.facilityLimitRepository.saveAll(newFacilityLimits);
|
||||
product.setFacilityLimits(newFacilityLimits);
|
||||
}
|
||||
}
|
||||
|
||||
// Update deposit limit KYC
|
||||
final SavingsProductDepositLimitKyc existingDepositLimitKyc = product.getDepositLimitKyc();
|
||||
final SavingsProductDepositLimitKyc newDepositLimitKyc =
|
||||
this.savingsProductAssembler.assembleDepositLimitKyc(command, product);
|
||||
|
||||
if (newDepositLimitKyc != null) {
|
||||
if (existingDepositLimitKyc != null) {
|
||||
// Update existing KYC
|
||||
existingDepositLimitKyc.updateFrom(newDepositLimitKyc);
|
||||
this.depositLimitKycRepository.saveAndFlush(existingDepositLimitKyc);
|
||||
} else {
|
||||
// Create new KYC
|
||||
this.depositLimitKycRepository.saveAndFlush(newDepositLimitKyc);
|
||||
}
|
||||
} else if (existingDepositLimitKyc != null) {
|
||||
// Delete existing KYC if not provided in update
|
||||
this.depositLimitKycRepository.delete(existingDepositLimitKyc);
|
||||
}
|
||||
|
||||
// accounting related changes
|
||||
final boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName);
|
||||
final Map<String, Object> accountingMappingChanges = this.accountMappingWritePlatformService
|
||||
|
||||
+19
-6
@@ -91,6 +91,11 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrap
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsHelper;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductAssembler;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKycRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformServiceImpl;
|
||||
@@ -414,19 +419,27 @@ public class SavingsConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SavingsProductReadPlatformService.class)
|
||||
public SavingsProductReadPlatformService savingsProductReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate,
|
||||
FineractEntityAccessUtil fineractEntityAccessUtil) {
|
||||
return new SavingsProductReadPlatformServiceImpl(context, jdbcTemplate, fineractEntityAccessUtil);
|
||||
FineractEntityAccessUtil fineractEntityAccessUtil, SavingsProductFacilityConfigRepository facilityConfigRepository,
|
||||
SavingsProductFacilityLimitRepository facilityLimitRepository, SavingsProductDepositLimitKycRepository depositLimitKycRepository) {
|
||||
return new SavingsProductReadPlatformServiceImpl(context, jdbcTemplate, fineractEntityAccessUtil, facilityConfigRepository,
|
||||
facilityLimitRepository, depositLimitKycRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SavingsProductWritePlatformService.class)
|
||||
public SavingsProductWritePlatformService savingsProductWritePlatformService(PlatformSecurityContext context,
|
||||
SavingsProductRepository savingProductRepository, SavingsProductDataValidator fromApiJsonDataValidator,
|
||||
public SavingsProductWritePlatformService savingsProductWritePlatformService(
|
||||
PlatformSecurityContext context,
|
||||
SavingsProductRepository savingProductRepository,
|
||||
SavingsProductDataValidator fromApiJsonDataValidator,
|
||||
SavingsProductAssembler savingsProductAssembler,
|
||||
ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
|
||||
FineractEntityAccessUtil fineractEntityAccessUtil) {
|
||||
FineractEntityAccessUtil fineractEntityAccessUtil,
|
||||
SavingsProductFacilityConfigRepository facilityConfigRepository,
|
||||
SavingsProductFacilityLimitRepository facilityLimitRepository,
|
||||
SavingsProductDepositLimitKycRepository depositLimitKycRepository) {
|
||||
return new SavingsProductWritePlatformServiceJpaRepositoryImpl(context, savingProductRepository, fromApiJsonDataValidator,
|
||||
savingsProductAssembler, accountMappingWritePlatformService, fineractEntityAccessUtil);
|
||||
savingsProductAssembler, accountMappingWritePlatformService, fineractEntityAccessUtil, facilityConfigRepository,
|
||||
facilityLimitRepository, depositLimitKycRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -44,7 +44,7 @@ fineract.security.oauth2.client.registrations.frontend-client.require-authorizat
|
||||
fineract.tenant.host=${FINERACT_DEFAULT_TENANTDB_HOSTNAME:localhost}
|
||||
fineract.tenant.port=${FINERACT_DEFAULT_TENANTDB_PORT:5432}
|
||||
fineract.tenant.username=${FINERACT_DEFAULT_TENANTDB_UID:postgres}
|
||||
fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:root}
|
||||
fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:313863}
|
||||
fineract.tenant.parameters=${FINERACT_DEFAULT_TENANTDB_CONN_PARAMS:}
|
||||
fineract.tenant.timezone=${FINERACT_DEFAULT_TENANTDB_TIMEZONE:Asia/Kolkata}
|
||||
fineract.tenant.identifier=${FINERACT_DEFAULT_TENANTDB_IDENTIFIER:default}
|
||||
@@ -405,7 +405,7 @@ server.tomcat.mbeanregistry.enabled=${FINERACT_SERVER_TOMCAT_MBEANREGISTRY_ENABL
|
||||
spring.datasource.hikari.driverClassName=${FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME:org.postgresql.Driver}
|
||||
spring.datasource.hikari.jdbcUrl=${FINERACT_HIKARI_JDBC_URL:jdbc:postgresql://localhost:5432/fineract_tenants}
|
||||
spring.datasource.hikari.username=${FINERACT_HIKARI_USERNAME:postgres}
|
||||
spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:root}
|
||||
spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:313863}
|
||||
spring.datasource.hikari.minimumIdle=${FINERACT_HIKARI_MINIMUM_IDLE:3}
|
||||
spring.datasource.hikari.maximumPoolSize=${FINERACT_HIKARI_MAXIMUM_POOL_SIZE:10}
|
||||
spring.datasource.hikari.idleTimeout=${FINERACT_HIKARI_IDLE_TIMEOUT:60000}
|
||||
|
||||
@@ -268,4 +268,5 @@
|
||||
<include file="parts/0247_add_huf_client_classification.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0248_add_cin_din_verification_fields.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0249_add_non_person_extended_fields.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0251_add_savings_product_enhanced_fields.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="0250_add_period_frequency_options">
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="PeriodFrequency"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
<insert tableName="m_code_value">
|
||||
<column name="code_id" valueComputed="(SELECT id FROM m_code WHERE code_name = 'PeriodFrequency')"/>
|
||||
<column name="code_value" value="Monthly"/>
|
||||
<column name="code_description" value="Monthly"/>
|
||||
<column name="order_position" valueNumeric="1"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="is_mandatory" valueBoolean="false"/>
|
||||
</insert>
|
||||
<insert tableName="m_code_value">
|
||||
<column name="code_id" valueComputed="(SELECT id FROM m_code WHERE code_name = 'PeriodFrequency')"/>
|
||||
<column name="code_value" value="Quarterly"/>
|
||||
<column name="code_description" value="Quarterly"/>
|
||||
<column name="order_position" valueNumeric="2"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="is_mandatory" valueBoolean="false"/>
|
||||
</insert>
|
||||
<insert tableName="m_code_value">
|
||||
<column name="code_id" valueComputed="(SELECT id FROM m_code WHERE code_name = 'PeriodFrequency')"/>
|
||||
<column name="code_value" value="Half Yearly"/>
|
||||
<column name="code_description" value="Half Yearly"/>
|
||||
<column name="order_position" valueNumeric="3"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="is_mandatory" valueBoolean="false"/>
|
||||
</insert>
|
||||
<insert tableName="m_code_value">
|
||||
<column name="code_id" valueComputed="(SELECT id FROM m_code WHERE code_name = 'PeriodFrequency')"/>
|
||||
<column name="code_value" value="Yearly"/>
|
||||
<column name="code_description" value="Yearly"/>
|
||||
<column name="order_position" valueNumeric="4"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="is_mandatory" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
|
||||
<!-- Add new columns to m_savings_product table -->
|
||||
<changeSet id="0251_add_savings_product_enhanced_fields" author="system">
|
||||
<addColumn tableName="m_savings_product">
|
||||
<column name="account_type" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="customer_segment" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="product_code" type="varchar(20)">
|
||||
<constraints nullable="true" unique="true"/>
|
||||
</column>
|
||||
<column name="effective_date" type="date">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="effective_to" type="date">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="end_date" type="date">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="introducer_required" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="share_linking_enabled" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="nomination_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="dormancy_alert" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="interest_calculate_selector" type="int">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="average_period" type="varchar(20)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="auto_post" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="frequency_fix_day" type="int">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="last_interest_date" type="date">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="enable_lockin_period" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Create m_savings_product_facility_config table -->
|
||||
<changeSet id="0252_create_savings_product_facility_config_table" author="system">
|
||||
<createTable tableName="m_savings_product_facility_config">
|
||||
<column name="id" type="bigint" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="bigint">
|
||||
<constraints nullable="false" unique="true"/>
|
||||
</column>
|
||||
<column name="atm_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="atm_withdrawal_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="upi_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="pos_transactions_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="cheque_book" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="imps_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="sms_alerts" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="bbps_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="insurance_cover" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="bepg_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="neft_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="rtgs_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="inter_bank_total_cap_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="withdrawal_facility" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="deposit_facility_kyc" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="virtual_debit_card" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created_date" type="datetime" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="m_savings_product_facility_config"
|
||||
baseColumnNames="savings_product_id"
|
||||
referencedTableName="m_savings_product"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_savings_product_facility_config_product_id"
|
||||
onDelete="CASCADE"/>
|
||||
</changeSet>
|
||||
|
||||
<!-- Create m_savings_product_facility_limits table -->
|
||||
<changeSet id="0253_create_savings_product_facility_limits_table" author="system">
|
||||
<createTable tableName="m_savings_product_facility_limits">
|
||||
<column name="id" type="bigint" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="bigint">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="limit_type" type="varchar(100)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="general_limit" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="minor_account_limit" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="small_saving_limit" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="created_date" type="datetime" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="m_savings_product_facility_limits"
|
||||
baseColumnNames="savings_product_id"
|
||||
referencedTableName="m_savings_product"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_savings_product_facility_limits_product_id"
|
||||
onDelete="CASCADE"/>
|
||||
|
||||
<createIndex tableName="m_savings_product_facility_limits" indexName="idx_savings_product_facility_limits_product_type">
|
||||
<column name="savings_product_id"/>
|
||||
<column name="limit_type"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
<!-- Create m_savings_product_deposit_limit_kyc table -->
|
||||
<changeSet id="0254_create_savings_product_deposit_limit_kyc_table" author="system">
|
||||
<createTable tableName="m_savings_product_deposit_limit_kyc">
|
||||
<column name="id" type="bigint" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="bigint">
|
||||
<constraints nullable="false" unique="true"/>
|
||||
</column>
|
||||
<column name="general_kyc_type" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="general_limit" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="minor_kyc_type" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="minor_limit" type="bigint">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="small_saving_kyc_type" type="varchar(50)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="small_saving_limit" type="bigint">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="created_date" type="datetime" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="m_savings_product_deposit_limit_kyc"
|
||||
baseColumnNames="savings_product_id"
|
||||
referencedTableName="m_savings_product"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_savings_product_deposit_limit_kyc_product_id"
|
||||
onDelete="CASCADE"/>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+3
@@ -260,6 +260,9 @@
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionTaxDetails</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsOfficerAssignmentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProduct</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKyc</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit</class>
|
||||
|
||||
<!-- Progressive Loan Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance</class>
|
||||
|
||||
@@ -4667,6 +4667,7 @@ CREATE TABLE IF NOT EXISTS `m_savings_product` (
|
||||
`days_to_inactive` INT DEFAULT NULL,
|
||||
`days_to_dormancy` INT DEFAULT NULL,
|
||||
`days_to_escheat` INT DEFAULT NULL,
|
||||
`other_gl_mappings` LONGTEXT DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `sp_unq_name` (`name`),
|
||||
UNIQUE KEY `sp_unq_short_name` (`short_name`),
|
||||
|
||||
+3
-2
@@ -4918,6 +4918,7 @@ CREATE TABLE IF NOT EXISTS `m_savings_product` (
|
||||
`days_to_inactive` INT DEFAULT NULL,
|
||||
`days_to_dormancy` INT DEFAULT NULL,
|
||||
`days_to_escheat` INT DEFAULT NULL,
|
||||
`other_gl_mappings` LONGTEXT DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `sp_unq_name` (`name`),
|
||||
UNIQUE KEY `sp_unq_short_name` (`short_name`),
|
||||
@@ -4927,8 +4928,8 @@ CREATE TABLE IF NOT EXISTS `m_savings_product` (
|
||||
|
||||
-- Dumping data for table mifostenant-reference.m_savings_product: ~1 rows (approximately)
|
||||
/*!40000 ALTER TABLE `m_savings_product` DISABLE KEYS */;
|
||||
INSERT INTO `m_savings_product` (`id`, `name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `lockin_period_frequency`, `lockin_period_frequency_enum`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, `withdrawal_fee_for_transfer`, `allow_overdraft`, `overdraft_limit`, `nominal_annual_interest_rate_overdraft`, `min_overdraft_for_interest_calculation`, `min_required_balance`, `enforce_min_required_balance`, `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`, `days_to_inactive`, `days_to_dormancy`, `days_to_escheat`) VALUES
|
||||
(1, 'Voluntary savings', 'VS', 'Save money', 100, 'USD', 2, 0, 9.500000, 1, 4, 1, 365, 1000.000000, 1.000000, 1, 2, NULL, NULL, 0, 0, NULL, 0.000000, 0.000000, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `m_savings_product` (`id`, `name`, `short_name`, `description`, `deposit_type_enum`, `currency_code`, `currency_digits`, `currency_multiplesof`, `nominal_annual_interest_rate`, `interest_compounding_period_enum`, `interest_posting_period_enum`, `interest_calculation_type_enum`, `interest_calculation_days_in_year_type_enum`, `min_required_opening_balance`, `lockin_period_frequency`, `lockin_period_frequency_enum`, `accounting_type`, `withdrawal_fee_amount`, `withdrawal_fee_type_enum`, `withdrawal_fee_for_transfer`, `allow_overdraft`, `overdraft_limit`, `nominal_annual_interest_rate_overdraft`, `min_overdraft_for_interest_calculation`, `min_required_balance`, `enforce_min_required_balance`, `min_balance_for_interest_calculation`, `withhold_tax`, `tax_group_id`, `is_dormancy_tracking_active`, `days_to_inactive`, `days_to_dormancy`, `days_to_escheat`, `other_gl_mappings`) VALUES
|
||||
(1, 'Voluntary savings', 'VS', 'Save money', 100, 'USD', 2, 0, 9.500000, 1, 4, 1, 365, 1000.000000, 1.000000, 1, 2, NULL, NULL, 0, 0, NULL, 0.000000, 0.000000, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
/*!40000 ALTER TABLE `m_savings_product` ENABLE KEYS */;
|
||||
|
||||
|
||||
|
||||
+12
-2
@@ -38,10 +38,20 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
|
||||
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName,
|
||||
feeOnMonthDayParamName, "currencyOptions", "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions",
|
||||
"interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions",
|
||||
"interestCalculationTypeOptions", "interestCalculationTypeOption", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions",
|
||||
"withdrawalFeeTypeOptions", nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
withHoldTaxParamName, taxGroupIdParamName, isDormancyTrackingActiveParamName, daysToInactiveParamName,
|
||||
daysToDormancyParamName, daysToInactiveParamName, accountMappingForPaymentParamName));
|
||||
daysToDormancyParamName, daysToInactiveParamName, accountMappingForPaymentParamName, "otherGlMappings", "accountTypeOptions",
|
||||
"customerSegmentOptions", "yesNoOptions",
|
||||
// Enhanced custom fields
|
||||
"accountType", "customerSegment", "productCode", "effectiveDate", "effectiveTo", "endDate",
|
||||
"introducerRequired", "shareLinkingEnabled", "nominationFacility", "dormancyAlert",
|
||||
"interestCalculateSelector", "averagePeriod", "autoPost", "frequencyFixDay", "lastInterestDate",
|
||||
"enableLockinPeriod", "balanceFrequency", "accountClosedZeroBalanceInDayClosing",
|
||||
"accountFacilityConfig", "accountFacilityLimits", "depositLimitKyc",
|
||||
"allowOverdraft", "overdraftLimit", "minRequiredBalance", "enforceMinRequiredBalance",
|
||||
"maxAllowedLienLimit", "lienAllowed", "minBalanceForInterestCalculation",
|
||||
"accountingRule", "accountingMappings", "charges", "periodFrequencyOptions"));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
|
||||
|
||||
+35
-4
@@ -88,13 +88,14 @@ public class SavingsProductDataValidator {
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final SavingsProductAccountingDataValidator savingsProductAccountingDataValidator;
|
||||
private static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
|
||||
SavingsApiConstants.localeParamName, SavingsApiConstants.monthDayFormatParamName, nameParamName, shortNameParamName,
|
||||
SavingsApiConstants.localeParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.monthDayFormatParamName, nameParamName, shortNameParamName,
|
||||
descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, inMultiplesOfParamName,
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName,
|
||||
interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, SavingsApiConstants.withdrawalFeeAmountParamName,
|
||||
SavingsApiConstants.withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName,
|
||||
SavingsApiConstants.accountingRuleParamName, SavingsApiConstants.chargesParamName,
|
||||
SavingsApiConstants.otherGlMappingsParamName,
|
||||
SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
|
||||
SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
|
||||
SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
@@ -110,7 +111,20 @@ public class SavingsProductDataValidator {
|
||||
minOverdraftForInterestCalculationParamName, SavingsApiConstants.minRequiredBalanceParamName,
|
||||
SavingsApiConstants.enforceMinRequiredBalanceParamName, SavingsApiConstants.maxAllowedLienLimitParamName,
|
||||
SavingsApiConstants.lienAllowedParamName, minBalanceForInterestCalculationParamName, withHoldTaxParamName,
|
||||
taxGroupIdParamName));
|
||||
taxGroupIdParamName,
|
||||
// Enhanced Savings Product Fields
|
||||
SavingsApiConstants.accountTypeParamName, SavingsApiConstants.customerSegmentParamName,
|
||||
SavingsApiConstants.productCodeParamName, SavingsApiConstants.effectiveDateParamName,
|
||||
SavingsApiConstants.effectiveToParamName, SavingsApiConstants.endDateParamName,
|
||||
SavingsApiConstants.introducerRequiredParamName, SavingsApiConstants.shareLinkingEnabledParamName,
|
||||
SavingsApiConstants.nominationFacilityParamName, SavingsApiConstants.dormancyAlertParamName,
|
||||
SavingsApiConstants.interestCalculateSelectorParamName, SavingsApiConstants.averagePeriodParamName,
|
||||
SavingsApiConstants.autoPostParamName, SavingsApiConstants.frequencyFixDayParamName,
|
||||
SavingsApiConstants.lastInterestDateParamName, SavingsApiConstants.enableLockinPeriodParamName,
|
||||
SavingsApiConstants.accountFacilityConfigParamName, SavingsApiConstants.accountFacilityLimitsParamName,
|
||||
SavingsApiConstants.depositLimitKycParamName,
|
||||
// Additional custom fields
|
||||
SavingsApiConstants.balanceFrequencyParamName, SavingsApiConstants.accountClosedZeroBalanceInDayClosingParamName));
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
|
||||
@@ -159,8 +173,7 @@ public class SavingsProductDataValidator {
|
||||
|
||||
final Integer interestCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull()
|
||||
.isOneOfTheseValues(SavingsInterestCalculationType.integerValues());
|
||||
baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull();
|
||||
|
||||
final Integer interestCalculationDaysInYearType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(interestCalculationDaysInYearTypeParamName, element);
|
||||
@@ -253,6 +266,15 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingsApiConstants.effectiveToParamName, element) && this.fromApiJsonHelper.parameterExists(SavingsApiConstants.effectiveDateParamName, element)) {
|
||||
final java.time.LocalDate effectiveDate = this.fromApiJsonHelper.extractLocalDateNamed(SavingsApiConstants.effectiveDateParamName, element);
|
||||
final java.time.LocalDate effectiveTo = this.fromApiJsonHelper.extractLocalDateNamed(SavingsApiConstants.effectiveToParamName, element);
|
||||
|
||||
if (effectiveDate != null && effectiveTo != null && effectiveTo.isBefore(effectiveDate)) {
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.effectiveToParamName).value(effectiveTo).failWithCode("error.msg.effectiveto.cannot.be.before.effectivedate");
|
||||
}
|
||||
}
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
@@ -263,6 +285,15 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator, DepositAccountType.SAVINGS_DEPOSIT, true);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SavingsApiConstants.effectiveToParamName, element) && this.fromApiJsonHelper.parameterExists(SavingsApiConstants.effectiveDateParamName, element)) {
|
||||
final java.time.LocalDate effectiveDate = this.fromApiJsonHelper.extractLocalDateNamed(SavingsApiConstants.effectiveDateParamName, element);
|
||||
final java.time.LocalDate effectiveTo = this.fromApiJsonHelper.extractLocalDateNamed(SavingsApiConstants.effectiveToParamName, element);
|
||||
|
||||
if (effectiveDate != null && effectiveTo != null && effectiveTo.isBefore(effectiveDate)) {
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.effectiveToParamName).value(effectiveTo).failWithCode("error.msg.effectiveto.cannot.be.before.effectivedate");
|
||||
}
|
||||
}
|
||||
|
||||
validateOverdraftParams(baseDataValidator, element);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minBalanceForInterestCalculationParamName, element)) {
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
|
||||
<changeSet id="1" author="fineract">
|
||||
<addColumn tableName="m_savings_product">
|
||||
<column name="account_type" type="VARCHAR(50)"/>
|
||||
<column name="customer_segment" type="VARCHAR(50)"/>
|
||||
<column name="product_code" type="VARCHAR(20)">
|
||||
<constraints unique="true" uniqueConstraintName="uq_savings_product_code"/>
|
||||
</column>
|
||||
<column name="effective_date" type="DATE"/>
|
||||
<column name="effective_to" type="DATE"/>
|
||||
<column name="end_date" type="DATE"/>
|
||||
<column name="introducer_required" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="share_linking_enabled" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="nomination_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="dormancy_alert" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="interest_calculate_selector" type="INT"/>
|
||||
<column name="average_period" type="VARCHAR(20)"/>
|
||||
<column name="auto_post" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="frequency_fix_day" type="INT"/>
|
||||
<column name="last_interest_date" type="DATE"/>
|
||||
<column name="enable_lockin_period" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2" author="fineract">
|
||||
<createTable tableName="m_savings_product_facility_config">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="BIGINT">
|
||||
<constraints nullable="false" unique="true" uniqueConstraintName="uq_savings_product_facility_config" foreignKeyName="fk_facility_config_savings_product" references="m_savings_product(id)" deleteCascade="true"/>
|
||||
</column>
|
||||
<column name="atm_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="atm_withdrawal_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="upi_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="pos_transactions_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="cheque_book" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="imps_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="sms_alerts" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="bbps_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="insurance_cover" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="bepg_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="neft_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="rtgs_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="inter_bank_total_cap_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="withdrawal_facility" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="deposit_facility_kyc" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="virtual_debit_card" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="created_date" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="3" author="fineract">
|
||||
<createTable tableName="m_savings_product_facility_limits">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_facility_limits_savings_product" references="m_savings_product(id)" deleteCascade="true"/>
|
||||
</column>
|
||||
<column name="limit_type" type="VARCHAR(100)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="general_limit" type="VARCHAR(50)"/>
|
||||
<column name="minor_account_limit" type="VARCHAR(50)"/>
|
||||
<column name="small_saving_limit" type="VARCHAR(50)"/>
|
||||
<column name="created_date" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addUniqueConstraint tableName="m_savings_product_facility_limits" columnNames="savings_product_id, limit_type" constraintName="uq_product_limit_type"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="4" author="fineract">
|
||||
<createTable tableName="m_savings_product_deposit_limit_kyc">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="savings_product_id" type="BIGINT">
|
||||
<constraints nullable="false" unique="true" uniqueConstraintName="uq_savings_product_deposit_limit" foreignKeyName="fk_deposit_limit_savings_product" references="m_savings_product(id)" deleteCascade="true"/>
|
||||
</column>
|
||||
<column name="general_kyc_type" type="VARCHAR(50)"/>
|
||||
<column name="general_limit" type="VARCHAR(50)"/>
|
||||
<column name="minor_kyc_type" type="VARCHAR(50)"/>
|
||||
<column name="minor_limit" type="BIGINT"/>
|
||||
<column name="small_saving_kyc_type" type="VARCHAR(50)"/>
|
||||
<column name="small_saving_limit" type="BIGINT"/>
|
||||
<column name="created_date" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+400
-5
@@ -48,12 +48,30 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.namePara
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.otherGlMappingsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.customerSegmentParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveToParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.endDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.introducerRequiredParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominationFacilityParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dormancyAlertParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculateSelectorParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.averagePeriodParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.autoPostParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.frequencyFixDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lastInterestDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.enableLockinPeriodParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.DiscriminatorColumn;
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
@@ -65,6 +83,9 @@ import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import java.math.BigDecimal;
|
||||
@@ -75,6 +96,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
@@ -209,6 +231,75 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
@Column(name = "days_to_escheat")
|
||||
private Long daysToEscheat;
|
||||
|
||||
@Lob
|
||||
@Column(name = "other_gl_mappings")
|
||||
private String otherGlMappings;
|
||||
|
||||
// Enhanced Savings Product Fields
|
||||
@Column(name = "account_type", length = 50)
|
||||
private String accountType;
|
||||
|
||||
@Column(name = "customer_segment", length = 50)
|
||||
private String customerSegment;
|
||||
|
||||
@Column(name = "product_code", length = 20, unique = true)
|
||||
private String productCode;
|
||||
|
||||
@Column(name = "effective_date")
|
||||
private LocalDate effectiveDate;
|
||||
|
||||
@Column(name = "effective_to")
|
||||
private LocalDate effectiveTo;
|
||||
|
||||
@Column(name = "end_date")
|
||||
private LocalDate endDate;
|
||||
|
||||
@Column(name = "introducer_required")
|
||||
private boolean introducerRequired = false;
|
||||
|
||||
@Column(name = "share_linking_enabled")
|
||||
private boolean shareLinkingEnabled = false;
|
||||
|
||||
@Column(name = "nomination_facility")
|
||||
private boolean nominationFacility = false;
|
||||
|
||||
@Column(name = "dormancy_alert")
|
||||
private boolean dormancyAlert = false;
|
||||
|
||||
@Column(name = "interest_calculate_selector")
|
||||
private Integer interestCalculateSelector;
|
||||
|
||||
@Column(name = "average_period", length = 20)
|
||||
private String averagePeriod;
|
||||
|
||||
@Column(name = "auto_post")
|
||||
private boolean autoPost = false;
|
||||
|
||||
@Column(name = "frequency_fix_day")
|
||||
private Integer frequencyFixDay;
|
||||
|
||||
@Column(name = "last_interest_date")
|
||||
private LocalDate lastInterestDate;
|
||||
|
||||
@Column(name = "enable_lockin_period")
|
||||
private boolean enableLockinPeriod = false;
|
||||
|
||||
@Column(name = "balance_frequency", length = 50)
|
||||
private String balanceFrequency;
|
||||
|
||||
@Column(name = "account_closed_zero_balance_in_day_closing")
|
||||
private Boolean accountClosedZeroBalanceInDayClosing = false;
|
||||
|
||||
// Relationships for complex objects
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private SavingsProductFacilityConfig facilityConfig;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private Set<SavingsProductFacilityLimit> facilityLimits = new HashSet<>();
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private SavingsProductDepositLimitKyc depositLimitKyc;
|
||||
|
||||
public static SavingsProduct createNew(final String name, final String shortName, final String description,
|
||||
final MonetaryCurrency currency, final BigDecimal interestRate,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
@@ -220,14 +311,15 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
final BigDecimal minRequiredBalance, final boolean lienAllowed, final BigDecimal maxAllowedLienLimit,
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||
final BigDecimal minOverdraftForInterestCalculation, boolean withHoldTax, TaxGroup taxGroup,
|
||||
final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat) {
|
||||
final String otherGlMappings, final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy,
|
||||
final Long daysToEscheat) {
|
||||
|
||||
return new SavingsProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, lienAllowed, maxAllowedLienLimit,
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax,
|
||||
taxGroup, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
|
||||
taxGroup, otherGlMappings, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
|
||||
}
|
||||
|
||||
protected SavingsProduct() {
|
||||
@@ -235,6 +327,22 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.description = null;
|
||||
}
|
||||
|
||||
protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, BigDecimal minBalanceForInterestCalculation, boolean withHoldTax,
|
||||
TaxGroup taxGroup, final String otherGlMappings) {
|
||||
this(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit,
|
||||
false, null, false, null, minBalanceForInterestCalculation, null, null, withHoldTax, taxGroup, null, null, null, null,
|
||||
null);
|
||||
this.otherGlMappings = otherGlMappings;
|
||||
}
|
||||
|
||||
protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
@@ -246,7 +354,7 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit,
|
||||
false, null, false, null, minBalanceForInterestCalculation, null, null, withHoldTax, taxGroup, null, null, null, null);
|
||||
minBalanceForInterestCalculation, withHoldTax, taxGroup, null);
|
||||
}
|
||||
|
||||
protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
@@ -259,7 +367,8 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
final BigDecimal minRequiredBalance, final boolean lienAllowed, final BigDecimal maxAllowedLienLimit,
|
||||
BigDecimal minBalanceForInterestCalculation, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||
final BigDecimal minOverdraftForInterestCalculation, final boolean withHoldTax, final TaxGroup taxGroup,
|
||||
final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy, final Long daysToEscheat) {
|
||||
final String otherGlMappings, final Boolean isDormancyTrackingActive, final Long daysToInactive, final Long daysToDormancy,
|
||||
final Long daysToEscheat) {
|
||||
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -306,6 +415,7 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
this.withHoldTax = withHoldTax;
|
||||
this.taxGroup = taxGroup;
|
||||
this.otherGlMappings = otherGlMappings;
|
||||
|
||||
if (isDormancyTrackingActive == null) {
|
||||
this.isDormancyTrackingActive = Boolean.FALSE;
|
||||
@@ -444,7 +554,7 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
if (command.isChangeInIntegerParameterNamed(interestCalculationTypeParamName, this.interestCalculationType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName);
|
||||
actualChanges.put(interestCalculationTypeParamName, newValue);
|
||||
this.interestCalculationType = SavingsInterestCalculationType.fromInt(newValue).getValue();
|
||||
this.interestCalculationType = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(interestCalculationDaysInYearTypeParamName, this.interestCalculationDaysInYearType)) {
|
||||
@@ -586,6 +696,14 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.taxGroup = null;
|
||||
}
|
||||
|
||||
if (command.hasParameter(otherGlMappingsParamName)) {
|
||||
final String newValue = command.jsonFragment(otherGlMappingsParamName);
|
||||
if (!Objects.equals(this.otherGlMappings, newValue)) {
|
||||
actualChanges.put(otherGlMappingsParamName, newValue);
|
||||
this.otherGlMappings = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(isDormancyTrackingActiveParamName, this.isDormancyTrackingActive)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isDormancyTrackingActiveParamName);
|
||||
actualChanges.put(isDormancyTrackingActiveParamName, newValue);
|
||||
@@ -616,6 +734,102 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.daysToEscheat = null;
|
||||
}
|
||||
|
||||
// Enhanced Savings Product Field Updates
|
||||
if (command.isChangeInStringParameterNamed(accountTypeParamName, this.accountType)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(accountTypeParamName);
|
||||
actualChanges.put(accountTypeParamName, newValue);
|
||||
this.accountType = newValue;
|
||||
}
|
||||
if (command.isChangeInStringParameterNamed(customerSegmentParamName, this.customerSegment)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(customerSegmentParamName);
|
||||
actualChanges.put(customerSegmentParamName, newValue);
|
||||
this.customerSegment = newValue;
|
||||
}
|
||||
if (command.isChangeInStringParameterNamed(productCodeParamName, this.productCode)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(productCodeParamName);
|
||||
actualChanges.put(productCodeParamName, newValue);
|
||||
this.productCode = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(effectiveDateParamName, this.effectiveDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(effectiveDateParamName);
|
||||
actualChanges.put(effectiveDateParamName, newValue);
|
||||
this.effectiveDate = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(effectiveToParamName, this.effectiveTo)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(effectiveToParamName);
|
||||
actualChanges.put(effectiveToParamName, newValue);
|
||||
this.effectiveTo = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(endDateParamName, this.endDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(endDateParamName);
|
||||
actualChanges.put(endDateParamName, newValue);
|
||||
this.endDate = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(introducerRequiredParamName, this.introducerRequired)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(introducerRequiredParamName);
|
||||
actualChanges.put(introducerRequiredParamName, newValue);
|
||||
this.introducerRequired = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(shareLinkingEnabledParamName, this.shareLinkingEnabled)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(shareLinkingEnabledParamName);
|
||||
actualChanges.put(shareLinkingEnabledParamName, newValue);
|
||||
this.shareLinkingEnabled = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(nominationFacilityParamName, this.nominationFacility)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(nominationFacilityParamName);
|
||||
actualChanges.put(nominationFacilityParamName, newValue);
|
||||
this.nominationFacility = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(dormancyAlertParamName, this.dormancyAlert)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(dormancyAlertParamName);
|
||||
actualChanges.put(dormancyAlertParamName, newValue);
|
||||
this.dormancyAlert = newValue;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(interestCalculateSelectorParamName, this.interestCalculateSelector)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(interestCalculateSelectorParamName);
|
||||
actualChanges.put(interestCalculateSelectorParamName, newValue);
|
||||
this.interestCalculateSelector = newValue;
|
||||
}
|
||||
if (command.isChangeInStringParameterNamed(averagePeriodParamName, this.averagePeriod)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(averagePeriodParamName);
|
||||
actualChanges.put(averagePeriodParamName, newValue);
|
||||
this.averagePeriod = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(autoPostParamName, this.autoPost)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(autoPostParamName);
|
||||
actualChanges.put(autoPostParamName, newValue);
|
||||
this.autoPost = newValue;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(frequencyFixDayParamName, this.frequencyFixDay)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(frequencyFixDayParamName);
|
||||
actualChanges.put(frequencyFixDayParamName, newValue);
|
||||
this.frequencyFixDay = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(lastInterestDateParamName, this.lastInterestDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(lastInterestDateParamName);
|
||||
actualChanges.put(lastInterestDateParamName, newValue);
|
||||
this.lastInterestDate = newValue;
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(enableLockinPeriodParamName, this.enableLockinPeriod)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enableLockinPeriodParamName);
|
||||
actualChanges.put(enableLockinPeriodParamName, newValue);
|
||||
this.enableLockinPeriod = newValue;
|
||||
}
|
||||
|
||||
// Update balanceFrequency
|
||||
if (command.isChangeInStringParameterNamed("balanceFrequency", this.balanceFrequency)) {
|
||||
final String newValue = command.stringValueOfParameterNamed("balanceFrequency");
|
||||
actualChanges.put("balanceFrequency", newValue);
|
||||
this.balanceFrequency = newValue;
|
||||
}
|
||||
|
||||
// Update accountClosedZeroBalanceInDayClosing
|
||||
if (command.isChangeInBooleanParameterNamed("accountClosedZeroBalanceInDayClosing", this.accountClosedZeroBalanceInDayClosing)) {
|
||||
final Boolean newValue = command.booleanObjectValueOfParameterNamed("accountClosedZeroBalanceInDayClosing");
|
||||
actualChanges.put("accountClosedZeroBalanceInDayClosing", newValue);
|
||||
this.accountClosedZeroBalanceInDayClosing = newValue;
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
esnureOverdraftLimitsSetForOverdraftAccounts();
|
||||
|
||||
@@ -779,4 +993,185 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
return this.daysToEscheat;
|
||||
}
|
||||
|
||||
public String getOtherGlMappings() {
|
||||
return this.otherGlMappings;
|
||||
}
|
||||
|
||||
// Enhanced Savings Product Getters and Setters
|
||||
public String getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
public void setAccountType(String accountType) {
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
public String getCustomerSegment() {
|
||||
return customerSegment;
|
||||
}
|
||||
|
||||
public void setCustomerSegment(String customerSegment) {
|
||||
this.customerSegment = customerSegment;
|
||||
}
|
||||
|
||||
public String getProductCode() {
|
||||
return productCode;
|
||||
}
|
||||
|
||||
public void setProductCode(String productCode) {
|
||||
this.productCode = productCode;
|
||||
}
|
||||
|
||||
public LocalDate getEffectiveDate() {
|
||||
return effectiveDate;
|
||||
}
|
||||
|
||||
public void setEffectiveDate(LocalDate effectiveDate) {
|
||||
this.effectiveDate = effectiveDate;
|
||||
}
|
||||
|
||||
public LocalDate getEffectiveTo() {
|
||||
return effectiveTo;
|
||||
}
|
||||
|
||||
public void setEffectiveTo(LocalDate effectiveTo) {
|
||||
this.effectiveTo = effectiveTo;
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void setEndDate(LocalDate endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public boolean isIntroducerRequired() {
|
||||
return introducerRequired;
|
||||
}
|
||||
|
||||
public void setIntroducerRequired(boolean introducerRequired) {
|
||||
this.introducerRequired = introducerRequired;
|
||||
}
|
||||
|
||||
public boolean isShareLinkingEnabled() {
|
||||
return shareLinkingEnabled;
|
||||
}
|
||||
|
||||
public void setShareLinkingEnabled(boolean shareLinkingEnabled) {
|
||||
this.shareLinkingEnabled = shareLinkingEnabled;
|
||||
}
|
||||
|
||||
public boolean isNominationFacility() {
|
||||
return nominationFacility;
|
||||
}
|
||||
|
||||
public void setNominationFacility(boolean nominationFacility) {
|
||||
this.nominationFacility = nominationFacility;
|
||||
}
|
||||
|
||||
public boolean isDormancyAlert() {
|
||||
return dormancyAlert;
|
||||
}
|
||||
|
||||
public void setDormancyAlert(boolean dormancyAlert) {
|
||||
this.dormancyAlert = dormancyAlert;
|
||||
}
|
||||
|
||||
public Integer getInterestCalculateSelector() {
|
||||
return interestCalculateSelector;
|
||||
}
|
||||
|
||||
public void setInterestCalculateSelector(Integer interestCalculateSelector) {
|
||||
this.interestCalculateSelector = interestCalculateSelector;
|
||||
}
|
||||
|
||||
public String getAveragePeriod() {
|
||||
return averagePeriod;
|
||||
}
|
||||
|
||||
public void setAveragePeriod(String averagePeriod) {
|
||||
this.averagePeriod = averagePeriod;
|
||||
}
|
||||
|
||||
public boolean isAutoPost() {
|
||||
return autoPost;
|
||||
}
|
||||
|
||||
public void setAutoPost(boolean autoPost) {
|
||||
this.autoPost = autoPost;
|
||||
}
|
||||
|
||||
public Integer getFrequencyFixDay() {
|
||||
return frequencyFixDay;
|
||||
}
|
||||
|
||||
public void setFrequencyFixDay(Integer frequencyFixDay) {
|
||||
this.frequencyFixDay = frequencyFixDay;
|
||||
}
|
||||
|
||||
public LocalDate getLastInterestDate() {
|
||||
return lastInterestDate;
|
||||
}
|
||||
|
||||
public void setLastInterestDate(LocalDate lastInterestDate) {
|
||||
this.lastInterestDate = lastInterestDate;
|
||||
}
|
||||
|
||||
public boolean isEnableLockinPeriod() {
|
||||
return enableLockinPeriod;
|
||||
}
|
||||
|
||||
public void setEnableLockinPeriod(boolean enableLockinPeriod) {
|
||||
this.enableLockinPeriod = enableLockinPeriod;
|
||||
}
|
||||
|
||||
public String getBalanceFrequency() {
|
||||
return balanceFrequency;
|
||||
}
|
||||
|
||||
public void setBalanceFrequency(String balanceFrequency) {
|
||||
this.balanceFrequency = balanceFrequency;
|
||||
}
|
||||
|
||||
public Boolean getAccountClosedZeroBalanceInDayClosing() {
|
||||
return accountClosedZeroBalanceInDayClosing;
|
||||
}
|
||||
|
||||
public void setAccountClosedZeroBalanceInDayClosing(Boolean accountClosedZeroBalanceInDayClosing) {
|
||||
this.accountClosedZeroBalanceInDayClosing = accountClosedZeroBalanceInDayClosing;
|
||||
}
|
||||
|
||||
public SavingsProductFacilityConfig getFacilityConfig() {
|
||||
return facilityConfig;
|
||||
}
|
||||
|
||||
public void setFacilityConfig(SavingsProductFacilityConfig facilityConfig) {
|
||||
this.facilityConfig = facilityConfig;
|
||||
}
|
||||
|
||||
public Set<SavingsProductFacilityLimit> getFacilityLimits() {
|
||||
return facilityLimits;
|
||||
}
|
||||
|
||||
public void setFacilityLimits(Set<SavingsProductFacilityLimit> facilityLimits) {
|
||||
this.facilityLimits = facilityLimits;
|
||||
}
|
||||
|
||||
public SavingsProductDepositLimitKyc getDepositLimitKyc() {
|
||||
return depositLimitKyc;
|
||||
}
|
||||
|
||||
public void setDepositLimitKyc(SavingsProductDepositLimitKyc depositLimitKyc) {
|
||||
this.depositLimitKyc = depositLimitKyc;
|
||||
}
|
||||
|
||||
// Helper methods for safely updating complex objects (avoids JPA Orphan removal crash on PUT)
|
||||
public void updateFacilityLimits(Set<SavingsProductFacilityLimit> newLimits) {
|
||||
if (newLimits != null) {
|
||||
this.facilityLimits.clear();
|
||||
this.facilityLimits.addAll(newLimits);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+198
-2
@@ -18,7 +18,25 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountFacilityConfigParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountFacilityLimitsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.averagePeriodParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.autoPostParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.customerSegmentParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.depositLimitKycParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dormancyAlertParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveToParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.enableLockinPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.endDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.frequencyFixDayParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.introducerRequiredParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lastInterestDateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominationFacilityParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.daysToDormancyParamName;
|
||||
@@ -29,6 +47,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.digitsAf
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.enforceMinRequiredBalanceParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.idParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.inMultiplesOfParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculateSelectorParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
@@ -46,12 +65,14 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.namePara
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.otherGlMappingsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
@@ -192,13 +213,72 @@ public class SavingsProductAssembler {
|
||||
final Long daysToInactive = command.longValueOfParameterNamed(daysToInactiveParamName);
|
||||
final Long daysToDormancy = command.longValueOfParameterNamed(daysToDormancyParamName);
|
||||
final Long daysToEscheat = command.longValueOfParameterNamed(daysToEscheatParamName);
|
||||
final String otherGlMappings = command.hasParameter(otherGlMappingsParamName) ? command.jsonFragment(otherGlMappingsParamName) : null;
|
||||
|
||||
return SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
SavingsProduct product = SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, lienAllowed, maxAllowedLienLimit,
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax,
|
||||
taxGroup, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
|
||||
taxGroup, otherGlMappings, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat);
|
||||
|
||||
// Set enhanced fields
|
||||
if (command.parameterExists(accountTypeParamName)) {
|
||||
product.setAccountType(command.stringValueOfParameterNamed(accountTypeParamName));
|
||||
}
|
||||
if (command.parameterExists(customerSegmentParamName)) {
|
||||
product.setCustomerSegment(command.stringValueOfParameterNamed(customerSegmentParamName));
|
||||
}
|
||||
if (command.parameterExists(productCodeParamName)) {
|
||||
product.setProductCode(command.stringValueOfParameterNamed(productCodeParamName));
|
||||
}
|
||||
if (command.parameterExists(effectiveDateParamName)) {
|
||||
product.setEffectiveDate(command.localDateValueOfParameterNamed(effectiveDateParamName));
|
||||
}
|
||||
if (command.parameterExists(effectiveToParamName)) {
|
||||
product.setEffectiveTo(command.localDateValueOfParameterNamed(effectiveToParamName));
|
||||
}
|
||||
if (command.parameterExists(endDateParamName)) {
|
||||
product.setEndDate(command.localDateValueOfParameterNamed(endDateParamName));
|
||||
}
|
||||
if (command.parameterExists(introducerRequiredParamName)) {
|
||||
product.setIntroducerRequired(command.booleanPrimitiveValueOfParameterNamed(introducerRequiredParamName));
|
||||
}
|
||||
if (command.parameterExists(shareLinkingEnabledParamName)) {
|
||||
product.setShareLinkingEnabled(command.booleanPrimitiveValueOfParameterNamed(shareLinkingEnabledParamName));
|
||||
}
|
||||
if (command.parameterExists(nominationFacilityParamName)) {
|
||||
product.setNominationFacility(command.booleanPrimitiveValueOfParameterNamed(nominationFacilityParamName));
|
||||
}
|
||||
if (command.parameterExists(dormancyAlertParamName)) {
|
||||
product.setDormancyAlert(command.booleanPrimitiveValueOfParameterNamed(dormancyAlertParamName));
|
||||
}
|
||||
if (command.parameterExists(interestCalculateSelectorParamName)) {
|
||||
product.setInterestCalculateSelector(command.integerValueOfParameterNamed(interestCalculateSelectorParamName));
|
||||
}
|
||||
if (command.parameterExists(averagePeriodParamName)) {
|
||||
product.setAveragePeriod(command.stringValueOfParameterNamed(averagePeriodParamName));
|
||||
}
|
||||
if (command.parameterExists(autoPostParamName)) {
|
||||
product.setAutoPost(command.booleanPrimitiveValueOfParameterNamed(autoPostParamName));
|
||||
}
|
||||
if (command.parameterExists(frequencyFixDayParamName)) {
|
||||
product.setFrequencyFixDay(command.integerValueOfParameterNamed(frequencyFixDayParamName));
|
||||
}
|
||||
if (command.parameterExists(lastInterestDateParamName)) {
|
||||
product.setLastInterestDate(command.localDateValueOfParameterNamed(lastInterestDateParamName));
|
||||
}
|
||||
if (command.parameterExists(enableLockinPeriodParamName)) {
|
||||
product.setEnableLockinPeriod(command.booleanPrimitiveValueOfParameterNamed(enableLockinPeriodParamName));
|
||||
}
|
||||
if (command.parameterExists("balanceFrequency")) {
|
||||
product.setBalanceFrequency(command.stringValueOfParameterNamed("balanceFrequency"));
|
||||
}
|
||||
if (command.parameterExists("accountClosedZeroBalanceInDayClosing")) {
|
||||
product.setAccountClosedZeroBalanceInDayClosing(command.booleanObjectValueOfParameterNamed("accountClosedZeroBalanceInDayClosing"));
|
||||
}
|
||||
|
||||
return product;
|
||||
}
|
||||
|
||||
public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {
|
||||
@@ -243,4 +323,120 @@ public class SavingsProductAssembler {
|
||||
}
|
||||
return taxGroup;
|
||||
}
|
||||
|
||||
public SavingsProductFacilityConfig assembleAccountFacilityConfig(final JsonCommand command, final SavingsProduct product) {
|
||||
if (!command.hasParameter(accountFacilityConfigParamName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonElement facilityConfigElement = command.parsedJson().getAsJsonObject().get(accountFacilityConfigParamName);
|
||||
if (facilityConfigElement == null || facilityConfigElement.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonObject facilityConfigJson = facilityConfigElement.getAsJsonObject();
|
||||
if (facilityConfigJson == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SavingsProductFacilityConfig config = new SavingsProductFacilityConfig(product);
|
||||
config.setAtmFacility(facilityConfigJson.has("atmFacility") ?
|
||||
facilityConfigJson.get("atmFacility").getAsBoolean() : false);
|
||||
config.setAtmWithdrawalFacility(facilityConfigJson.has("atmWithdrawalFacility") ?
|
||||
facilityConfigJson.get("atmWithdrawalFacility").getAsBoolean() : false);
|
||||
config.setUpiFacility(facilityConfigJson.has("upiFacility") ?
|
||||
facilityConfigJson.get("upiFacility").getAsBoolean() : false);
|
||||
config.setPosTransactionsFacility(facilityConfigJson.has("posTransactionsFacility") ?
|
||||
facilityConfigJson.get("posTransactionsFacility").getAsBoolean() : false);
|
||||
config.setChequeBook(facilityConfigJson.has("chequeBook") ?
|
||||
facilityConfigJson.get("chequeBook").getAsBoolean() : false);
|
||||
config.setImpsFacility(facilityConfigJson.has("impsFacility") ?
|
||||
facilityConfigJson.get("impsFacility").getAsBoolean() : false);
|
||||
config.setSmsAlerts(facilityConfigJson.has("smsAlerts") ?
|
||||
facilityConfigJson.get("smsAlerts").getAsBoolean() : false);
|
||||
config.setBbpsFacility(facilityConfigJson.has("bbpsFacility") ?
|
||||
facilityConfigJson.get("bbpsFacility").getAsBoolean() : false);
|
||||
config.setInsuranceCover(facilityConfigJson.has("insuranceCover") ?
|
||||
facilityConfigJson.get("insuranceCover").getAsBoolean() : false);
|
||||
config.setBepgFacility(facilityConfigJson.has("bepgFacility") ?
|
||||
facilityConfigJson.get("bepgFacility").getAsBoolean() : false);
|
||||
config.setNeftFacility(facilityConfigJson.has("neftFacility") ?
|
||||
facilityConfigJson.get("neftFacility").getAsBoolean() : false);
|
||||
config.setRtgsFacility(facilityConfigJson.has("rtgsFacility") ?
|
||||
facilityConfigJson.get("rtgsFacility").getAsBoolean() : false);
|
||||
config.setInterBankTotalCapFacility(facilityConfigJson.has("interBankTotalCapFacility") ?
|
||||
facilityConfigJson.get("interBankTotalCapFacility").getAsBoolean() : false);
|
||||
config.setWithdrawalFacility(facilityConfigJson.has("withdrawalFacility") ?
|
||||
facilityConfigJson.get("withdrawalFacility").getAsBoolean() : false);
|
||||
config.setDepositFacilityKyc(facilityConfigJson.has("depositFacilityKyc") ?
|
||||
facilityConfigJson.get("depositFacilityKyc").getAsBoolean() : false);
|
||||
config.setVirtualDebitCard(facilityConfigJson.has("virtualDebitCard") ?
|
||||
facilityConfigJson.get("virtualDebitCard").getAsBoolean() : false);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public Set<SavingsProductFacilityLimit> assembleAccountFacilityLimits(final JsonCommand command, final SavingsProduct product) {
|
||||
final Set<SavingsProductFacilityLimit> limits = new HashSet<>();
|
||||
|
||||
if (!command.hasParameter(accountFacilityLimitsParamName)) {
|
||||
return limits;
|
||||
}
|
||||
|
||||
final JsonArray limitsArray = command.arrayOfParameterNamed(accountFacilityLimitsParamName);
|
||||
if (limitsArray == null) {
|
||||
return limits;
|
||||
}
|
||||
|
||||
for (int i = 0; i < limitsArray.size(); i++) {
|
||||
final JsonObject limitJson = limitsArray.get(i).getAsJsonObject();
|
||||
SavingsProductFacilityLimit limit = SavingsProductFacilityLimit.create(
|
||||
product,
|
||||
limitJson.has("limitType") ? limitJson.get("limitType").getAsString() : null,
|
||||
limitJson.has("generalLimit") ? limitJson.get("generalLimit").getAsString() : null,
|
||||
limitJson.has("minorAccountLimit") ? limitJson.get("minorAccountLimit").getAsString() : null,
|
||||
limitJson.has("smallSavingLimit") ? limitJson.get("smallSavingLimit").getAsString() : null
|
||||
);
|
||||
limits.add(limit);
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
||||
public SavingsProductDepositLimitKyc assembleDepositLimitKyc(final JsonCommand command, final SavingsProduct product) {
|
||||
if (!command.hasParameter(depositLimitKycParamName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonElement kycElement = command.parsedJson().getAsJsonObject().get(depositLimitKycParamName);
|
||||
if (kycElement == null || kycElement.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonObject kycJson = kycElement.getAsJsonObject();
|
||||
if (kycJson == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SavingsProductDepositLimitKyc kyc = new SavingsProductDepositLimitKyc(product);
|
||||
|
||||
if (kycJson.has("general")) {
|
||||
final JsonObject generalJson = kycJson.getAsJsonObject("general");
|
||||
kyc.setGeneralKycType(generalJson.has("kycType") ? generalJson.get("kycType").getAsString() : null);
|
||||
kyc.setGeneralLimit(generalJson.has("limit") ? generalJson.get("limit").getAsString() : null);
|
||||
}
|
||||
|
||||
if (kycJson.has("minor")) {
|
||||
final JsonObject minorJson = kycJson.getAsJsonObject("minor");
|
||||
kyc.setMinorKycType(minorJson.has("kycType") ? minorJson.get("kycType").getAsString() : null);
|
||||
kyc.setMinorLimit(minorJson.has("limit") ? minorJson.get("limit").getAsLong() : null);
|
||||
}
|
||||
|
||||
if (kycJson.has("smallSaving")) {
|
||||
final JsonObject smallSavingJson = kycJson.getAsJsonObject("smallSaving");
|
||||
kyc.setSmallSavingKycType(smallSavingJson.has("kycType") ? smallSavingJson.get("kycType").getAsString() : null);
|
||||
kyc.setSmallSavingLimit(smallSavingJson.has("limit") ? smallSavingJson.get("limit").getAsLong() : null);
|
||||
}
|
||||
|
||||
return kyc;
|
||||
}
|
||||
}
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_deposit_limit_kyc")
|
||||
public class SavingsProductDepositLimitKyc extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "general_kyc_type", length = 50)
|
||||
private String generalKycType;
|
||||
|
||||
@Column(name = "general_limit", length = 50)
|
||||
private String generalLimit; // "No Limit" or numeric
|
||||
|
||||
@Column(name = "minor_kyc_type", length = 50)
|
||||
private String minorKycType;
|
||||
|
||||
@Column(name = "minor_limit")
|
||||
private Long minorLimit;
|
||||
|
||||
@Column(name = "small_saving_kyc_type", length = 50)
|
||||
private String smallSavingKycType;
|
||||
|
||||
@Column(name = "small_saving_limit")
|
||||
private Long smallSavingLimit;
|
||||
|
||||
@Column(name = "created_date", nullable = false)
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
protected SavingsProductDepositLimitKyc() {
|
||||
this.createdDate = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public SavingsProductDepositLimitKyc(SavingsProduct savingsProduct) {
|
||||
this();
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public SavingsProduct getSavingsProduct() {
|
||||
return savingsProduct;
|
||||
}
|
||||
|
||||
public void setSavingsProduct(SavingsProduct savingsProduct) {
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
public String getGeneralKycType() {
|
||||
return generalKycType;
|
||||
}
|
||||
|
||||
public void setGeneralKycType(String generalKycType) {
|
||||
this.generalKycType = generalKycType;
|
||||
}
|
||||
|
||||
public String getGeneralLimit() {
|
||||
return generalLimit;
|
||||
}
|
||||
|
||||
public void setGeneralLimit(String generalLimit) {
|
||||
this.generalLimit = generalLimit;
|
||||
}
|
||||
|
||||
public String getMinorKycType() {
|
||||
return minorKycType;
|
||||
}
|
||||
|
||||
public void setMinorKycType(String minorKycType) {
|
||||
this.minorKycType = minorKycType;
|
||||
}
|
||||
|
||||
public Long getMinorLimit() {
|
||||
return minorLimit;
|
||||
}
|
||||
|
||||
public void setMinorLimit(Long minorLimit) {
|
||||
this.minorLimit = minorLimit;
|
||||
}
|
||||
|
||||
public String getSmallSavingKycType() {
|
||||
return smallSavingKycType;
|
||||
}
|
||||
|
||||
public void setSmallSavingKycType(String smallSavingKycType) {
|
||||
this.smallSavingKycType = smallSavingKycType;
|
||||
}
|
||||
|
||||
public Long getSmallSavingLimit() {
|
||||
return smallSavingLimit;
|
||||
}
|
||||
|
||||
public void setSmallSavingLimit(Long smallSavingLimit) {
|
||||
this.smallSavingLimit = smallSavingLimit;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void updateFrom(SavingsProductDepositLimitKyc other) {
|
||||
this.generalKycType = other.getGeneralKycType();
|
||||
this.generalLimit = other.getGeneralLimit();
|
||||
this.minorKycType = other.getMinorKycType();
|
||||
this.minorLimit = other.getMinorLimit();
|
||||
this.smallSavingKycType = other.getSmallSavingKycType();
|
||||
this.smallSavingLimit = other.getSmallSavingLimit();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SavingsProductDepositLimitKycRepository extends JpaRepository<SavingsProductDepositLimitKyc, Long> {
|
||||
|
||||
SavingsProductDepositLimitKyc findBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_facility_config")
|
||||
public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "atm_facility")
|
||||
private Boolean atmFacility = false;
|
||||
|
||||
@Column(name = "atm_withdrawal_facility")
|
||||
private Boolean atmWithdrawalFacility = false;
|
||||
|
||||
@Column(name = "upi_facility")
|
||||
private Boolean upiFacility = false;
|
||||
|
||||
@Column(name = "pos_transactions_facility")
|
||||
private Boolean posTransactionsFacility = false;
|
||||
|
||||
@Column(name = "cheque_book")
|
||||
private Boolean chequeBook = false;
|
||||
|
||||
@Column(name = "imps_facility")
|
||||
private Boolean impsFacility = false;
|
||||
|
||||
@Column(name = "sms_alerts")
|
||||
private Boolean smsAlerts = false;
|
||||
|
||||
@Column(name = "bbps_facility")
|
||||
private Boolean bbpsFacility = false;
|
||||
|
||||
@Column(name = "insurance_cover")
|
||||
private Boolean insuranceCover = false;
|
||||
|
||||
@Column(name = "bepg_facility")
|
||||
private Boolean bepgFacility = false;
|
||||
|
||||
@Column(name = "neft_facility")
|
||||
private Boolean neftFacility = false;
|
||||
|
||||
@Column(name = "rtgs_facility")
|
||||
private Boolean rtgsFacility = false;
|
||||
|
||||
@Column(name = "inter_bank_total_cap_facility")
|
||||
private Boolean interBankTotalCapFacility = false;
|
||||
|
||||
@Column(name = "withdrawal_facility")
|
||||
private Boolean withdrawalFacility = false;
|
||||
|
||||
@Column(name = "deposit_facility_kyc")
|
||||
private Boolean depositFacilityKyc = false;
|
||||
|
||||
@Column(name = "virtual_debit_card")
|
||||
private Boolean virtualDebitCard = false;
|
||||
|
||||
@Column(name = "created_date", nullable = false)
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
protected SavingsProductFacilityConfig() {
|
||||
this.createdDate = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public SavingsProductFacilityConfig(SavingsProduct savingsProduct) {
|
||||
this();
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public SavingsProduct getSavingsProduct() {
|
||||
return savingsProduct;
|
||||
}
|
||||
|
||||
public void setSavingsProduct(SavingsProduct savingsProduct) {
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
public Boolean getAtmFacility() {
|
||||
return atmFacility;
|
||||
}
|
||||
|
||||
public void setAtmFacility(Boolean atmFacility) {
|
||||
this.atmFacility = atmFacility != null ? atmFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getAtmWithdrawalFacility() {
|
||||
return atmWithdrawalFacility;
|
||||
}
|
||||
|
||||
public void setAtmWithdrawalFacility(Boolean atmWithdrawalFacility) {
|
||||
this.atmWithdrawalFacility = atmWithdrawalFacility != null ? atmWithdrawalFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getUpiFacility() {
|
||||
return upiFacility;
|
||||
}
|
||||
|
||||
public void setUpiFacility(Boolean upiFacility) {
|
||||
this.upiFacility = upiFacility != null ? upiFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getPosTransactionsFacility() {
|
||||
return posTransactionsFacility;
|
||||
}
|
||||
|
||||
public void setPosTransactionsFacility(Boolean posTransactionsFacility) {
|
||||
this.posTransactionsFacility = posTransactionsFacility != null ? posTransactionsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getChequeBook() {
|
||||
return chequeBook;
|
||||
}
|
||||
|
||||
public void setChequeBook(Boolean chequeBook) {
|
||||
this.chequeBook = chequeBook != null ? chequeBook : false;
|
||||
}
|
||||
|
||||
public Boolean getImpsFacility() {
|
||||
return impsFacility;
|
||||
}
|
||||
|
||||
public void setImpsFacility(Boolean impsFacility) {
|
||||
this.impsFacility = impsFacility != null ? impsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getSmsAlerts() {
|
||||
return smsAlerts;
|
||||
}
|
||||
|
||||
public void setSmsAlerts(Boolean smsAlerts) {
|
||||
this.smsAlerts = smsAlerts != null ? smsAlerts : false;
|
||||
}
|
||||
|
||||
public Boolean getBbpsFacility() {
|
||||
return bbpsFacility;
|
||||
}
|
||||
|
||||
public void setBbpsFacility(Boolean bbpsFacility) {
|
||||
this.bbpsFacility = bbpsFacility != null ? bbpsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getInsuranceCover() {
|
||||
return insuranceCover;
|
||||
}
|
||||
|
||||
public void setInsuranceCover(Boolean insuranceCover) {
|
||||
this.insuranceCover = insuranceCover != null ? insuranceCover : false;
|
||||
}
|
||||
|
||||
public Boolean getBepgFacility() {
|
||||
return bepgFacility;
|
||||
}
|
||||
|
||||
public void setBepgFacility(Boolean bepgFacility) {
|
||||
this.bepgFacility = bepgFacility != null ? bepgFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getNeftFacility() {
|
||||
return neftFacility;
|
||||
}
|
||||
|
||||
public void setNeftFacility(Boolean neftFacility) {
|
||||
this.neftFacility = neftFacility != null ? neftFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getRtgsFacility() {
|
||||
return rtgsFacility;
|
||||
}
|
||||
|
||||
public void setRtgsFacility(Boolean rtgsFacility) {
|
||||
this.rtgsFacility = rtgsFacility != null ? rtgsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getInterBankTotalCapFacility() {
|
||||
return interBankTotalCapFacility;
|
||||
}
|
||||
|
||||
public void setInterBankTotalCapFacility(Boolean interBankTotalCapFacility) {
|
||||
this.interBankTotalCapFacility = interBankTotalCapFacility != null ? interBankTotalCapFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getWithdrawalFacility() {
|
||||
return withdrawalFacility;
|
||||
}
|
||||
|
||||
public void setWithdrawalFacility(Boolean withdrawalFacility) {
|
||||
this.withdrawalFacility = withdrawalFacility != null ? withdrawalFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getDepositFacilityKyc() {
|
||||
return depositFacilityKyc;
|
||||
}
|
||||
|
||||
public void setDepositFacilityKyc(Boolean depositFacilityKyc) {
|
||||
this.depositFacilityKyc = depositFacilityKyc != null ? depositFacilityKyc : false;
|
||||
}
|
||||
|
||||
public Boolean getVirtualDebitCard() {
|
||||
return virtualDebitCard;
|
||||
}
|
||||
|
||||
public void setVirtualDebitCard(Boolean virtualDebitCard) {
|
||||
this.virtualDebitCard = virtualDebitCard != null ? virtualDebitCard : false;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void updateFrom(SavingsProductFacilityConfig other) {
|
||||
this.atmFacility = other.getAtmFacility();
|
||||
this.atmWithdrawalFacility = other.getAtmWithdrawalFacility();
|
||||
this.upiFacility = other.getUpiFacility();
|
||||
this.posTransactionsFacility = other.getPosTransactionsFacility();
|
||||
this.chequeBook = other.getChequeBook();
|
||||
this.impsFacility = other.getImpsFacility();
|
||||
this.smsAlerts = other.getSmsAlerts();
|
||||
this.bbpsFacility = other.getBbpsFacility();
|
||||
this.insuranceCover = other.getInsuranceCover();
|
||||
this.bepgFacility = other.getBepgFacility();
|
||||
this.neftFacility = other.getNeftFacility();
|
||||
this.rtgsFacility = other.getRtgsFacility();
|
||||
this.interBankTotalCapFacility = other.getInterBankTotalCapFacility();
|
||||
this.withdrawalFacility = other.getWithdrawalFacility();
|
||||
this.depositFacilityKyc = other.getDepositFacilityKyc();
|
||||
this.virtualDebitCard = other.getVirtualDebitCard();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SavingsProductFacilityConfigRepository extends JpaRepository<SavingsProductFacilityConfig, Long> {
|
||||
|
||||
SavingsProductFacilityConfig findBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_facility_limits")
|
||||
public class SavingsProductFacilityLimit extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private SavingsProduct savingsProduct;
|
||||
|
||||
@Column(name = "limit_type", length = 100, nullable = false)
|
||||
private String limitType;
|
||||
|
||||
@Column(name = "general_limit", length = 50)
|
||||
private String generalLimit; // Can be "UNLIMITED", "N/A", or numeric value
|
||||
|
||||
@Column(name = "minor_account_limit", length = 50)
|
||||
private String minorAccountLimit;
|
||||
|
||||
@Column(name = "small_saving_limit", length = 50)
|
||||
private String smallSavingLimit;
|
||||
|
||||
@Column(name = "created_date", nullable = false)
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
protected SavingsProductFacilityLimit() {
|
||||
this.createdDate = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public SavingsProductFacilityLimit(SavingsProduct savingsProduct, String limitType,
|
||||
String generalLimit, String minorAccountLimit, String smallSavingLimit) {
|
||||
this();
|
||||
this.savingsProduct = savingsProduct;
|
||||
this.limitType = limitType;
|
||||
this.generalLimit = generalLimit;
|
||||
this.minorAccountLimit = minorAccountLimit;
|
||||
this.smallSavingLimit = smallSavingLimit;
|
||||
}
|
||||
|
||||
public static SavingsProductFacilityLimit create(SavingsProduct savingsProduct, String limitType,
|
||||
String generalLimit, String minorAccountLimit, String smallSavingLimit) {
|
||||
return new SavingsProductFacilityLimit(savingsProduct, limitType, generalLimit,
|
||||
minorAccountLimit, smallSavingLimit);
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public SavingsProduct getSavingsProduct() {
|
||||
return savingsProduct;
|
||||
}
|
||||
|
||||
public void setSavingsProduct(SavingsProduct savingsProduct) {
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
public String getLimitType() {
|
||||
return limitType;
|
||||
}
|
||||
|
||||
public void setLimitType(String limitType) {
|
||||
this.limitType = limitType;
|
||||
}
|
||||
|
||||
public String getGeneralLimit() {
|
||||
return generalLimit;
|
||||
}
|
||||
|
||||
public void setGeneralLimit(String generalLimit) {
|
||||
this.generalLimit = generalLimit;
|
||||
}
|
||||
|
||||
public String getMinorAccountLimit() {
|
||||
return minorAccountLimit;
|
||||
}
|
||||
|
||||
public void setMinorAccountLimit(String minorAccountLimit) {
|
||||
this.minorAccountLimit = minorAccountLimit;
|
||||
}
|
||||
|
||||
public String getSmallSavingLimit() {
|
||||
return smallSavingLimit;
|
||||
}
|
||||
|
||||
public void setSmallSavingLimit(String smallSavingLimit) {
|
||||
this.smallSavingLimit = smallSavingLimit;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SavingsProductFacilityLimitRepository extends JpaRepository<SavingsProductFacilityLimit, Long> {
|
||||
|
||||
List<SavingsProductFacilityLimit> findBySavingsProductId(Long savingsProductId);
|
||||
|
||||
void deleteBySavingsProductId(Long savingsProductId);
|
||||
}
|
||||
+4
@@ -27,4 +27,8 @@
|
||||
<include file="parts/2002_add_savings_accrual_permission.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2003_add_accrued_till_date_to_savings_account.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2004_add_savings_account_cob_infrastructure.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2005_add_savings_product_classification_code_values.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2006_add_period_frequency_options.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2007_add_interest_calculation_type_option.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2008_add_other_gl_mappings_to_savings_product.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="2005-1-savings-product-account-type-code">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_code where code_name = 'SavingsProductAccountType'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="SavingsProductAccountType"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2005-2-savings-product-customer-segment-code">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_code where code_name = 'SavingsProductCustomerSegment'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="SavingsProductCustomerSegment"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2005-3-savings-product-account-type-values">
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'SavingsProductAccountType', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'SavingsProductAccountType');
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Savings Account Minor', 1, 'Savings Account Minor', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Savings Account Minor'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Small Saving Account', 2, 'Small Saving Account', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Small Saving Account'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Savings HUF', 3, 'Savings HUF', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Savings HUF'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2005-4-savings-product-customer-segment-values">
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'SavingsProductCustomerSegment', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'SavingsProductCustomerSegment');
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Individual', 1, 'Individual', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductCustomerSegment'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Individual'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Corporate', 2, 'Corporate', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductCustomerSegment'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Corporate'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2005-5-savings-product-classification-seed-upsert">
|
||||
<comment>
|
||||
Recover older databases where the original changesets may have been marked ran before the data was inserted.
|
||||
This keeps the seed idempotent for both fresh and existing tenants.
|
||||
</comment>
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'SavingsProductAccountType', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'SavingsProductAccountType');
|
||||
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'SavingsProductCustomerSegment', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'SavingsProductCustomerSegment');
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Savings Account Minor', 1, 'Savings Account Minor', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Savings Account Minor'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Small Saving Account', 2, 'Small Saving Account', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Small Saving Account'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Savings HUF', 3, 'Savings HUF', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Savings HUF'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Individual', 1, 'Individual', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductCustomerSegment'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Individual'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Corporate', 2, 'Corporate', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'SavingsProductCustomerSegment'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Corporate'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="2006-period-frequency-code">
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'PeriodFrequency', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'PeriodFrequency');
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Monthly', 1, 'Monthly', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'PeriodFrequency'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Monthly'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Quarterly', 2, 'Quarterly', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'PeriodFrequency'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Quarterly'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Half Yearly', 3, 'Half Yearly', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'PeriodFrequency'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Half Yearly'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Yearly', 4, 'Yearly', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'PeriodFrequency'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Yearly'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="2007-interest-calculation-type-option">
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'InterestCalculationTypeOption', TRUE
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'InterestCalculationTypeOption');
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Compounding', 1, 'Compounding', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'InterestCalculationTypeOption'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Compounding'
|
||||
);
|
||||
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, code_description, is_active, is_mandatory)
|
||||
SELECT c.id, 'Accrual', 2, 'Accrual', TRUE, FALSE
|
||||
FROM m_code c
|
||||
WHERE c.code_name = 'InterestCalculationTypeOption'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = 'Accrual'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. This file is licensed under the Apache License, Version 2.0.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="2008-add-other-gl-mappings-to-savings-product">
|
||||
<addColumn tableName="m_savings_product">
|
||||
<column name="other_gl_mappings" type="LONGTEXT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+3
@@ -109,6 +109,9 @@
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionTaxDetails</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsOfficerAssignmentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProduct</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKyc</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig</class>
|
||||
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit</class>
|
||||
|
||||
<!-- Charge Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.charge.domain.Charge</class>
|
||||
|
||||
+1397
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
{"timestamp":"2026-04-11T09:18:17.723Z","status":401,"error":"Unauthorized","path":"/fineract-provider/api/v1/savingsproducts/3"}
|
||||
Reference in New Issue
Block a user