# 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)