FINERACT-2498: Add GROUP as a Guarantor Type to Support Group Savings Accounts as Loan Collateral

This commit is contained in:
Ralph Hopman
2026-02-20 11:44:46 +00:00
committed by Adam Saghy
parent 55c51b140e
commit 76d108953b
11 changed files with 387 additions and 9 deletions
@@ -141,6 +141,7 @@ public final class TemplatePopulateImportConstants {
// Guarantor Types
public static final String GUARANTOR_INTERNAL = "Internal";
public static final String GUARANTOR_EXTERNAL = "External";
public static final String GUARANTOR_GROUP = "Group";
// Loan Account/Loan repayment Client External Id
public static final Boolean CONTAINS_CLIENT_EXTERNAL_ID = true;
@@ -94,6 +94,8 @@ public class GuarantorImportHandler implements ImportHandler {
guarantorTypeId = 1;
} else if (guarantorType.equalsIgnoreCase(TemplatePopulateImportConstants.GUARANTOR_EXTERNAL)) {
guarantorTypeId = 3;
} else if (guarantorType.equalsIgnoreCase(TemplatePopulateImportConstants.GUARANTOR_GROUP)) {
guarantorTypeId = 4;
}
}
String clientName = ImportHandlerUtils.readAsString(GuarantorConstants.ENTITY_ID_COL, row);
@@ -209,8 +209,9 @@ public class GuarantorWorkbookPopulator extends AbstractWorkbookPopulator {
"INDIRECT(CONCATENATE(\"Account_\",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE($B1,\" \",\"_\"),\"(\",\"_\"),\")\",\"_\")))");
DataValidationConstraint savingsaccountNumberConstraint = validationHelper.createFormulaListConstraint(
"INDIRECT(CONCATENATE(\"SavingsAccount_\",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE($G1,\" \",\"_\"),\"(\",\"_\"),\")\",\"_\")))");
DataValidationConstraint guranterTypeConstraint = validationHelper.createExplicitListConstraint(
new String[] { TemplatePopulateImportConstants.GUARANTOR_INTERNAL, TemplatePopulateImportConstants.GUARANTOR_EXTERNAL });
DataValidationConstraint guranterTypeConstraint = validationHelper
.createExplicitListConstraint(new String[] { TemplatePopulateImportConstants.GUARANTOR_INTERNAL,
TemplatePopulateImportConstants.GUARANTOR_EXTERNAL, TemplatePopulateImportConstants.GUARANTOR_GROUP });
DataValidationConstraint guarantorRelationshipConstraint = validationHelper.createFormulaListConstraint("GuarantorRelationship");
DataValidationConstraint entityofficeNameConstraint = validationHelper.createFormulaListConstraint("Office");
DataValidationConstraint entityclientNameConstraint = validationHelper
@@ -207,4 +207,8 @@ public class GuarantorData implements IGuarantor {
public boolean isStaffMember() {
return GuarantorType.STAFF.getValue().equals(this.guarantorType.getId().intValue());
}
public boolean isExistingGroup() {
return GuarantorType.GROUP.getValue().equals(this.guarantorType.getId().intValue());
}
}
@@ -188,6 +188,10 @@ public class Guarantor extends AbstractPersistableCustom<Long> {
return GuarantorType.STAFF.getValue().equals(this.gurantorType);
}
public boolean isExistingGroup() {
return GuarantorType.GROUP.getValue().equals(this.gurantorType);
}
public boolean isExternalGuarantor() {
return GuarantorType.EXTERNAL.getValue().equals(this.gurantorType);
}
@@ -390,7 +390,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
if (guarantor.isSelfGuarantee()) {
selfGuarantorList.add(guarantorFundingDetails);
selfGuarantee = selfGuarantee.add(guarantorFundingDetails.getAmountRemaining());
} else if (guarantor.isExistingCustomer()) {
} else if (guarantor.isExistingCustomer() || guarantor.isExistingGroup()) {
externalGuarantorList.add(guarantorFundingDetails);
guarantorGuarantee = guarantorGuarantee.add(guarantorFundingDetails.getAmountRemaining());
}
@@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.account.domain.AccountAssociationType;
import org.apache.fineract.portfolio.account.domain.AccountAssociations;
import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.guarantor.GuarantorConstants;
@@ -70,6 +71,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
private final ClientRepositoryWrapper clientRepositoryWrapper;
private final StaffRepositoryWrapper staffRepositoryWrapper;
private final GroupRepositoryWrapper groupRepositoryWrapper;
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final GuarantorRepository guarantorRepository;
private final GuarantorCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@@ -81,11 +83,13 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
@Autowired
public GuarantorWritePlatformServiceJpaRepositoryIImpl(final LoanRepositoryWrapper loanRepositoryWrapper,
final GuarantorRepository guarantorRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
final StaffRepositoryWrapper staffRepositoryWrapper, final GuarantorCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final StaffRepositoryWrapper staffRepositoryWrapper, final GroupRepositoryWrapper groupRepositoryWrapper,
final GuarantorCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final CodeValueRepositoryWrapper codeValueRepositoryWrapper, final SavingsAccountAssembler savingsAccountAssembler,
final AccountAssociationsRepository accountAssociationsRepository, final GuarantorDomainService guarantorDomainService) {
this.loanRepositoryWrapper = loanRepositoryWrapper;
this.clientRepositoryWrapper = clientRepositoryWrapper;
this.groupRepositoryWrapper = groupRepositoryWrapper;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.guarantorRepository = guarantorRepository;
this.staffRepositoryWrapper = staffRepositoryWrapper;
@@ -148,6 +152,8 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
String defaultUserMessage = null;
if (guarantorTypeId.equals(GuarantorType.STAFF.getValue())) {
defaultUserMessage = this.staffRepositoryWrapper.findOneWithNotFoundDetection(entityId).displayName();
} else if (guarantorTypeId.equals(GuarantorType.GROUP.getValue())) {
defaultUserMessage = this.groupRepositoryWrapper.findOneWithNotFoundDetection(entityId).getName();
} else {
defaultUserMessage = this.clientRepositoryWrapper.findOneWithNotFoundDetection(entityId).getDisplayName();
}
@@ -225,12 +231,19 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
final List<Guarantor> existGuarantorList = this.guarantorRepository.findByLoan(loan);
final Integer guarantorTypeId = guarantorCommand.getGuarantorTypeId();
final GuarantorType guarantorType = GuarantorType.fromInt(guarantorTypeId);
if (guarantorType.isCustomer() || guarantorType.isStaff()) {
if (guarantorType.isCustomer() || guarantorType.isStaff() || guarantorType.isGroup()) {
final Long entityId = guarantorCommand.getEntityId();
for (final Guarantor guarantor : existGuarantorList) {
if (guarantor.getEntityId().equals(entityId) && guarantor.getGurantorType().equals(guarantorTypeId)
&& !guarantorForUpdate.getId().equals(guarantor.getId())) {
String defaultUserMessage = this.clientRepositoryWrapper.findOneWithNotFoundDetection(entityId).getDisplayName();
String defaultUserMessage = null;
if (guarantorTypeId.equals(GuarantorType.STAFF.getValue())) {
defaultUserMessage = this.staffRepositoryWrapper.findOneWithNotFoundDetection(entityId).displayName();
} else if (guarantorTypeId.equals(GuarantorType.GROUP.getValue())) {
defaultUserMessage = this.groupRepositoryWrapper.findOneWithNotFoundDetection(entityId).getName();
} else {
defaultUserMessage = this.clientRepositoryWrapper.findOneWithNotFoundDetection(entityId).getDisplayName();
}
defaultUserMessage = defaultUserMessage + " is already exist as a guarantor for this loan";
final String action = loan.client() != null ? "client.guarantor" : "group.guarantor";
throw new DuplicateGuarantorException(action, "is.already.exist.same.loan", defaultUserMessage, entityId, loanId);
@@ -336,6 +349,9 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
} else if (guarantor.isExistingEmployee()) {
this.staffRepositoryWrapper.findOneWithNotFoundDetection(guarantor.getEntityId());
} else if (guarantor.isExistingGroup()) {
// check group exists
this.groupRepositoryWrapper.findOneWithNotFoundDetection(guarantor.getEntityId());
}
}