Refactor Client to support auditable fields
This commit is contained in:
committed by
Arnold Gálovics
parent
b8f8217148
commit
d8f483ab45
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.infrastructure.core.api;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Serializer for Java Offset Date Time {@link OffsetDateTime} that returns the date in ISO-8601 Offset date time format
|
||||
*/
|
||||
public class OffsetDateTimeAdapter implements JsonSerializer<OffsetDateTime> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unused")
|
||||
public JsonElement serialize(final OffsetDateTime dateTime, final Type typeOfSrc, final JsonSerializationContext context) {
|
||||
JsonElement object = null;
|
||||
if (dateTime != null) {
|
||||
object = new JsonPrimitive(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(dateTime));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
+87
@@ -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.api;
|
||||
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
//@Profile("test")
|
||||
@Component
|
||||
@Path("/internal/client")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class InternalClientInformationApiResource implements InitializingBean {
|
||||
|
||||
private final ClientRepositoryWrapper clientRepositoryWrapper;
|
||||
private final ToApiJsonSerializer<Map> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
log.warn("------------------------------------------------------------");
|
||||
log.warn(" ");
|
||||
log.warn("DO NOT USE THIS IN PRODUCTION!");
|
||||
log.warn("Internal client services mode is enabled");
|
||||
log.warn("DO NOT USE THIS IN PRODUCTION!");
|
||||
log.warn(" ");
|
||||
log.warn("------------------------------------------------------------");
|
||||
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/audit")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String getClientAuditFields(@Context final UriInfo uriInfo, @PathParam("clientId") Long clientId) {
|
||||
log.warn("------------------------------------------------------------");
|
||||
log.warn(" ");
|
||||
log.warn("Fetching client with {}", clientId);
|
||||
log.warn(" ");
|
||||
log.warn("------------------------------------------------------------");
|
||||
|
||||
final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
Map<String, Object> auditFields = new HashMap<>(
|
||||
Map.of(CREATED_BY, client.getCreatedBy().orElse(null), CREATED_DATE, client.getCreatedDate().orElse(null), LAST_MODIFIED_BY,
|
||||
client.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, client.getLastModifiedDate().orElse(null)));
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, auditFields);
|
||||
}
|
||||
}
|
||||
+9
-22
@@ -44,7 +44,7 @@ import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.Image;
|
||||
@@ -59,7 +59,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
||||
@Entity
|
||||
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE"), //
|
||||
@UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") })
|
||||
public final class Client extends AbstractPersistableCustom {
|
||||
public class Client extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||
private String accountNumber;
|
||||
@@ -180,16 +180,14 @@ public final class Client extends AbstractPersistableCustom {
|
||||
@Column(name = "submittedon_date", nullable = true)
|
||||
private LocalDate submittedOnDate;
|
||||
|
||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "submittedon_userid", nullable = true)
|
||||
private AppUser submittedBy;
|
||||
// Deprecated since common Auditable fields were introduced. Columns and data left untouched to help migration.
|
||||
|
||||
@Column(name = "updated_on", nullable = true)
|
||||
private LocalDate updatedOnDate;
|
||||
// @Column(name = "updated_on", nullable = true)
|
||||
// private LocalDate updatedOnDate;
|
||||
|
||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "updated_by", nullable = true)
|
||||
private AppUser updatedBy;
|
||||
// @ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
// @JoinColumn(name = "updated_by", nullable = true)
|
||||
// private AppUser updatedBy;
|
||||
|
||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "activatedon_userid", nullable = true)
|
||||
@@ -270,9 +268,7 @@ public final class Client extends AbstractPersistableCustom {
|
||||
savingsAccountId, dataOfBirth, gender, clientType, clientClassification, legalForm, isStaff);
|
||||
}
|
||||
|
||||
Client() {
|
||||
this.setLegalForm(null);
|
||||
}
|
||||
protected Client() {}
|
||||
|
||||
private Client(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup,
|
||||
final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname,
|
||||
@@ -289,7 +285,6 @@ public final class Client extends AbstractPersistableCustom {
|
||||
}
|
||||
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.submittedBy = currentUser;
|
||||
|
||||
this.status = status.getValue();
|
||||
this.office = office;
|
||||
@@ -969,8 +964,6 @@ public final class Client extends AbstractPersistableCustom {
|
||||
this.rejectionReason = rejectionReason;
|
||||
this.rejectionDate = rejectionDate;
|
||||
this.rejectedBy = currentUser;
|
||||
this.updatedBy = currentUser;
|
||||
this.updatedOnDate = rejectionDate;
|
||||
this.status = ClientStatus.REJECTED.getValue();
|
||||
|
||||
}
|
||||
@@ -979,8 +972,6 @@ public final class Client extends AbstractPersistableCustom {
|
||||
this.withdrawalReason = withdrawalReason;
|
||||
this.withdrawalDate = withdrawalDate;
|
||||
this.withdrawnBy = currentUser;
|
||||
this.updatedBy = currentUser;
|
||||
this.updatedOnDate = withdrawalDate;
|
||||
this.status = ClientStatus.WITHDRAWN.getValue();
|
||||
|
||||
}
|
||||
@@ -990,8 +981,6 @@ public final class Client extends AbstractPersistableCustom {
|
||||
this.closureReason = null;
|
||||
this.reactivateDate = reactivateDate;
|
||||
this.reactivatedBy = currentUser;
|
||||
this.updatedBy = currentUser;
|
||||
this.updatedOnDate = reactivateDate;
|
||||
this.status = ClientStatus.PENDING.getValue();
|
||||
|
||||
}
|
||||
@@ -999,8 +988,6 @@ public final class Client extends AbstractPersistableCustom {
|
||||
public void reOpened(AppUser currentUser, LocalDate reopenedDate) {
|
||||
this.reopenedDate = reopenedDate;
|
||||
this.reopenedBy = currentUser;
|
||||
this.updatedBy = currentUser;
|
||||
this.updatedOnDate = reopenedDate;
|
||||
this.status = ClientStatus.PENDING.getValue();
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -430,7 +430,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
sqlBuilder.append("left join m_savings_product sp on sp.id = c.default_savings_product ");
|
||||
sqlBuilder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
||||
|
||||
sqlBuilder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser sbu on sbu.id = c.created_by ");
|
||||
sqlBuilder.append("left join m_appuser acu on acu.id = c.activatedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser clu on clu.id = c.closedon_userid ");
|
||||
sqlBuilder.append("left join m_code_value cv on cv.id = c.gender_cv_id ");
|
||||
@@ -618,7 +618,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
builder.append("left join m_staff s on s.id = c.staff_id ");
|
||||
builder.append("left join m_savings_product sp on sp.id = c.default_savings_product ");
|
||||
builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
||||
builder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
|
||||
builder.append("left join m_appuser sbu on sbu.id = c.created_by ");
|
||||
builder.append("left join m_appuser acu on acu.id = c.activatedon_userid ");
|
||||
builder.append("left join m_appuser clu on clu.id = c.closedon_userid ");
|
||||
builder.append("left join m_code_value cv on cv.id = c.gender_cv_id ");
|
||||
|
||||
@@ -39,4 +39,5 @@
|
||||
<include file="parts/0017_fix_stretchy_reports.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0018_pentaho_reports_to_table.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0019_refactor_loan_transaction.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0020_add_audit_entries.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. 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.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<!--Client-->
|
||||
<changeSet author="fineract" id="1" context="mysql">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="submittedon_userid"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="1" context="postgresql">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="submittedon_userid"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="2">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_client"
|
||||
constraintName="FK_client_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_client"
|
||||
constraintName="FK_client_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="3" author="fineract">
|
||||
<dropColumn tableName="m_client">
|
||||
<column name="submittedon_userid"/>
|
||||
</dropColumn>
|
||||
</changeSet>
|
||||
<!--Loan-->
|
||||
<changeSet author="fineract" id="4" context="mysql">
|
||||
<addColumn tableName="m_loan">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="submittedon_userid"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="4" context="postgresql">
|
||||
<addColumn tableName="m_loan">
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="submittedon_userid"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="5">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_loan"
|
||||
constraintName="FK_loan_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_loan"
|
||||
constraintName="FK_loan_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="6" author="fineract">
|
||||
<dropForeignKeyConstraint baseTableName="m_loan" constraintName="FK_submittedon_userid"/>
|
||||
<dropColumn tableName="m_loan">
|
||||
<column name="submittedon_userid"/>
|
||||
</dropColumn>
|
||||
</changeSet>
|
||||
<!-- Loan transactions -->
|
||||
<changeSet author="fineract" id="7" context="mysql">
|
||||
<addColumn tableName="m_loan_transaction">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="8" context="postgresql">
|
||||
<addColumn tableName="m_loan_transaction">
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet id="9" author="fineract">
|
||||
<renameColumn tableName="m_loan_transaction" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
|
||||
<renameColumn tableName="m_loan_transaction" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="10">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_loan_transaction"
|
||||
constraintName="FK_loan_transaction_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_loan_transaction"
|
||||
constraintName="FK_loan_transaction_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="11" author="fineract" context="mysql">
|
||||
<update tableName="stretchy_report">
|
||||
<column name="report_sql"
|
||||
value="SELECT mc.id AS "id", mc.firstname AS "firstName", mc.middlename AS "middleName", mc.lastname AS "lastName", mc.display_name AS "fullName", mc.mobile_no AS "mobileNo", ml.principal_amount AS "loanAmount", (IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding", ounder.id AS "officeNumber", ml.account_no AS "loanAccountNumber", SUM(lt.amount) AS "repaymentAmount" FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, '%') INNER JOIN m_client mc ON mc.office_id=ounder.id INNER JOIN m_loan ml ON ml.client_id = mc.id INNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = 'loan_status_id' INNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id INNER JOIN m_appuser au ON au.id = lt.createdby_id LEFT JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id LEFT JOIN m_payment_detail mpd ON mpd.id=lt.payment_detail_id LEFT JOIN m_currency cur ON cur.code = ml.currency_code LEFT JOIN m_group_client gc ON gc.client_id = mc.id LEFT JOIN m_group g ON g.id = gc.group_id LEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id LEFT JOIN m_guarantor gua ON gua.loan_id = ml.id WHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), lt.transaction_date) BETWEEN ${fromX} AND ${toY}) AND lt.is_reversed=0 AND lt.transaction_type_enum=2 AND laa.loan_id IS NULL GROUP BY ml.id ORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no"/>
|
||||
<where>report_name = 'Loan payments received (Active Loans)'</where>
|
||||
</update>
|
||||
<update tableName="stretchy_report">
|
||||
<column name="report_sql"
|
||||
value="SELECT ml.id AS "loanId", mc.id AS "id", mc.firstname AS "firstName", mc.middlename AS "middleName", mc.lastname AS "lastName", mc.display_name AS "fullName", mc.mobile_no AS "mobileNo", ml.principal_amount AS "loanAmount", (IFNULL(ml.principal_outstanding_derived, 0) + IFNULL(ml.interest_outstanding_derived, 0) + IFNULL(ml.fee_charges_outstanding_derived, 0) + IFNULL(ml.penalty_charges_outstanding_derived, 0)) AS "loanOutstanding", ounder.id AS "officeNumber", ml.account_no AS "loanAccountNumber", SUM(lt.amount) AS "repaymentAmount" FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, '%') INNER JOIN m_client mc ON mc.office_id=ounder.id INNER JOIN m_loan ml ON ml.client_id = mc.id INNER JOIN r_enum_value rev ON rev.enum_id=ml.loan_status_id AND rev.enum_name = 'loan_status_id' INNER JOIN m_loan_arrears_aging laa ON laa.loan_id=ml.id INNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id INNER JOIN m_appuser au ON au.id = lt.created_by LEFT JOIN m_payment_detail mpd ON mpd.id=lt.payment_detail_id LEFT JOIN m_currency cur ON cur.code = ml.currency_code LEFT JOIN m_group_client gc ON gc.client_id = mc.id LEFT JOIN m_group g ON g.id = gc.group_id LEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id LEFT JOIN m_guarantor gua ON gua.loan_id = ml.id WHERE ml.loan_status_id=300 AND mo.id=${officeId} AND (IFNULL(ml.loan_officer_id, -10) = ${loanOfficerId} OR "-1" = ${loanOfficerId}) AND (DATEDIFF(CURDATE(), lt.transaction_date) BETWEEN ${fromX} AND ${toY}) AND (DATEDIFF(CURDATE(), laa.overdue_since_date_derived) BETWEEN ${overdueX} AND ${overdueY}) AND lt.is_reversed=0 AND lt.transaction_type_enum=2 GROUP BY ml.id ORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no"/>
|
||||
<where>report_name = 'Loan payments received (Overdue Loans)'</where>
|
||||
</update>
|
||||
</changeSet>
|
||||
<changeSet id="12" author="fineract" context="postgresql">
|
||||
<update tableName="stretchy_report">
|
||||
<column name="report_sql"
|
||||
value="SELECT mc.id AS id, mc.firstname AS firstName, mc.middlename AS middleName, mc.lastname AS lastName, mc.display_name AS fullName, mc.mobile_no AS mobileNo, ml.principal_amount AS loanAmount, (COALESCE(ml.principal_outstanding_derived, 0) + COALESCE(ml.interest_outstanding_derived, 0) + COALESCE(ml.fee_charges_outstanding_derived, 0) + COALESCE(ml.penalty_charges_outstanding_derived, 0)) AS loanOutstanding, ounder.id AS officeNumber, ml.account_no AS loanAccountNumber, SUM(lt.amount) AS repaymentAmount FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, '%') INNER JOIN m_client mc ON mc.office_id = ounder.id INNER JOIN m_loan ml ON ml.client_id = mc.id INNER JOIN r_enum_value rev ON rev.enum_id = ml.loan_status_id AND rev.enum_name = 'loan_status_id' INNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id INNER JOIN m_appuser au ON au.id = lt.created_by LEFT JOIN m_loan_arrears_aging laa ON laa.loan_id = ml.id LEFT JOIN m_payment_detail mpd ON mpd.id = lt.payment_detail_id LEFT JOIN m_currency cur ON cur.code = ml.currency_code LEFT JOIN m_group_client gc ON gc.client_id = mc.id LEFT JOIN m_group g ON g.id = gc.group_id LEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id LEFT JOIN m_guarantor gua ON gua.loan_id = ml.id WHERE ml.loan_status_id = 300 AND mo.id = '${officeId}' AND (COALESCE(ml.loan_officer_id, -10) = ${loanOfficerId} OR '-1' = ${loanOfficerId}) AND (EXTRACT(DAY FROM (CURRENT_DATE - lt.transaction_date::TIMESTAMP)) BETWEEN 9${fromX} AND ${toY}) AND lt.is_reversed = false AND lt.transaction_type_enum = 2 AND laa.loan_id IS NULL GROUP BY ml.id, mc.id, ounder.id ORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no"/>
|
||||
<where>report_name = 'Loan payments received (Active Loans)'</where>
|
||||
</update>
|
||||
<update tableName="stretchy_report">
|
||||
<column name="report_sql"
|
||||
value="SELECT ml.id AS loanId, mc.id AS id, mc.firstname AS firstName, mc.middlename AS middleName, mc.lastname AS lastName, mc.display_name AS fullName, mc.mobile_no AS mobileNo, ml.principal_amount AS loanAmount, (COALESCE(ml.principal_outstanding_derived, 0) + COALESCE(ml.interest_outstanding_derived, 0) + COALESCE(ml.fee_charges_outstanding_derived, 0) + COALESCE(ml.penalty_charges_outstanding_derived, 0)) AS loanOutstanding, ounder.id AS officeNumber, ml.account_no AS loanAccountNumber, SUM(lt.amount) AS repaymentAmount FROM m_office mo JOIN m_office ounder ON ounder.hierarchy LIKE CONCAT(mo.hierarchy, '%') INNER JOIN m_client mc ON mc.office_id = ounder.id INNER JOIN m_loan ml ON ml.client_id = mc.id INNER JOIN r_enum_value rev ON rev.enum_id = ml.loan_status_id AND rev.enum_name = 'loan_status_id' INNER JOIN m_loan_arrears_aging laa ON laa.loan_id = ml.id INNER JOIN m_loan_transaction lt ON lt.loan_id = ml.id INNER JOIN m_appuser au ON au.id = lt.created_by LEFT JOIN m_payment_detail mpd ON mpd.id = lt.payment_detail_id LEFT JOIN m_currency cur ON cur.code = ml.currency_code LEFT JOIN m_group_client gc ON gc.client_id = mc.id LEFT JOIN m_group g ON g.id = gc.group_id LEFT JOIN m_staff lo ON lo.id = ml.loan_officer_id LEFT JOIN m_guarantor gua ON gua.loan_id = ml.id WHERE ml.loan_status_id = 300 AND mo.id = '${officeId}' AND (COALESCE(ml.loan_officer_id, -10) = ${loanOfficerId} OR '-1' = ${loanOfficerId}) AND (EXTRACT(DAY FROM(CURRENT_DATE - lt.transaction_date::TIMESTAMP)) BETWEEN ${fromX} AND ${toY}) AND (EXTRACT(DAY FROM(CURRENT_DATE - laa.overdue_since_date_derived::TIMESTAMP)) BETWEEN ${overdueX} AND ${overdueY}) AND lt.is_reversed = false AND lt.transaction_type_enum = 2 GROUP BY ml.id, mc.id, ounder.id ORDER BY ounder.hierarchy, ml.currency_code, mc.account_no, ml.account_no"/>
|
||||
<where>report_name = 'Loan payments received (Overdue Loans)'</where>
|
||||
</update>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* 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.integrationtests;
|
||||
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY;
|
||||
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.organisation.StaffHelper;
|
||||
import org.apache.fineract.integrationtests.useradministration.users.UserHelper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClientAuditingIntegrationTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClientAuditingIntegrationTest.class);
|
||||
private ResponseSpecification responseSpec;
|
||||
private RequestSpecification requestSpec;
|
||||
private ClientHelper clientHelper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||
|
||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAuditDates() throws InterruptedException {
|
||||
final Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec);
|
||||
String username = Utils.randomNameGenerator("user", 8);
|
||||
final Integer userId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, 1, staffId, username, "resourceId");
|
||||
OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
|
||||
// Testing in minutes precision, but still need to take care around the end of the actual minute
|
||||
if (now.getSecond() > 56) {
|
||||
Thread.sleep(5000);
|
||||
now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
|
||||
}
|
||||
LOG.info("-------------------------Creating Client---------------------------");
|
||||
|
||||
final Integer clientID = ClientHelper.createClientPending(requestSpec, responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientID);
|
||||
Map<String, Object> auditFieldsResponse = ClientHelper.getClientAuditFields(requestSpec, responseSpec, clientID, "");
|
||||
|
||||
OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE),
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
|
||||
OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE),
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
|
||||
LOG.info("-------------------------Check Audit dates---------------------------");
|
||||
assertEquals(1, auditFieldsResponse.get(CREATED_BY));
|
||||
assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY));
|
||||
assertEquals(now.getYear(), createdDate.getYear());
|
||||
assertEquals(now.getMonth(), createdDate.getMonth());
|
||||
assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth());
|
||||
assertEquals(now.getHour(), createdDate.getHour());
|
||||
assertEquals(now.getMinute(), createdDate.getMinute());
|
||||
|
||||
assertEquals(now.getYear(), lastModifiedDate.getYear());
|
||||
assertEquals(now.getMonth(), lastModifiedDate.getMonth());
|
||||
assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth());
|
||||
assertEquals(now.getHour(), lastModifiedDate.getHour());
|
||||
assertEquals(now.getMinute(), lastModifiedDate.getMinute());
|
||||
|
||||
LOG.info("-------------------------Modify Client with System user---------------------------");
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
this.requestSpec.header("Authorization",
|
||||
"Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "password"));
|
||||
|
||||
this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec);
|
||||
this.clientHelper.activateClient(clientID);
|
||||
auditFieldsResponse = ClientHelper.getClientAuditFields(requestSpec, responseSpec, clientID, "");
|
||||
|
||||
createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
|
||||
lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE),
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
|
||||
LOG.info("-------------------------Check Audit dates---------------------------");
|
||||
assertEquals(1, auditFieldsResponse.get(CREATED_BY));
|
||||
assertEquals(now.getYear(), createdDate.getYear());
|
||||
assertEquals(now.getMonth(), createdDate.getMonth());
|
||||
assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth());
|
||||
assertEquals(now.getHour(), createdDate.getHour());
|
||||
assertEquals(now.getMinute(), createdDate.getMinute());
|
||||
|
||||
now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
|
||||
|
||||
assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY));
|
||||
assertEquals(now.getYear(), lastModifiedDate.getYear());
|
||||
assertEquals(now.getMonth(), lastModifiedDate.getMonth());
|
||||
assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth());
|
||||
assertEquals(now.getHour(), lastModifiedDate.getHour());
|
||||
assertEquals(now.getMinute(), lastModifiedDate.getMinute());
|
||||
}
|
||||
|
||||
}
|
||||
+8
-1
@@ -346,6 +346,13 @@ public class ClientHelper {
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_CLIENT_URL, jsonReturn);
|
||||
}
|
||||
|
||||
public static HashMap<String, Object> getClientAuditFields(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer clientId, final String jsonReturn) {
|
||||
final String GET_CLIENT_URL = "/fineract-provider/api/v1/internal/client/" + clientId + "/audit?" + Utils.TENANT_IDENTIFIER;
|
||||
log.info("---------------------------------GET A CLIENT ENTITY AUDIT FIELDS---------------------------------------------");
|
||||
return Utils.performServerGet(requestSpec, responseSpec, GET_CLIENT_URL, jsonReturn);
|
||||
}
|
||||
|
||||
/* Client status is a map.So adding SuppressWarnings */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static HashMap<String, Object> getClientStatus(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
@@ -435,7 +442,7 @@ public class ClientHelper {
|
||||
|
||||
}
|
||||
|
||||
private String getActivateClientAsJSON(String date) {
|
||||
private static String getActivateClientAsJSON(String date) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public final class UserHelper {
|
||||
private static String getTestCreateUserAsJSON(int roleId, int staffId, String username) {
|
||||
return "{ \"username\": \"" + username + "\", \"firstname\": \"Test\", \"lastname\": \"User\", \"email\": \"whatever@mifos.org\","
|
||||
+ " \"officeId\": \"1\", \"staffId\": " + "\"" + staffId + "\",\"roles\": [\"" + roleId
|
||||
+ "\"], \"sendPasswordToEmail\": false}";
|
||||
+ "\"], \"sendPasswordToEmail\": false, \"password\": \"password\"," + " \"repeatPassword\": \"password\"}";
|
||||
}
|
||||
|
||||
private static String getTestUpdateUserAsJSON(String username) {
|
||||
|
||||
Reference in New Issue
Block a user