feat(savings,shares): bidirectional savings/share account linking, optional savings link on share create
- Savings account creation validates and stores a required "shareAccountId" once Share Linking is
enabled, checked against the client's own active share accounts (raw SQL - fineract-savings has
no dependency on the shareaccounts domain). On save, mirrors the link back onto the share
account's own savings_account_id, the same way that field already gets set from the share side.
- New GET /clients/{id}/activeshareaccounts - a client's active share accounts, for the savings
creation screen's picker (kept separate from the shared Savings/FD/RD/Current template DTO).
- ShareAccountDataSerializer.validateAndCreate no longer requires savingsAccountId on create - the
DB column and domain relationship were already nullable, only this validation blocked it.
fix(branchday): stop the denomination carry-forward preview from doubling yesterday's closing count
GET /branchday/denominations classified every detail row that wasn't literally leg='OPENING' as
"closing" - which, once CLOSING_VAULT rows existed alongside CLOSING (single-teller offices record
the same breakdown under both), silently doubled every count shown as "yesterday's closing" when
opening the next business day. Filters to leg IN ('OPENING','CLOSING') explicitly instead of an
else-catches-everything branch.
feat(accounting): seed missing Income/Expense/Transfers-Suspense/Escheat-Liability accounts
The Basoda-derived chart of accounts (0523) carried none of these - a balance sheet has no P&L
heads, and Transfers Suspense/Escheat Liability aren't balance-sheet line items either - so a
Savings Product's accounting mapping had nowhere to point those required fields. Same guard as
0523: only seeds a Basoda-derived tenant that hasn't already gotten it, never touches a tenant with
its own chart of accounts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -48,7 +48,8 @@ public class SavingsAccountConstant extends SavingsApiConstants {
|
||||
introducerIdParamName, introducerNameParamName, introducerCifNumberParamName,
|
||||
nomineeParamName, "nominees", linkedAccountIdParamName, linkedAccountTypeParamName, linkedAccountNoParamName,
|
||||
accountFacilityConfigParamName, jointHoldersParamName,
|
||||
balanceSwapOptionParamName, msmeParamName, autoDebitFacilityParamName, introducerRequiredParamName, shareLinkingEnabledParamName));
|
||||
balanceSwapOptionParamName, msmeParamName, autoDebitFacilityParamName, introducerRequiredParamName, shareLinkingEnabledParamName,
|
||||
shareAccountIdParamName));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
|
||||
|
||||
+13
@@ -4426,6 +4426,16 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
@Column(name = "share_linking_enabled", nullable = false, columnDefinition = "boolean default false")
|
||||
private Boolean shareLinkingEnabled = false;
|
||||
|
||||
/**
|
||||
* Plain id, not a JPA relationship - fineract-savings cannot depend on the shareaccounts domain
|
||||
* class (it lives in fineract-provider, which depends on fineract-savings, not the other way
|
||||
* round). The write side resolves and validates this id against m_share_account directly; this
|
||||
* column just carries it back to the share account's own {@code savings_account_id}, mirroring
|
||||
* the link from both ends.
|
||||
*/
|
||||
@Column(name = "share_account_id")
|
||||
private Long shareAccountId;
|
||||
|
||||
@Column(name = "nomination_facility", nullable = false, columnDefinition = "boolean default false")
|
||||
private Boolean nominationFacility = false;
|
||||
|
||||
@@ -4532,6 +4542,9 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
public Boolean getShareLinkingEnabled() { return shareLinkingEnabled; }
|
||||
public void setShareLinkingEnabled(Boolean v) { this.shareLinkingEnabled = v; }
|
||||
|
||||
public Long getShareAccountId() { return shareAccountId; }
|
||||
public void setShareAccountId(Long v) { this.shareAccountId = v; }
|
||||
|
||||
public boolean isSeniorCitizen() { return isSeniorCitizen; }
|
||||
public void setSeniorCitizen(boolean v) { this.isSeniorCitizen = v; }
|
||||
|
||||
|
||||
+1
@@ -53,4 +53,5 @@
|
||||
<include file="parts/2029_remove_proposed_payload_json.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2030_add_savings_account_pending_edit_table.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2031_add_savings_account_edit_approval_permissions.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2032_add_share_account_id_to_savings_account.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
<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">
|
||||
|
||||
<!-- The reverse of m_share_account.savings_account_id (0489-era, already existed): this is the
|
||||
savings account's own pointer back to the share account it was linked to at creation, when
|
||||
Share Linking Enabled was set. No FK to m_share_account here - fineract-savings has no
|
||||
reference to that table's owning module, so the write side is responsible for validating
|
||||
this id and for keeping the two ends of the link in sync. -->
|
||||
|
||||
<changeSet id="2032_add_share_account_id_to_savings_account" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_savings_account"/>
|
||||
<not><columnExists tableName="m_savings_account" columnName="share_account_id"/></not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_account">
|
||||
<column name="share_account_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user