diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareAdvanceCollectionApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareAdvanceCollectionApiResource.java index d2a8a5be9..4874057f9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareAdvanceCollectionApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareAdvanceCollectionApiResource.java @@ -712,17 +712,24 @@ public class ShareAdvanceCollectionApiResource { // Every receipt in this settlement is marked applied, not just the one in the path — they // were all consumed by it, and an unmarked one would still show as money awaiting use. The fee // receipt is marked applied too, even though it posted no GL entry of its own. + // + // client_id is rewritten to this account's own client here too -- a voucher can now be found + // and applied from any member's screen, so whoever last searched it (the value it carried + // going in) is not necessarily who its money actually became share capital for. Leaving the + // old value in place would make the receipt's own record misname whose it is the moment it + // settles, which is exactly the figure a receipt-detail popup reads back afterwards. + final Object settledClientId = acct.get("client_id"); for (final Long id : collectionIds) { jdbcTemplate.update( "UPDATE m_share_advance_collection SET status = 'APPLIED', applied_share_account_id = ?, " - + " applied_on_date = ?, applied_gl_transaction_id = ? WHERE id = ?", - shareAccountId, java.sql.Date.valueOf(entryDate), txnId, id); + + " applied_on_date = ?, applied_gl_transaction_id = ?, client_id = ? WHERE id = ?", + shareAccountId, java.sql.Date.valueOf(entryDate), txnId, settledClientId, id); } if (chargeCollectionId != null) { jdbcTemplate.update( "UPDATE m_share_advance_collection SET status = 'APPLIED', applied_share_account_id = ?, " - + " applied_on_date = ?, applied_gl_transaction_id = ? WHERE id = ?", - shareAccountId, java.sql.Date.valueOf(entryDate), txnId, chargeCollectionId); + + " applied_on_date = ?, applied_gl_transaction_id = ?, client_id = ? WHERE id = ?", + shareAccountId, java.sql.Date.valueOf(entryDate), txnId, settledClientId, chargeCollectionId); } // Reveals the purchase transaction in the passbook and transactions views. diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/serialization/ShareAccountDataSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/serialization/ShareAccountDataSerializer.java index c3f1fc7a8..29bbb45d2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/serialization/ShareAccountDataSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/serialization/ShareAccountDataSerializer.java @@ -894,13 +894,11 @@ public class ShareAccountDataSerializer { // already used" does not say which one to go and look at. final Object label = collection.get("voucher_no") != null ? collection.get("voucher_no") : collection.get("receipt_no"); - final Number collectionClientId = (Number) collection.get("client_id"); - if (collectionClientId == null || collectionClientId.longValue() != account.getClientId().longValue()) { - baseDataValidator.reset().parameter(ShareAccountApiConstants.advancecollectionid_paramname).value(advanceCollectionId) - .failWithCodeAndMessage("share.advance.collection.client.mismatch", - "Voucher " + label + " belongs to a different member."); - } - + // No client-match check here, matching the same product decision already applied to the + // first-application Apply Collection flow: a voucher is reachable and attachable from any + // account's screen (see ShareAdvanceCollectionApiResource), so rejecting it again here, + // at the very last step, would only fail a submission the counter was told was valid. + // // Only money still sitting in Sundry can fund a tranche. APPLIED has already become // share capital somewhere, and REFUNDED went back to the member. final String status = (String) collection.get("status"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/AdditionalShareTrancheFundingService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/AdditionalShareTrancheFundingService.java index fcf1b502a..4598e3211 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/AdditionalShareTrancheFundingService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/AdditionalShareTrancheFundingService.java @@ -146,12 +146,18 @@ public class AdditionalShareTrancheFundingService { } // Every receipt behind the tranche, not just the lead one: a member's later instalments have // become share capital too, and one left UNAPPLIED could be spent a second time. + // + // client_id is rewritten to this account's own client here too -- a voucher can now be found + // and applied from any member's screen, so whoever last searched it (the value it carried + // going in) is not necessarily who its money actually became share capital for. Leaving the + // old value in place would make the receipt's own record misname whose it is the moment it + // settles, which is exactly the figure a receipt-detail popup reads back afterwards. for (final Long collectionId : transaction.getAllAdvanceCollectionIds()) { this.jdbcTemplate.update(""" UPDATE m_share_advance_collection - SET status = 'APPLIED', applied_share_account_id = ?, applied_on_date = ? + SET status = 'APPLIED', applied_share_account_id = ?, applied_on_date = ?, client_id = ? WHERE id = ? AND status = 'UNAPPLIED' - """, account.getId(), java.sql.Date.valueOf(DateUtils.getBusinessLocalDate()), collectionId); + """, account.getId(), java.sql.Date.valueOf(DateUtils.getBusinessLocalDate()), account.getClientId(), collectionId); } }