diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkShareWithdrawalRequestApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkShareWithdrawalRequestApiResource.java index da1a79dc7..e7dedf034 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkShareWithdrawalRequestApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkShareWithdrawalRequestApiResource.java @@ -451,8 +451,18 @@ public class ClerkShareWithdrawalRequestApiResource { // not-applicable rather than failed for a GL request — a share account with no linked // savings is a perfectly valid GL-settlement case. final boolean glSettlementMode = "GL".equals(record.get("settlement_mode")); - checks.add(glSettlementMode - ? checkResult("Linked savings account is Active", true, "Not applicable — settlement is a GL book-transfer") + // 'NONE' is the third mode approve() handles, and submit() produces it on its own: a clerk who + // names the product's own Share Sundry GL as the destination is saying "stop here", so the + // request is downgraded from GL to NONE and approve() posts Dr Share Capital / Cr Share Sundry + // and nothing further. Like a GL settlement it never reaches a savings account, so the + // savings-side checks below do not apply to it either — running them reports a missing fund + // source mapping that no posting in this mode is ever going to read. + final boolean sundryOnlySettlement = "NONE".equals(record.get("settlement_mode")); + final boolean noSavingsLeg = glSettlementMode || sundryOnlySettlement; + checks.add(noSavingsLeg + ? checkResult("Linked savings account is Active", true, sundryOnlySettlement + ? "Not applicable — the redemption rests in Share Sundry" + : "Not applicable — settlement is a GL book-transfer") : checkResult("Linked savings account is Active", savingsAccountId != null && savingsStatus != null && savingsStatus == 300, savingsAccountId == null ? "No linked savings account configured" : "Account #" + savingsAccountId + " — " + savingsStatusLabel(savingsStatus))); @@ -541,6 +551,9 @@ public class ClerkShareWithdrawalRequestApiResource { final boolean settlementGlPresent = glAccountIdObj != null; checks.add(checkResult("Settlement GL Account recorded", settlementGlPresent, settlementGlPresent ? glCodeOf(((Number) glAccountIdObj).longValue()) : "Missing")); + } else if (sundryOnlySettlement) { + checks.add(checkResult("Settlement destination recorded", true, + "Share Sundry — the redemption stops there, so no fund source mapping is read")); } else { boolean glMappingOk = false; String glMappingDetail = "Linked savings account or settlement payment type missing — cannot check"; @@ -992,8 +1005,8 @@ public class ClerkShareWithdrawalRequestApiResource { // The purchase that issued the holding - type 500. Its unit price is what the member paid. final BigDecimal unitPrice = jdbcTemplate .queryForList(""" - SELECT unit_price FROM m_share_account_transaction - WHERE share_account_id = ? AND type_enum = 500 AND unit_price IS NOT NULL + SELECT unit_price FROM m_share_account_transactions + WHERE account_id = ? AND is_active = true AND type_enum = 500 AND unit_price IS NOT NULL ORDER BY id DESC LIMIT 1 """, BigDecimal.class, shareAccountId) .stream().findFirst().orElse(null);