Add extended fields to ClientNonPersonDetails: authorizedSignatory, additionalInfo, dateOfRegistration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-04-04 15:06:45 +05:30
co-authored by Claude Opus 4.6
parent 90c21d40c1
commit 87e132f93d
147 changed files with 422232 additions and 167 deletions
@@ -32,4 +32,8 @@ public interface GlAccountTypeMapper {
@Mapping(target = "description", source = "glAccountType.code")
EnumOptionData map(GLAccountType glAccountType);
default GLAccountType map(Integer value) {
return GLAccountType.fromInt(value);
}
}
@@ -647,6 +647,35 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder verifyCinClientKyc(final Long clientId, final Long kycId) {
this.actionName = "VERIFYCIN";
this.entityName = "CLIENTKYC";
this.entityId = kycId;
this.clientId = clientId;
this.href = "/clients/" + clientId + "/kyc/" + kycId + "?command=verify-cin";
return this;
}
public CommandWrapperBuilder verifyDinClientKyc(final Long clientId, final Long kycId) {
this.actionName = "VERIFYDIN";
this.entityName = "CLIENTKYC";
this.entityId = kycId;
this.clientId = clientId;
this.href = "/clients/" + clientId + "/kyc/" + kycId + "?command=verify-din";
return this;
}
// ── Form 60 ──────────────────────────────────────────────────────────────
public CommandWrapperBuilder createClientForm60(final Long clientId) {
this.actionName = "CREATE";
this.entityName = "CLIENTFORM60";
this.entityId = null;
this.clientId = clientId;
this.href = "/clients/" + clientId + "/form60";
return this;
}
public CommandWrapperBuilder createClient() {
this.actionName = "CREATE";
this.entityName = "CLIENT";
@@ -58,6 +58,7 @@ public class ClientApiConstants {
public static final String CLIENT_WITHDRAW_REASON = "ClientWithdrawReason";
public static final String GENDER = "Gender";
public static final String SALUTATION = "Salutation";
public static final String CLIENT_TYPE = "ClientType";
public static final String CLIENT_CLASSIFICATION = "ClientClassification";
@@ -72,8 +73,9 @@ public class ClientApiConstants {
public static final String dateFormatParamName = "dateFormat";
public static final String address = "address";
public static final String familyMembers = "familyMembers";
public static final String MARITALSTATUS = "MARITALSTATUS";
public static final String MARITAL_STATUS = "MaritalStatus";
public static final String maritalStatusIdParamName = "maritalStatusId";
public static final String maritalStatusParamName = "maritalStatus";
public static final String CLIENT_TYPE_INDIVIDUAL = "Individual";
@@ -84,6 +86,7 @@ public class ClientApiConstants {
public static final String cifNumberParamName = "cifNumber";
public static final String externalIdParamName = "externalId";
public static final String mobileNoParamName = "mobileNo";
public static final String alternateMobileNoParamName = "alternateMobileNo";
public static final String emailAddressParamName = "emailAddress";
public static final String firstnameParamName = "firstname";
public static final String middlenameParamName = "middlename";
@@ -112,6 +115,8 @@ public class ClientApiConstants {
public static final String dateOfBirthParamName = "dateOfBirth";
public static final String genderIdParamName = "genderId";
public static final String genderParamName = "gender";
public static final String salutationIdParamName = "salutationId";
public static final String salutationParamName = "salutation";
public static final String clientTypeIdParamName = "clientTypeId";
public static final String clientTypeParamName = "clientType";
public static final String clientClassificationIdParamName = "clientClassificationId";
@@ -120,6 +125,24 @@ public class ClientApiConstants {
public static final String occupationCategoryParamName = "occupationCategory";
public static final String occupationIdParamName = "occupationId";
public static final String occupationParamName = "occupation";
public static final String monthlyIncomeParamName = "monthlyIncome";
public static final String annualTurnoverParamName = "annualTurnover";
public static final String ageYearsParamName = "ageYears";
public static final String ageMonthsParamName = "ageMonths";
public static final String ageDaysParamName = "ageDays";
public static final String nationalityIdParamName = "nationalityId";
public static final String isMinorParamName = "isMinor";
public static final String guardianClientIdParamName = "guardianClientId";
public static final String guardianClientDisplayNameParamName = "guardianClientDisplayName";
public static final String guardianRelationParamName = "guardianRelation";
public static final String dipVerifiedParamName = "dipVerified";
public static final String dipLookupLogIdParamName = "dipLookupLogId";
public static final String dipTimestampParamName = "dipTimestamp";
public static final String alternateDipVerifiedParamName = "alternateDipVerified";
public static final String alternateDipLookupLogIdParamName = "alternateDipLookupLogId";
public static final String alternateDipTimestampParamName = "alternateDipTimestamp";
public static final String nameVerifiedParamName = "nameVerified";
public static final String screeningLogIdParamName = "screeningLogId";
public static final String legalFormIdParamName = "legalFormId";
public static final String legalFormParamName = "legalForm";
// request parameters for payment details
@@ -137,6 +160,9 @@ public class ClientApiConstants {
public static final String incorpValidityTillParamName = "incorpValidityTillDate";
public static final String constitutionIdParamName = "constitutionId";
public static final String mainBusinessLineIdParamName = "mainBusinessLineId";
public static final String authorizedSignatoryParamName = "authorizedSignatory";
public static final String additionalInfoParamName = "additionalInfo";
public static final String dateOfRegistrationParamName = "dateOfRegistration";
// response parameters
public static final String statusParamName = "status";
@@ -206,7 +232,12 @@ public class ClientApiConstants {
officeNameParamName, transferToOfficeIdParamName, transferToOfficeNameParamName, hierarchyParamName, imageIdParamName,
imagePresentParamName, staffIdParamName, staffNameParamName, timelineParamName, groupsParamName, officeOptionsParamName,
staffOptionsParamName, dateOfBirthParamName, genderParamName, clientTypeParamName, clientClassificationParamName,
occupationCategoryParamName, occupationParamName,
salutationParamName, occupationCategoryParamName, occupationParamName, maritalStatusParamName, monthlyIncomeParamName,
annualTurnoverParamName, ageYearsParamName, ageMonthsParamName, ageDaysParamName,
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianClientDisplayNameParamName, guardianRelationParamName,
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
alternateMobileNoParamName, alternateDipVerifiedParamName, alternateDipLookupLogIdParamName, alternateDipTimestampParamName,
nameVerifiedParamName, screeningLogIdParamName,
legalFormParamName, clientNonPersonDetailsParamName, isStaffParamName, legalFormParamName));
protected static final Set<String> CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(chargeIdParamName,
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.client.data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
@@ -66,13 +67,34 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private String fullname;
private String displayName;
private String mobileNo;
private String alternateMobileNo;
private String emailAddress;
private LocalDate dateOfBirth;
private CodeValueData gender;
private CodeValueData salutation;
private CodeValueData clientType;
private CodeValueData clientClassification;
private CodeValueData occupationCategory;
private CodeValueData occupation;
private CodeValueData maritalStatus;
private BigDecimal monthlyIncome;
private BigDecimal annualTurnover;
private Integer ageYears;
private Integer ageMonths;
private Integer ageDays;
private String nationality;
private Boolean isMinor;
private Long guardianClientId;
private String guardianClientDisplayName;
private String guardianRelation;
private Boolean dipVerified;
private Long dipLookupLogId;
private String dipTimestamp;
private Boolean alternateDipVerified;
private Long alternateDipLookupLogId;
private String alternateDipTimestamp;
private Boolean nameVerified;
private Long screeningLogId;
private Boolean isStaff;
private Long officeId;
@@ -103,6 +125,7 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private Collection<SavingsProductData> savingProductOptions;
private Collection<SavingsAccountData> savingAccountOptions;
private Collection<CodeValueData> genderOptions;
private Collection<CodeValueData> salutationOptions;
private Collection<CodeValueData> clientTypeOptions;
private Collection<CodeValueData> clientClassificationOptions;
private Collection<CodeValueData> occupationCategoryOptions;
@@ -284,7 +307,8 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> narrations,
final Collection<CodeValueData> genderOptions, final Collection<SavingsProductData> savingProductOptions,
final Collection<CodeValueData> genderOptions, final Collection<CodeValueData> salutationOptions,
final Collection<SavingsProductData> savingProductOptions,
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions,
final Collection<CodeValueData> occupationCategoryOptions, final Collection<CodeValueData> occupationOptions,
final Collection<CodeValueData> clientNonPersonConstitutionOptions,
@@ -330,6 +354,7 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
clientNonPersonDetails, clientLegalFormOptions, familyMemberOptions, legalForm, address, isAddressEnabled, datatables,
isStaff, clientCollateralManagements);
data.salutationOptions = salutationOptions;
data.occupationCategoryOptions = occupationCategoryOptions;
data.occupationOptions = occupationOptions;
return data;
@@ -351,10 +376,32 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
templateData.familyMemberOptions, clientData.legalForm, clientData.address, clientData.isAddressEnabled, null,
clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.salutation = clientData.salutation;
data.salutationOptions = templateData.salutationOptions;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.occupationCategoryOptions = templateData.occupationCategoryOptions;
data.occupationOptions = templateData.occupationOptions;
data.maritalStatus = clientData.maritalStatus;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
data.nationality = clientData.nationality;
data.isMinor = clientData.isMinor;
data.guardianClientId = clientData.guardianClientId;
data.guardianClientDisplayName = clientData.guardianClientDisplayName;
data.guardianRelation = clientData.guardianRelation;
data.alternateMobileNo = clientData.alternateMobileNo;
data.dipVerified = clientData.dipVerified;
data.dipLookupLogId = clientData.dipLookupLogId;
data.dipTimestamp = clientData.dipTimestamp;
data.alternateDipVerified = clientData.alternateDipVerified;
data.alternateDipLookupLogId = clientData.alternateDipLookupLogId;
data.alternateDipTimestamp = clientData.alternateDipTimestamp;
data.nameVerified = clientData.nameVerified;
data.screeningLogId = clientData.screeningLogId;
return data;
}
@@ -375,10 +422,32 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
clientData.familyMemberOptions, clientData.legalForm, clientData.address, clientData.isAddressEnabled, null,
clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.salutation = clientData.salutation;
data.salutationOptions = clientData.salutationOptions;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.occupationCategoryOptions = clientData.occupationCategoryOptions;
data.occupationOptions = clientData.occupationOptions;
data.maritalStatus = clientData.maritalStatus;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
data.nationality = clientData.nationality;
data.isMinor = clientData.isMinor;
data.guardianClientId = clientData.guardianClientId;
data.guardianClientDisplayName = clientData.guardianClientDisplayName;
data.guardianRelation = clientData.guardianRelation;
data.alternateMobileNo = clientData.alternateMobileNo;
data.dipVerified = clientData.dipVerified;
data.dipLookupLogId = clientData.dipLookupLogId;
data.dipTimestamp = clientData.dipTimestamp;
data.alternateDipVerified = clientData.alternateDipVerified;
data.alternateDipLookupLogId = clientData.alternateDipLookupLogId;
data.alternateDipTimestamp = clientData.alternateDipTimestamp;
data.nameVerified = clientData.nameVerified;
data.screeningLogId = clientData.screeningLogId;
return data;
}
@@ -397,8 +466,29 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.familyMemberOptions, clientData.legalForm,
clientData.address, clientData.isAddressEnabled, null, clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.salutation = clientData.salutation;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.maritalStatus = clientData.maritalStatus;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
data.nationality = clientData.nationality;
data.isMinor = clientData.isMinor;
data.guardianClientId = clientData.guardianClientId;
data.guardianClientDisplayName = clientData.guardianClientDisplayName;
data.guardianRelation = clientData.guardianRelation;
data.alternateMobileNo = clientData.alternateMobileNo;
data.dipVerified = clientData.dipVerified;
data.dipLookupLogId = clientData.dipLookupLogId;
data.dipTimestamp = clientData.dipTimestamp;
data.alternateDipVerified = clientData.alternateDipVerified;
data.alternateDipLookupLogId = clientData.alternateDipLookupLogId;
data.alternateDipTimestamp = clientData.alternateDipTimestamp;
data.nameVerified = clientData.nameVerified;
data.screeningLogId = clientData.screeningLogId;
return data;
}
@@ -513,10 +603,11 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
final CodeValueData subStatus, final Long officeId, final String officeName, final Long transferToOfficeId,
final String transferToOfficeName, final Long id, final String firstname, final String middlename, final String lastname,
final String fullname, final String displayName, final ExternalId externalId, final String mobileNo,
final String emailAddress, final LocalDate dateOfBirth, final CodeValueData gender, final LocalDate activationDate,
final Long imageId, final Long staffId, final String staffName, final ClientTimelineData timeline,
final Long savingsProductId, final String savingsProductName, final Long savingsAccountId, final CodeValueData clientType,
final CodeValueData clientClassification, final CodeValueData occupationCategory, final CodeValueData occupation,
final String emailAddress, final LocalDate dateOfBirth, final CodeValueData gender, final CodeValueData salutation,
final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final ClientTimelineData timeline, final Long savingsProductId, final String savingsProductName,
final Long savingsAccountId, final CodeValueData clientType, final CodeValueData clientClassification,
final CodeValueData occupationCategory, final CodeValueData occupation,
final EnumOptionData legalForm, final ClientNonPersonData clientNonPerson, final Boolean isStaff) {
final Collection<OfficeData> allowedOffices = null;
@@ -538,6 +629,7 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
clientNonPerson, clientLegalFormOptions, familyMemberOptions, legalForm, null, null, null, isStaff, null);
data.cifNumber = cifNumber;
data.salutation = salutation;
data.occupationCategory = occupationCategory;
data.occupation = occupation;
return data;
@@ -57,4 +57,11 @@ public class ClientFamilyMemberRequest implements Serializable {
private String nominationType;
private BigDecimal percentageShare;
private String remarks;
private String aadhaarNumber;
private String panNumber;
private String nationality;
private Boolean isAlive;
private Long linkedClientId;
private String marriageDate;
private String marriageAuthority;
}
@@ -73,6 +73,17 @@ public final class ClientFamilyMembersData implements Serializable {
private final String remarks;
// CBS extended fields
private final String aadhaarNumber;
private final String panNumber;
private final String nationality;
private final Boolean isAlive;
private final Long linkedClientId;
private final String linkedClientName;
private final String linkedClientCif;
private final LocalDate marriageDate;
private final String marriageAuthority;
// template holder
private final Collection<CodeValueData> relationshipIdOptions;
private final Collection<CodeValueData> genderIdOptions;
@@ -33,6 +33,9 @@ public class ClientNonPersonData implements Serializable {
private final LocalDate incorpValidityTillDate;
private final CodeValueData mainBusinessLine;
private final String remarks;
private final String authorizedSignatory;
private final String additionalInfo;
private final LocalDate dateOfRegistration;
// import fields
private Long mainBusinessLineId;
@@ -58,16 +61,23 @@ public class ClientNonPersonData implements Serializable {
this.locale = locale;
this.constitution = null;
this.mainBusinessLine = null;
this.authorizedSignatory = null;
this.additionalInfo = null;
this.dateOfRegistration = null;
}
public ClientNonPersonData(CodeValueData constitution, String incorpNo, LocalDate incorpValidityTillDate,
CodeValueData mainBusinessLine, String remarks) {
CodeValueData mainBusinessLine, String remarks, String authorizedSignatory, String additionalInfo,
LocalDate dateOfRegistration) {
this.constitution = constitution;
this.incorpNumber = incorpNo;
this.incorpValidityTillDate = incorpValidityTillDate;
this.mainBusinessLine = mainBusinessLine;
this.remarks = remarks;
this.authorizedSignatory = authorizedSignatory;
this.additionalInfo = additionalInfo;
this.dateOfRegistration = dateOfRegistration;
}
}
@@ -108,6 +108,9 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@Column(name = "mobile_no", length = 50, unique = true)
private String mobileNo;
@Column(name = "alternate_mobile_no", length = 50)
private String alternateMobileNo;
@Column(name = "email_address", length = 50, unique = true)
private String emailAddress;
@@ -124,6 +127,10 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@JoinColumn(name = "gender_cv_id")
private CodeValue gender;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "salutation_cv_id")
private CodeValue salutation;
@ManyToOne
@JoinColumn(name = "staff_id")
private Staff staff;
@@ -201,6 +208,53 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@JoinColumn(name = "occupation_cv_id")
private CodeValue occupation;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "marital_status_cv_id")
private CodeValue maritalStatus;
@Column(name = "monthly_income")
private java.math.BigDecimal monthlyIncome;
@Column(name = "annual_turnover")
private java.math.BigDecimal annualTurnover;
@Column(name = "nationality", length = 100)
private String nationality;
@Column(name = "is_minor")
private Boolean isMinor;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guardian_client_id")
private Client guardianClient;
@Column(name = "guardian_relation", length = 50)
private String guardianRelation;
@Column(name = "dip_verified")
private Boolean dipVerified;
@Column(name = "dip_lookup_log_id")
private Long dipLookupLogId;
@Column(name = "dip_timestamp")
private String dipTimestamp;
@Column(name = "alternate_dip_verified")
private Boolean alternateDipVerified;
@Column(name = "alternate_dip_lookup_log_id")
private Long alternateDipLookupLogId;
@Column(name = "alternate_dip_timestamp")
private String alternateDipTimestamp;
@Column(name = "name_verified")
private Boolean nameVerified;
@Column(name = "screening_log_id")
private Long screeningLogId;
@Column(name = "legal_form_enum")
private Integer legalForm;
@@ -222,11 +276,12 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
final String fullname, final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId,
final String mobileNo, final String emailAddress, final Staff staff, final LocalDate submittedOnDate,
final Long savingsProductId, final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender,
final CodeValue clientType, final CodeValue clientClassification, final CodeValue occupationCategory,
final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
final CodeValue salutation, final CodeValue clientType, final CodeValue clientClassification,
final CodeValue occupationCategory, final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
return new Client(currentUser, status, office, clientParentGroup, accountNo, cifNumber, firstname, middlename, lastname, fullname,
activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff, submittedOnDate, savingsProductId,
savingsAccountId, dateOfBirth, gender, clientType, clientClassification, occupationCategory, occupation, legalForm, isStaff);
savingsAccountId, dateOfBirth, gender, salutation, clientType, clientClassification, occupationCategory, occupation,
legalForm, isStaff);
}
protected Client() {}
@@ -236,8 +291,8 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
final String fullname, final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId,
final String mobileNo, final String emailAddress, final Staff staff, final LocalDate submittedOnDate,
final Long savingsProductId, final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender,
final CodeValue clientType, final CodeValue clientClassification, final CodeValue occupationCategory,
final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
final CodeValue salutation, final CodeValue clientType, final CodeValue clientClassification,
final CodeValue occupationCategory, final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
@@ -300,6 +355,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
if (gender != null) {
this.gender = gender;
}
this.salutation = salutation;
this.dateOfBirth = dateOfBirth;
@@ -486,7 +542,13 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
} else {
StringBuilder nameBuilder = new StringBuilder();
if (legalForm == null || LegalForm.fromInt(legalForm).isPerson()) {
if (this.salutation != null && StringUtils.isNotBlank(this.salutation.getLabel())) {
nameBuilder.append(this.salutation.getLabel());
}
if (StringUtils.isNotBlank(this.firstname)) {
if (!nameBuilder.isEmpty()) {
nameBuilder.append(' ');
}
nameBuilder.append(this.firstname);
}
if (StringUtils.isNotBlank(this.middlename)) {
@@ -632,6 +694,18 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return genderId;
}
public Long salutationId() {
Long salutationId = null;
if (this.salutation != null) {
salutationId = this.salutation.getId();
}
return salutationId;
}
public void updateSalutation(CodeValue salutation) {
this.salutation = salutation;
}
public Long clientTypeId() {
Long clientTypeId = null;
if (this.clientType != null) {
@@ -696,6 +770,18 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.occupation = occupation;
}
public Long maritalStatusId() {
Long maritalStatusId = null;
if (this.maritalStatus != null) {
maritalStatusId = this.maritalStatus.getId();
}
return maritalStatusId;
}
public void updateMaritalStatus(CodeValue maritalStatus) {
this.maritalStatus = maritalStatus;
}
public void updateGender(CodeValue gender) {
this.gender = gender;
}
@@ -738,6 +824,10 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.status = ClientStatus.PENDING.getValue();
}
public Integer getLegalForm() {
return this.legalForm;
}
public void setLegalForm(Integer legalForm) {
this.legalForm = legalForm;
}
@@ -0,0 +1,93 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
/**
* Form 60 declaration as per Rule 114B of Income Tax Rules, 1962.
* Filed by individuals who do not have a PAN for specified financial transactions.
*/
@Entity
@Getter
@Table(name = "m_client_form60")
public class ClientForm60 extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "full_name", length = 200, nullable = false)
private String fullName;
@Column(name = "date_of_birth")
private LocalDate dateOfBirth;
@Column(name = "father_name", length = 200)
private String fatherName;
@Column(name = "address", length = 500)
private String address;
@Column(name = "transaction_type", length = 100, nullable = false)
private String transactionType;
@Column(name = "transaction_amount", scale = 6, precision = 19)
private BigDecimal transactionAmount;
@Column(name = "estimated_total_income", scale = 6, precision = 19)
private BigDecimal estimatedTotalIncome;
@Column(name = "reason_for_no_pan", length = 200)
private String reasonForNoPan;
@Column(name = "declaration", nullable = false)
private boolean declaration;
@Column(name = "submitted_on")
private LocalDate submittedOn;
protected ClientForm60() {}
public static ClientForm60 fromJson(final Client client, final JsonCommand command) {
final ClientForm60 form = new ClientForm60();
form.client = client;
form.fullName = command.stringValueOfParameterNamed("fullName");
form.dateOfBirth = command.localDateValueOfParameterNamed("dateOfBirth");
form.fatherName = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("fatherName"), null);
form.address = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("address"), null);
form.transactionType = command.stringValueOfParameterNamed("transactionType");
form.transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
form.estimatedTotalIncome = command.bigDecimalValueOfParameterNamed("estimatedTotalIncome");
form.reasonForNoPan = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("reasonForNoPan"), null);
form.declaration = command.booleanPrimitiveValueOfParameterNamed("declaration");
form.submittedOn = LocalDate.now();
return form;
}
}
@@ -0,0 +1,32 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.domain;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientForm60Repository extends JpaRepository<ClientForm60, Long> {
List<ClientForm60> findByClientId(Long clientId);
Optional<ClientForm60> findByIdAndClientId(Long id, Long clientId);
}
@@ -77,8 +77,14 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@Column(name = "pan_full_name", length = 200)
private String panFullName;
/** Y = YES, N = NO, NA = Not Available (Aadhaar seeding status on PAN card) */
@Column(name = "pan_aadhaar_seeding_status", length = 5)
@Column(name = "pan_first_name", length = 200)
private String panFirstName;
@Column(name = "pan_last_name", length = 200)
private String panLastName;
/** LINKED, NOT_LINKED, Y, N, NA etc. (Aadhaar seeding status on PAN card) */
@Column(name = "pan_aadhaar_seeding_status", length = 20)
private String panAadhaarSeedingStatus;
/** PAN card category: individual, company, firm, etc. */
@@ -110,6 +116,87 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@Column(name = "gstin_verified_on")
private LocalDate gstinVerifiedOn;
// ── Enterprise / Non-Individual fields ──────────────────────────────────
@Column(name = "enterprise_pan", length = 10)
private String enterprisePan;
@Column(name = "cin_number", length = 21)
private String cinNumber;
@Column(name = "cin_verified", nullable = false)
private boolean cinVerified;
@Column(name = "cin_verified_on")
private LocalDate cinVerifiedOn;
// ── DIN (Director Identification Number) ────────────────────────────────
@Column(name = "din_number", length = 8)
private String dinNumber;
@Column(name = "din_verified", nullable = false)
private boolean dinVerified;
@Column(name = "din_verified_on")
private LocalDate dinVerifiedOn;
@Column(name = "incorporation_date")
private LocalDate incorporationDate;
// ── KYC Document ─────────────────────────────────────────────────────────
@Column(name = "kyc_document_name", length = 100)
private String kycDocumentName;
@Column(name = "kyc_document_number", length = 50)
private String kycDocumentNumber;
@Column(name = "kyc_doc_issue_date")
private LocalDate kycDocIssueDate;
@Column(name = "kyc_doc_expiry_date")
private LocalDate kycDocExpiryDate;
// ── AML / Compliance flags ───────────────────────────────────────────────
@Column(name = "aml_check_status", length = 20)
private String amlCheckStatus;
@Column(name = "banned_entity_match", length = 10)
private String bannedEntityMatch;
@Column(name = "willful_defaulter", length = 10)
private String willfulDefaulter;
@Column(name = "ecgc_sal_flag", length = 10)
private String ecgcSalFlag;
@Column(name = "dormant_flag", length = 20)
private String dormantFlag;
// ── Account status / Freeze ──────────────────────────────────────────────
@Column(name = "account_status", length = 20)
private String accountStatus;
@Column(name = "freeze_reason", length = 200)
private String freezeReason;
@Column(name = "freeze_authority", length = 100)
private String freezeAuthority;
// ── Form 60 / Form 15G/15H ───────────────────────────────────────────────
@Column(name = "form60_type", length = 20)
private String form60Type;
@Column(name = "form60_date")
private LocalDate form60Date;
@Column(name = "form15_applicable")
private Boolean form15Applicable;
@Column(name = "form15_type", length = 10)
private String form15Type;
@Column(name = "form15_fy", length = 10)
private String form15Fy;
// ── CKYCRR ───────────────────────────────────────────────────────────────
/** Central KYC Records Registry number issued by CERSAI */
@Column(name = "ckyc_number", length = 14)
@@ -150,17 +237,21 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.panVerified = false;
this.aadhaarVerified = false;
this.gstinVerified = false;
this.cinVerified = false;
this.dinVerified = false;
this.initiatedOn = LocalDate.now();
}
public static ClientKyc initiateKyc(final Client client, final JsonCommand command) {
final Integer kycType = command.integerValueOfParameterNamed("kycType");
final Integer riskCategory = command.integerValueOfParameterNamed("riskCategory");
final String panNumber = command.stringValueOfParameterNamed("panNumber");
final String aadhaarNumberMasked = command.stringValueOfParameterNamed("aadhaarNumberMasked");
final String gstinNumber = command.stringValueOfParameterNamed("gstinNumber");
final String remarks = command.stringValueOfParameterNamed("remarks");
return new ClientKyc(client, kycType, riskCategory, panNumber, aadhaarNumberMasked, gstinNumber, remarks);
final ClientKyc kyc = new ClientKyc(client,
command.integerValueOfParameterNamed("kycType"),
command.integerValueOfParameterNamed("riskCategory"),
command.stringValueOfParameterNamed("panNumber"),
command.stringValueOfParameterNamed("aadhaarNumberMasked"),
command.stringValueOfParameterNamed("gstinNumber"),
command.stringValueOfParameterNamed("remarks"));
kyc.applyExtendedFields(command);
return kyc;
}
/**
@@ -172,6 +263,48 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return new ClientKyc(client, kycType, riskCategory, panNumber, aadhaarNumberMasked, gstinNumber, remarks);
}
private void applyExtendedFields(final JsonCommand command) {
this.panAadhaarSeedingStatus = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("panAadhaarSeedingStatus"), this.panAadhaarSeedingStatus);
this.enterprisePan = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("enterprisePan"), null);
this.cinNumber = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("cinNumber"), null);
this.dinNumber = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("dinNumber"), null);
this.incorporationDate = command.localDateValueOfParameterNamed("incorporationDate");
this.kycDocumentName = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("kycDocumentName"), null);
this.kycDocumentNumber = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("kycDocumentNumber"), null);
this.kycDocIssueDate = command.localDateValueOfParameterNamed("kycDocIssueDate");
this.kycDocExpiryDate = command.localDateValueOfParameterNamed("kycDocExpiryDate");
this.amlCheckStatus = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("amlCheckStatus"), null);
this.bannedEntityMatch = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("bannedEntityMatch"), null);
this.willfulDefaulter = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("willfulDefaulter"), null);
this.ecgcSalFlag = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("ecgcSalFlag"), null);
this.dormantFlag = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("dormantFlag"), null);
this.accountStatus = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("accountStatus"), null);
this.freezeReason = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("freezeReason"), null);
this.freezeAuthority = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("freezeAuthority"), null);
this.form60Type = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("form60Type"), null);
this.form60Date = command.localDateValueOfParameterNamed("form60Date");
this.form15Applicable = command.booleanObjectValueOfParameterNamed("form15Applicable");
this.form15Type = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("form15Type"), null);
this.form15Fy = StringUtils.defaultIfEmpty(
command.stringValueOfParameterNamed("form15FY"), null);
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>();
@@ -210,9 +343,72 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.remarks = StringUtils.defaultIfEmpty(newValue, null);
}
updateStringField(command, "panAadhaarSeedingStatus", this.panAadhaarSeedingStatus, actualChanges,
v -> this.panAadhaarSeedingStatus = v);
updateStringField(command, "enterprisePan", this.enterprisePan, actualChanges, v -> this.enterprisePan = v);
updateStringField(command, "cinNumber", this.cinNumber, actualChanges, v -> this.cinNumber = v);
updateStringField(command, "dinNumber", this.dinNumber, actualChanges, v -> this.dinNumber = v);
updateDateField(command, "incorporationDate", this.incorporationDate, actualChanges,
v -> this.incorporationDate = v);
updateStringField(command, "kycDocumentName", this.kycDocumentName, actualChanges,
v -> this.kycDocumentName = v);
updateStringField(command, "kycDocumentNumber", this.kycDocumentNumber, actualChanges,
v -> this.kycDocumentNumber = v);
updateDateField(command, "kycDocIssueDate", this.kycDocIssueDate, actualChanges,
v -> this.kycDocIssueDate = v);
updateDateField(command, "kycDocExpiryDate", this.kycDocExpiryDate, actualChanges,
v -> this.kycDocExpiryDate = v);
updateStringField(command, "amlCheckStatus", this.amlCheckStatus, actualChanges,
v -> this.amlCheckStatus = v);
updateStringField(command, "bannedEntityMatch", this.bannedEntityMatch, actualChanges,
v -> this.bannedEntityMatch = v);
updateStringField(command, "willfulDefaulter", this.willfulDefaulter, actualChanges,
v -> this.willfulDefaulter = v);
updateStringField(command, "ecgcSalFlag", this.ecgcSalFlag, actualChanges, v -> this.ecgcSalFlag = v);
updateStringField(command, "dormantFlag", this.dormantFlag, actualChanges, v -> this.dormantFlag = v);
updateStringField(command, "accountStatus", this.accountStatus, actualChanges, v -> this.accountStatus = v);
updateStringField(command, "freezeReason", this.freezeReason, actualChanges, v -> this.freezeReason = v);
updateStringField(command, "freezeAuthority", this.freezeAuthority, actualChanges,
v -> this.freezeAuthority = v);
updateStringField(command, "form60Type", this.form60Type, actualChanges, v -> this.form60Type = v);
updateDateField(command, "form60Date", this.form60Date, actualChanges, v -> this.form60Date = v);
updateBooleanField(command, "form15Applicable", this.form15Applicable, actualChanges,
v -> this.form15Applicable = v);
updateStringField(command, "form15Type", this.form15Type, actualChanges, v -> this.form15Type = v);
updateStringField(command, "form15FY", this.form15Fy, actualChanges, v -> this.form15Fy = v);
return actualChanges;
}
private void updateStringField(final JsonCommand command, final String param, final String current,
final Map<String, Object> changes, final java.util.function.Consumer<String> setter) {
if (command.isChangeInStringParameterNamed(param, current)) {
final String newValue = command.stringValueOfParameterNamed(param);
changes.put(param, newValue);
setter.accept(StringUtils.defaultIfEmpty(newValue, null));
}
}
private void updateDateField(final JsonCommand command, final String param, final LocalDate current,
final Map<String, Object> changes, final java.util.function.Consumer<LocalDate> setter) {
if (command.isChangeInLocalDateParameterNamed(param, current)) {
final LocalDate newValue = command.localDateValueOfParameterNamed(param);
changes.put(param, newValue);
setter.accept(newValue);
}
}
private void updateBooleanField(final JsonCommand command, final String param, final Boolean current,
final Map<String, Object> changes, final java.util.function.Consumer<Boolean> setter) {
if (command.parameterExists(param)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(param);
if ((newValue == null && current != null) || (newValue != null && !newValue.equals(current))) {
changes.put(param, newValue);
setter.accept(newValue);
}
}
}
/** Called when documents are submitted and 3rd-party verification is initiated. */
public void markInProgress() {
this.kycStatus = ClientKycStatus.IN_PROGRESS.getValue();
@@ -237,11 +433,13 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.remarks = StringUtils.defaultIfEmpty(remarks, this.remarks);
}
public void markPanVerified(final String fullName, final String aadhaarSeedingStatus,
final String category, final String status) {
public void markPanVerified(final String fullName, final String firstName, final String lastName,
final String aadhaarSeedingStatus, final String category, final String status) {
this.panVerified = true;
this.panVerifiedOn = LocalDate.now();
this.panFullName = StringUtils.defaultIfEmpty(fullName, null);
this.panFirstName = StringUtils.defaultIfEmpty(firstName, null);
this.panLastName = StringUtils.defaultIfEmpty(lastName, null);
this.panAadhaarSeedingStatus = normalizeAadhaarSeedingStatus(aadhaarSeedingStatus);
this.panCategory = StringUtils.defaultIfEmpty(category, null);
this.panStatus = StringUtils.defaultIfEmpty(status, null);
@@ -272,6 +470,38 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.gstinVerifiedOn = LocalDate.now();
}
public void markCinVerified() {
this.cinVerified = true;
this.cinVerifiedOn = LocalDate.now();
}
public void markDinVerified() {
this.dinVerified = true;
this.dinVerifiedOn = LocalDate.now();
}
/**
* Checks if all required verifications are complete for this KYC type and auto-promotes
* to VERIFIED status if so.
* <ul>
* <li>INDIVIDUAL: PAN + Aadhaar both verified</li>
* <li>NON_INDIVIDUAL: PAN + GSTIN both verified</li>
* </ul>
*/
public boolean tryAutoVerify() {
final ClientKycType type = ClientKycType.fromInt(this.kycType);
boolean allDone = false;
if (type != null && type.isIndividual()) {
allDone = this.panVerified && this.aadhaarVerified;
} else if (type != null && type.isNonIndividual()) {
allDone = this.panVerified && this.gstinVerified;
}
if (allDone && !getKycStatus().isVerified()) {
markVerified(this.ckycNumber);
}
return allDone;
}
// ── Accessors ─────────────────────────────────────────────────────────────
public Client getClient() {
@@ -318,6 +548,14 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return panFullName;
}
public String getPanFirstName() {
return panFirstName;
}
public String getPanLastName() {
return panLastName;
}
public String getPanAadhaarSeedingStatus() {
return panAadhaarSeedingStatus;
}
@@ -377,4 +615,104 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
public String getRemarks() {
return remarks;
}
public String getEnterprisePan() {
return enterprisePan;
}
public String getCinNumber() {
return cinNumber;
}
public boolean isCinVerified() {
return cinVerified;
}
public LocalDate getCinVerifiedOn() {
return cinVerifiedOn;
}
public String getDinNumber() {
return dinNumber;
}
public boolean isDinVerified() {
return dinVerified;
}
public LocalDate getDinVerifiedOn() {
return dinVerifiedOn;
}
public LocalDate getIncorporationDate() {
return incorporationDate;
}
public String getKycDocumentName() {
return kycDocumentName;
}
public String getKycDocumentNumber() {
return kycDocumentNumber;
}
public LocalDate getKycDocIssueDate() {
return kycDocIssueDate;
}
public LocalDate getKycDocExpiryDate() {
return kycDocExpiryDate;
}
public String getAmlCheckStatus() {
return amlCheckStatus;
}
public String getBannedEntityMatch() {
return bannedEntityMatch;
}
public String getWillfulDefaulter() {
return willfulDefaulter;
}
public String getEcgcSalFlag() {
return ecgcSalFlag;
}
public String getDormantFlag() {
return dormantFlag;
}
public String getAccountStatus() {
return accountStatus;
}
public String getFreezeReason() {
return freezeReason;
}
public String getFreezeAuthority() {
return freezeAuthority;
}
public String getForm60Type() {
return form60Type;
}
public LocalDate getForm60Date() {
return form60Date;
}
public Boolean getForm15Applicable() {
return form15Applicable;
}
public String getForm15Type() {
return form15Type;
}
public String getForm15Fy() {
return form15Fy;
}
}
@@ -0,0 +1,95 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
/**
* Nominee for a client. Links to an existing client in the system.
* For Individual clients, nominee must be an existing client (no manual entry).
* A client can have multiple nominees with percentage share totalling 100%.
*/
@Entity
@Table(name = "m_client_nominee")
@Getter
@Setter
@NoArgsConstructor
public class ClientNominee extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
/** The nominee — must be an existing client in CBS */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "nominee_client_id", nullable = false)
private Client nomineeClient;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "relationship_cv_id")
private CodeValue relationship;
@Column(name = "percentage_share", precision = 5, scale = 2)
private BigDecimal percentageShare;
@Column(name = "is_active")
private Boolean isActive;
/** If nominee is a minor, guardian details */
@Column(name = "nominee_is_minor")
private Boolean nomineeIsMinor;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guardian_client_id")
private Client guardianClient;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guardian_relationship_cv_id")
private CodeValue guardianRelationship;
@Column(name = "effective_date")
private LocalDate effectiveDate;
@Column(name = "remarks", length = 500)
private String remarks;
/** Auto-generated unique nominee identifier, e.g. NOM-SB00123456-01 */
@Column(name = "nominee_identifier", length = 50, unique = true)
private String nomineeIdentifier;
/** Account number this nominee is linked to */
@Column(name = "account_no", length = 50)
private String accountNo;
/** Account type prefix: SB, CB, FD, RD, LA */
@Column(name = "account_type", length = 10)
private String accountType;
}
@@ -0,0 +1,46 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.domain;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ClientNomineeRepository extends JpaRepository<ClientNominee, Long> {
@Query("SELECT n FROM ClientNominee n WHERE n.client.id = :clientId ORDER BY n.id")
List<ClientNominee> findAllByClientId(@Param("clientId") Long clientId);
@Query("SELECT n FROM ClientNominee n WHERE n.client.id = :clientId AND n.id = :nomineeId")
Optional<ClientNominee> findByClientIdAndId(@Param("clientId") Long clientId, @Param("nomineeId") Long nomineeId);
@Query("SELECT n FROM ClientNominee n WHERE n.client.id = :clientId AND n.isActive = true")
List<ClientNominee> findActiveByClientId(@Param("clientId") Long clientId);
@Query("SELECT n FROM ClientNominee n WHERE n.accountNo = :accountNo AND n.accountType = :accountType AND n.isActive = true")
List<ClientNominee> findActiveByAccountNoAndAccountType(@Param("accountNo") String accountNo, @Param("accountType") String accountType);
@Query("SELECT n FROM ClientNominee n WHERE n.client.id = :clientId AND n.accountNo = :accountNo AND n.accountType = :accountType ORDER BY n.id")
List<ClientNominee> findByClientIdAndAccountNoAndAccountType(@Param("clientId") Long clientId, @Param("accountNo") String accountNo, @Param("accountType") String accountType);
@Query("SELECT COUNT(n) FROM ClientNominee n WHERE n.accountNo = :accountNo AND n.accountType = :accountType")
long countByAccountNoAndAccountType(@Param("accountNo") String accountNo, @Param("accountType") String accountType);
}
@@ -26,8 +26,8 @@ import lombok.Getter;
@Getter
public enum LegalForm {
PERSON(1, "legalFormType.person", "Person"), //
ENTITY(2, "legalFormType.entity", "Entity"); //
PERSON(1, "legalFormType.individual", "Individual"), //
ENTITY(2, "legalFormType.nonIndividual", "Non-Individual"); //
private final Integer value;
private final String code;
@@ -32,6 +32,7 @@ public class SearchedClient {
private final String displayName;
private final ExternalId externalId;
private final String accountNumber;
private final String cifNumber;
private final Long officeId;
private final String officeName;
private final String mobileNo;
@@ -75,9 +75,9 @@ public class SearchingClientRepositoryImpl implements SearchingClientRepository
predicates.add(cb.like(o.get("hierarchy"), hierarchyLikeValue));
String searchLikeValue = "%" + searchText + "%";
predicates.add(cb.or(cb.like(r.get("accountNumber"), searchLikeValue), cb.like(r.get("displayName"), searchLikeValue),
cb.like(r.get("externalId"), searchLikeValue), cb.like(r.get("mobileNo"), searchLikeValue),
cb.like(identity.get("documentKey"), searchLikeValue)));
predicates.add(cb.or(cb.like(r.get("accountNumber"), searchLikeValue), cb.like(r.get("cifNumber"), searchLikeValue),
cb.like(r.get("displayName"), searchLikeValue), cb.like(r.get("externalId"), searchLikeValue),
cb.like(r.get("mobileNo"), searchLikeValue), cb.like(identity.get("documentKey"), searchLikeValue)));
return cb.and(predicates.toArray(new Predicate[0]));
};
@@ -87,8 +87,8 @@ public class SearchingClientRepositoryImpl implements SearchingClientRepository
query.orderBy(orders);
query.select(cb.construct(SearchedClient.class, root.get("id"), root.get("displayName"), root.get("externalId"),
root.get("accountNumber"), office.get("id"), office.get("name"), root.get("mobileNo"), root.get("status"),
root.get("activationDate"), root.get("createdDate")));
root.get("accountNumber"), root.get("cifNumber"), office.get("id"), office.get("name"), root.get("mobileNo"),
root.get("status"), root.get("activationDate"), root.get("createdDate")));
TypedQuery<SearchedClient> queryToExecute = entityManager.createQuery(query);
@@ -0,0 +1,88 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Export Oriented Unit (EOU) entity classification.
* Captures EOU registration, export obligations, FEMA compliance, and AD bank details.
*/
@Entity
@Table(name = "m_client_eou")
@Getter
@Setter
@NoArgsConstructor
public class ClientEou extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "eou_registration_number", length = 50)
private String eouRegistrationNumber;
@Column(name = "registered_dc_zone", length = 50)
private String registeredDcZone;
@Column(name = "bond_lut_number", length = 50)
private String bondLutNumber;
@Column(name = "validity_from")
private LocalDate validityFrom;
@Column(name = "validity_to")
private LocalDate validityTo;
@Column(name = "gstin_eou", length = 15)
private String gstinEou;
@Column(name = "annual_export_obligation", precision = 19, scale = 2)
private BigDecimal annualExportObligation;
@Column(name = "nfe_target", precision = 19, scale = 2)
private BigDecimal nfeTarget;
@Column(name = "softex_filing_status", length = 20)
private String softexFilingStatus;
@Column(name = "brc_submission_status", length = 20)
private String brcSubmissionStatus;
@Column(name = "ad_category_bank_code", length = 20)
private String adCategoryBankCode;
@Column(name = "fema_declaration_date")
private LocalDate femaDeclarationDate;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientEouRepository extends JpaRepository<ClientEou, Long> {
Optional<ClientEou> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,87 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Import/Export (IEC / DGFT) entity classification.
* Captures Importer Exporter Code, trade details, ECGC insurance, and FEMA compliance.
*/
@Entity
@Table(name = "m_client_import_export")
@Getter
@Setter
@NoArgsConstructor
public class ClientImportExport extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "iec_code", length = 10)
private String iecCode;
@Column(name = "iec_issue_date")
private LocalDate iecIssueDate;
@Column(name = "iec_status", length = 20)
private String iecStatus;
@Column(name = "trade_type", length = 30)
private String tradeType;
@Column(name = "primary_hs_code", length = 20)
private String primaryHsCode;
@Column(name = "key_trading_countries", length = 200)
private String keyTradingCountries;
@Column(name = "ad_category_bank_code", length = 20)
private String adCategoryBankCode;
@Column(name = "ecgc_policy_number", length = 50)
private String ecgcPolicyNumber;
@Column(name = "ecgc_policy_expiry")
private LocalDate ecgcPolicyExpiry;
@Column(name = "eefc_account_required")
private Boolean eefcAccountRequired;
@Column(name = "pcfc_facility_required")
private Boolean pcfcFacilityRequired;
@Column(name = "fema_declaration_obtained")
private Boolean femaDeclarationObtained;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientImportExportRepository extends JpaRepository<ClientImportExport, Long> {
Optional<ClientImportExport> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,93 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
@Entity
@Table(name = "m_client_msme")
@Getter
@Setter
@NoArgsConstructor
public class ClientMsme extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
// Udyam Registration
@Column(name = "udyam_registration_number", length = 30)
private String udyamRegistrationNumber;
@Column(name = "registration_date")
private LocalDate registrationDate;
@Column(name = "registration_status", length = 20)
private String registrationStatus;
@Column(name = "msme_classification", length = 20)
private String msmeClassification;
@Column(name = "enterprise_type", length = 30)
private String enterpriseType;
@Column(name = "nic_activity_code", length = 20)
private String nicActivityCode;
// Financial Thresholds
@Column(name = "annual_turnover", precision = 19, scale = 2)
private BigDecimal annualTurnover;
@Column(name = "investment_plant_machinery", precision = 19, scale = 2)
private BigDecimal investmentPlantMachinery;
@Column(name = "financial_year_assessment", length = 10)
private String financialYearAssessment;
// Owner / Promoter Details
@Column(name = "social_category_owner", length = 30)
private String socialCategoryOwner;
@Column(name = "gender_primary_owner", length = 20)
private String genderPrimaryOwner;
@Column(name = "no_of_employees")
private Integer noOfEmployees;
@Column(name = "women_led_enterprise")
private Boolean womenLedEnterprise;
@Column(name = "divyang_pwd_owned")
private Boolean divyangPwdOwned;
}
@@ -0,0 +1,32 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ClientMsmeRepository extends JpaRepository<ClientMsme, Long> {
@Query("SELECT e FROM ClientMsme e WHERE e.client.id = :clientId")
Optional<ClientMsme> findByClientId(@Param("clientId") Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,82 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Mudra Borrower (PMMY) entity classification.
* Captures Pradhan Mantri Mudra Yojana loan details - SHISHU, KISHORE, or TARUN categories.
*/
@Entity
@Table(name = "m_client_mudra_borrower")
@Getter
@Setter
@NoArgsConstructor
public class ClientMudraBorrower extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "mudra_category", length = 20)
private String mudraCategory;
@Column(name = "mudra_loan_account_no", length = 50)
private String mudraLoanAccountNo;
@Column(name = "lending_institution_name", length = 100)
private String lendingInstitutionName;
@Column(name = "sanctioned_amount", precision = 19, scale = 2)
private BigDecimal sanctionedAmount;
@Column(name = "disbursement_date")
private LocalDate disbursementDate;
@Column(name = "loan_purpose", length = 50)
private String loanPurpose;
@Column(name = "mudra_card_number", length = 20)
private String mudraCardNumber;
@Column(name = "current_outstanding", precision = 19, scale = 2)
private BigDecimal currentOutstanding;
@Column(name = "repayment_status", length = 30)
private String repaymentStatus;
@Column(name = "npa_flag")
private Boolean npaFlag;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientMudraBorrowerRepository extends JpaRepository<ClientMudraBorrower, Long> {
Optional<ClientMudraBorrower> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,80 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Non-Priority Sector (NPS) entity classification.
* Captures industry details, risk categorization, AML classification, and PEP/watchlist flags.
*/
@Entity
@Table(name = "m_client_non_priority_sector")
@Getter
@Setter
@NoArgsConstructor
public class ClientNonPrioritySector extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "industry_sector", length = 50)
private String industrySector;
@Column(name = "nic_code", length = 10)
private String nicCode;
@Column(name = "industry_description", length = 200)
private String industryDescription;
@Column(name = "annual_revenue_band", length = 30)
private String annualRevenueBand;
@Column(name = "risk_category", length = 20)
private String riskCategory;
@Column(name = "customer_risk_score")
private Integer customerRiskScore;
@Column(name = "aml_risk_classification", length = 50)
private String amlRiskClassification;
@Column(name = "pep_flag")
private Boolean pepFlag;
@Column(name = "aml_watchlist_match")
private Boolean amlWatchlistMatch;
@Column(name = "adverse_media_flag")
private Boolean adverseMediaFlag;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientNonPrioritySectorRepository extends JpaRepository<ClientNonPrioritySector, Long> {
Optional<ClientNonPrioritySector> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,97 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Priority Sector Lending (PSL) entity classification as per RBI Master Direction.
* Captures PSL category, MSME/Udyam details, weaker section flags, and FIDD reporting codes.
*/
@Entity
@Table(name = "m_client_priority_sector")
@Getter
@Setter
@NoArgsConstructor
public class ClientPrioritySector extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "psl_category", length = 30)
private String pslCategory;
@Column(name = "psl_sub_category", length = 50)
private String pslSubCategory;
@Column(name = "psl_loan_purpose_code", length = 10)
private String pslLoanPurposeCode;
@Column(name = "psl_eligibility_basis", length = 100)
private String pslEligibilityBasis;
@Column(name = "fidd_reporting_code", length = 20)
private String fiddReportingCode;
@Column(name = "psl_sanctioned_limit", precision = 19, scale = 2)
private BigDecimal pslSanctionedLimit;
@Column(name = "msme_classification", length = 50)
private String msmeClassification;
@Column(name = "udyam_registration_number", length = 30)
private String udyamRegistrationNumber;
@Column(name = "udyam_registration_date")
private LocalDate udyamRegistrationDate;
@Column(name = "annual_turnover", precision = 19, scale = 2)
private BigDecimal annualTurnover;
@Column(name = "investment_plant_machinery", precision = 19, scale = 2)
private BigDecimal investmentPlantMachinery;
@Column(name = "weaker_section_flag")
private Boolean weakerSectionFlag;
@Column(name = "sc_st_borrower_flag")
private Boolean scStBorrowerFlag;
@Column(name = "women_entrepreneur_flag")
private Boolean womenEntrepreneurFlag;
@Column(name = "minority_community_flag")
private Boolean minorityCommunityFlag;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientPrioritySectorRepository extends JpaRepository<ClientPrioritySector, Long> {
Optional<ClientPrioritySector> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -0,0 +1,94 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
/**
* Startup India (DPIIT) entity classification for non-individual clients.
* Captures DPIIT recognition details, tax exemptions, and priority sector lending info.
*/
@Entity
@Table(name = "m_client_startup_india")
@Getter
@Setter
@NoArgsConstructor
public class ClientStartupIndia extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@Column(name = "enabled")
private Boolean enabled;
@Column(name = "dpiit_recognition_number", length = 50)
private String dpiitRecognitionNumber;
@Column(name = "recognition_date")
private LocalDate recognitionDate;
@Column(name = "certificate_expiry_date")
private LocalDate certificateExpiryDate;
@Column(name = "entity_stage", length = 30)
private String entityStage;
@Column(name = "sector_as_dpiit", length = 50)
private String sectorAsDpiit;
@Column(name = "nic_industry_code", length = 20)
private String nicIndustryCode;
@Column(name = "tax_exemption_80iac")
private Boolean taxExemption80iac;
@Column(name = "sidbi_fund")
private Boolean sidbiFund;
@Column(name = "self_certification")
private Boolean selfCertification;
@Column(name = "fast_track_patent")
private Boolean fastTrackPatent;
@Column(name = "govt_tender_exemption")
private Boolean govtTenderExemption;
@Column(name = "credit_guarantee_cgss")
private Boolean creditGuaranteeCgss;
@Column(name = "psl_loan_limit", precision = 19, scale = 2)
private BigDecimal pslLoanLimit;
@Column(name = "psl_sub_category", length = 50)
private String pslSubCategory;
}
@@ -0,0 +1,31 @@
/**
* 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. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.client.entityclassification.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ClientStartupIndiaRepository extends JpaRepository<ClientStartupIndia, Long> {
Optional<ClientStartupIndia> findByClientId(Long clientId);
void deleteByClientId(Long clientId);
}
@@ -58,6 +58,7 @@ public class MobileLookupLog extends AbstractAuditableWithUTCDateTimeCustom<Long
private String lookupSource;
@Column(name = "client_id")
@lombok.Setter
private Long clientId;
@Column(name = "looked_up_on", nullable = false)
@@ -85,6 +85,7 @@ public class SanctionsScreeningLog extends AbstractAuditableWithUTCDateTimeCusto
public String getMatchedNames() { return matchedNames; }
public String getScreeningSource() { return screeningSource; }
public Long getClientId() { return clientId; }
public void setClientId(Long clientId) { this.clientId = clientId; }
public String getIpAddress() { return ipAddress; }
public OffsetDateTime getScreenedOn() { return screenedOn; }
}