Skip to content

Commit

Permalink
[MODAUD-174] - Implemented status change history feature and cleaned …
Browse files Browse the repository at this point in the history
…code
  • Loading branch information
azizbekxm committed Nov 14, 2023
1 parent 20a1b7f commit ecd4f24
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 25 deletions.
2 changes: 1 addition & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
"methods": [
"GET"
],
"pathPattern": "/audit-data/acquisition/piece/{id}/unique-status",
"pathPattern": "/audit-data/acquisition/piece/{id}/status-change-history",
"permissionsRequired": [
"acquisition.piece.events.get"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class OrderEventsDaoImpl implements OrderEventsDao {
public static final String TABLE_NAME = "acquisition_order_log";

public static final String GET_BY_ORDER_ID_SQL = "SELECT id, action, order_id, user_id, event_date, action_date, modified_content_snapshot," +
" (SELECT count(*) AS total_records FROM %s WHERE order_id = $1) FROM %s WHERE order_id = $1 %s LIMIT $2 OFFSET $3";
" FROM %s WHERE order_id = $1 %s LIMIT $2 OFFSET $3";

public static final String INSERT_SQL = "INSERT INTO %s (id, action, order_id, user_id, event_date, action_date, modified_content_snapshot)" +
" VALUES ($1, $2, $3, $4, $5, $6, $7)";
Expand Down Expand Up @@ -65,7 +65,7 @@ public Future<OrderAuditEventCollection> getAuditEventsByOrderId(String orderId,
try {
LOGGER.info("getAuditEventsByOrderId:: Trying to Retrieve AuditEvent with order id : {}", orderId);
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_BY_ORDER_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
String query = format(GET_BY_ORDER_ID_SQL, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
Tuple queryParams = Tuple.of(UUID.fromString(orderId), limit, offset);
pgClientFactory.createInstance(tenantId).selectRead(query, queryParams, promise);
} catch (Exception e) {
Expand Down Expand Up @@ -98,10 +98,13 @@ private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderAudit
private OrderAuditEventCollection mapRowToListOfOrderEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderEvent:: Mapping row to List of Order Events");
OrderAuditEventCollection orderAuditEventCollection = new OrderAuditEventCollection();
// set audit piece change record(s) by mapping rowSet one by one
rowSet.iterator().forEachRemaining(row -> {
orderAuditEventCollection.getOrderAuditEvents().add(mapRowToOrderEvent(row));
orderAuditEventCollection.setTotalItems(row.getInteger(TOTAL_RECORDS_FIELD));
});
// set total records
int totalRecords = orderAuditEventCollection.getOrderAuditEvents().size();
orderAuditEventCollection.setTotalItems(totalRecords);
LOGGER.info("mapRowToListOfOrderEvent:: Mapped row to List of Order Events");
return orderAuditEventCollection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class OrderLineEventsDaoImpl implements OrderLineEventsDao {
public static final String TABLE_NAME = "acquisition_order_line_log";

public static final String GET_BY_ORDER_LINE_ID_SQL = "SELECT id, action, order_id, order_line_id, user_id, event_date, action_date, modified_content_snapshot," +
" (SELECT count(*) AS total_records FROM %s WHERE order_line_id = $1) " +
" FROM %s WHERE order_line_id = $1 %s LIMIT $2 OFFSET $3";

private static final String INSERT_SQL = "INSERT INTO %s (id, action, order_id, order_line_id, user_id, event_date, action_date, modified_content_snapshot) " +
Expand Down Expand Up @@ -67,7 +66,7 @@ public Future<OrderLineAuditEventCollection> getAuditEventsByOrderLineId(String
try {
LOGGER.info("getAuditEventsByOrderLineId:: Trying to Retrieve AuditEvent with order line id : {}", orderLineId);
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_BY_ORDER_LINE_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
String query = format(GET_BY_ORDER_LINE_ID_SQL, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
Tuple queryParams = Tuple.of(UUID.fromString(orderLineId), limit, offset);
pgClientFactory.createInstance(tenantId).selectRead(query, queryParams, promise);
} catch (Exception e) {
Expand Down Expand Up @@ -101,10 +100,13 @@ private void makeSaveCall(Promise<RowSet<Row>> promise, String query, OrderLineA
private OrderLineAuditEventCollection mapRowToListOfOrderLineEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderLineEvent:: Mapping row to List of Order Line Events");
OrderLineAuditEventCollection orderLineAuditEventCollection = new OrderLineAuditEventCollection();
// set audit piece change record(s) by mapping rowSet one by one
rowSet.iterator().forEachRemaining(row -> {
orderLineAuditEventCollection.getOrderLineAuditEvents().add(mapRowToOrderLineEvent(row));
orderLineAuditEventCollection.setTotalItems(row.getInteger(TOTAL_RECORDS_FIELD));
});
// set total records
int totalRecords = orderLineAuditEventCollection.getOrderLineAuditEvents().size();
orderLineAuditEventCollection.setTotalItems(totalRecords);
LOGGER.info("mapRowToListOfOrderLineEvent:: Mapped row to List of Order Line Events");
return orderLineAuditEventCollection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,16 @@ public class PieceEventsDaoImpl implements PieceEventsDao {
private static final String TABLE_NAME = "acquisition_piece_log";
private static final String GET_BY_PIECE_ID_SQL = "SELECT id, action, piece_id, user_id, event_date, action_date, modified_content_snapshot" +
" FROM %s WHERE piece_id = $1 %s LIMIT $2 OFFSET $3";
private static final String GET_UNIQUE_STATUS_BY_PIECE_ID_SQL = "SELECT id, action, piece_id, user_id, event_date, action_date, modified_content_snapshot" +
" FROM %s WHERE piece_id = $1 AND" +
" action IN" +
" (SELECT action FROM %s WHERE piece_id = $1 GROUP BY action HAVING COUNT(action) = 1)" +
" %s LIMIT $2 OFFSET $3";
private static final String GET_STATUS_CHANGE_HISTORY_BY_PIECE_ID_SQL =
"""
WITH StatusChanges AS (SELECT id, action, piece_id, user_id, event_date, action_date, modified_content_snapshot,
LAG(modified_content_snapshot ->> 'status') OVER (PARTITION BY piece_id ORDER BY action_date) AS previous_status FROM %s
)
SELECT id, action, piece_id, user_id, event_date, action_date, modified_content_snapshot FROM StatusChanges
WHERE piece_id = $1 and modified_content_snapshot ->> 'status' <> COALESCE(previous_status, '')
%s LIMIT $2 OFFSET $3
""";

private static final String INSERT_SQL = "INSERT INTO %s (id, action, piece_id, user_id, event_date, action_date, modified_content_snapshot)" +
" VALUES ($1, $2, $3, $4, $5, $6, $7)";

Expand Down Expand Up @@ -89,9 +94,9 @@ public Future<PieceAuditEventCollection> getAuditEventsWithUniqueStatusByPieceId
LOGGER.debug("getAuditEventsByOrderId:: Retrieving AuditEvent with piece id : {}", pieceId);
Promise<RowSet<Row>> promise = Promise.promise();
try {
LOGGER.info("getAuditEventsByOrderId:: Trying to Retrieve AuditEvent with order id : {}", pieceId);
LOGGER.info("getAuditEventsByOrderId:: Trying to Retrieve AuditEvent with piece id : {}", pieceId);
String logTable = formatDBTableName(tenantId, TABLE_NAME);
String query = format(GET_UNIQUE_STATUS_BY_PIECE_ID_SQL, logTable, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
String query = format(GET_STATUS_CHANGE_HISTORY_BY_PIECE_ID_SQL, logTable, format(ORDER_BY_PATTERN, sortBy, sortOrder));
Tuple queryParams = Tuple.of(UUID.fromString(pieceId), limit, offset);
pgClientFactory.createInstance(tenantId).selectRead(query, queryParams, promise);
} catch (Exception e) {
Expand All @@ -106,15 +111,13 @@ public Future<PieceAuditEventCollection> getAuditEventsWithUniqueStatusByPieceId
private PieceAuditEventCollection mapRowToListOfPieceEvent(RowSet<Row> rowSet) {
LOGGER.debug("mapRowToListOfOrderEvent:: Mapping row to List of Piece Events");
PieceAuditEventCollection pieceAuditEventCollection = new PieceAuditEventCollection();

// set audit piece change record(s) by mapping rowSet one by one
rowSet.iterator().forEachRemaining(row -> {
pieceAuditEventCollection.getPieceAuditEvents().add(mapRowToPieceEvent(row));
});
// set total records
int totalRecords = pieceAuditEventCollection.getPieceAuditEvents().size();
pieceAuditEventCollection.setTotalItems(totalRecords);

LOGGER.info("mapRowToListOfOrderEvent:: Mapped row to List of Piece Events");
return pieceAuditEventCollection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.folio.rest.jaxrs.model.AuditDataAcquisitionOrderIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionOrderLineIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionPieceIdGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionPieceIdUniqueStatusGetSortOrder;
import org.folio.rest.jaxrs.model.AuditDataAcquisitionPieceIdStatusChangeHistoryGetSortOrder;
import org.folio.rest.jaxrs.resource.AuditDataAcquisition;
import org.folio.rest.tools.utils.TenantTool;
import org.folio.services.acquisition.OrderAuditEventsService;
Expand Down Expand Up @@ -105,7 +105,9 @@ public void getAuditDataAcquisitionPieceById(String pieceId, String sortBy, Audi
}

@Override
public void getAuditDataAcquisitionPieceUniqueStatusById(String pieceId, String sortBy, AuditDataAcquisitionPieceIdUniqueStatusGetSortOrder sortOrder, int limit, int offset, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
public void getAuditDataAcquisitionPieceStatusChangeHistoryById(String pieceId, String sortBy,
AuditDataAcquisitionPieceIdStatusChangeHistoryGetSortOrder sortOrder,
int limit, int offset, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
LOGGER.debug("getAuditDataAcquisitionOrderById:: Retrieving Audit Data Acquisition Piece with unique status By Id : {}", pieceId);
String tenantId = TenantTool.tenantId(okapiHeaders);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.folio.services.acquisition.impl;

import static org.folio.util.AuditEventDBConstants.UNIQUE_CONSTRAINT_VIOLATION_CODE;

import io.vertx.core.Future;
import io.vertx.pgclient.PgException;
import io.vertx.sqlclient.Row;
Expand All @@ -19,8 +21,6 @@ public class OrderAuditEventsServiceImpl implements OrderAuditEventsService {

private static final Logger LOGGER = LogManager.getLogger();

public static final String UNIQUE_CONSTRAINT_VIOLATION_CODE = "23505";

private OrderEventsDao orderEventsDao;

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.folio.services.acquisition.impl;

import static org.folio.util.AuditEventDBConstants.UNIQUE_CONSTRAINT_VIOLATION_CODE;

import io.vertx.core.Future;
import io.vertx.pgclient.PgException;
import io.vertx.sqlclient.Row;
Expand All @@ -19,8 +21,6 @@ public class OrderLineAuditEventsServiceImpl implements OrderLineAuditEventsServ

private static final Logger LOGGER = LogManager.getLogger();

public static final String UNIQUE_CONSTRAINT_VIOLATION_CODE = "23505";

private OrderLineEventsDao orderLineEventsDao;

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.folio.services.acquisition.impl;

import static org.folio.util.AuditEventDBConstants.UNIQUE_CONSTRAINT_VIOLATION_CODE;

import io.vertx.core.Future;
import io.vertx.pgclient.PgException;
import io.vertx.sqlclient.Row;
Expand All @@ -17,7 +19,7 @@
@Service
public class PieceAuditEventsServiceImpl implements PieceAuditEventsService {
private static final Logger LOGGER = LogManager.getLogger();
private static final String UNIQUE_CONSTRAINT_VIOLATION_CODE = "23505";

private final PieceEventsDao pieceEventsDao;

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ private AuditEventDBConstants() {}

public static final String ORDER_BY_PATTERN = "ORDER BY %s %s";

public static final String UNIQUE_CONSTRAINT_VIOLATION_CODE = "23505";
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
{
"run": "after",
"snippetPath": "acquisition/create_acquisition_piece_log_table.sql",
"fromModuleVersion": "mod-audit-2.8.1"
"fromModuleVersion": "mod-audit-2.9.0"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.folio.utils.EntityUtils.ORDER_ID;
import static org.folio.utils.EntityUtils.ORDER_LINE_ID;
import static org.folio.utils.EntityUtils.PIECE_ID;
import static org.folio.utils.EntityUtils.createPieceAuditEvent;
import static org.hamcrest.Matchers.containsString;

import java.util.Date;
Expand Down Expand Up @@ -34,6 +35,7 @@ public class AuditDataAcquisitionAPITest extends ApiTestBase {
private static final String ACQ_AUDIT_ORDER_PATH = "/audit-data/acquisition/order/";
private static final String ACQ_AUDIT_ORDER_LINE_PATH = "/audit-data/acquisition/order-line/";
private static final String ACQ_AUDIT_PIECE_PATH = "/audit-data/acquisition/piece/";
private static final String ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH = "/status-change-history";
private static final String TENANT_ID = "modaudittest";

@Spy
Expand Down Expand Up @@ -146,4 +148,58 @@ void shouldReturnPieceEventsOnGetByPieceId() {
given().header(CONTENT_TYPE).header(TENANT).header(PERMS).get(ACQ_AUDIT_PIECE_PATH + PIECE_ID + 123).then().log().all().statusCode(500)
.body(containsString("UUID string too large"));
}

@Test
void shouldReturnPieceEventsStatusChangeHistoryGetByPieceId() {
String id1 = UUID.randomUUID().toString();
String id2 = UUID.randomUUID().toString();
String id3 = UUID.randomUUID().toString();
String id4 = UUID.randomUUID().toString();
String id5 = UUID.randomUUID().toString();
var pieceAuditEvent1 = createPieceAuditEvent(id1, "STATUS 1");
var pieceAuditEvent2 = createPieceAuditEvent(id2, "STATUS 1");
var pieceAuditEvent3 = createPieceAuditEvent(id3, "STATUS 2");
var pieceAuditEvent4 = createPieceAuditEvent(id4, "STATUS 2");
var pieceAuditEvent5 = createPieceAuditEvent(id5, "STATUS 1");

pieceEventsDao.save(pieceAuditEvent1, TENANT_ID);
pieceEventsDao.save(pieceAuditEvent2, TENANT_ID);
pieceEventsDao.save(pieceAuditEvent3, TENANT_ID);
pieceEventsDao.save(pieceAuditEvent4, TENANT_ID);
pieceEventsDao.save(pieceAuditEvent5, TENANT_ID);

// based on our business logic, it returns pieceAuditEvent1, pieceAuditEvent3, pieceAuditEvent5
given().header(CONTENT_TYPE).header(TENANT).header(PERMS)
.get(ACQ_AUDIT_PIECE_PATH + INVALID_ID + ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH)
.then().log().all().statusCode(200)
.body(containsString("pieceAuditEvents")).body(containsString("totalItems"));


given().header(CONTENT_TYPE).header(TENANT).header(PERMS)
.get(ACQ_AUDIT_PIECE_PATH + PIECE_ID + ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH)
.then().log().all().statusCode(200)
.body(containsString(PIECE_ID))
.body(containsString(id1))
.body(containsString(id3))
.body(containsString(id5));

given().header(CONTENT_TYPE).header(TENANT).header(PERMS)
.get(ACQ_AUDIT_PIECE_PATH + PIECE_ID + ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH +"?limit=1")
.then().log().all().statusCode(200)
.body(containsString(PIECE_ID))
.body(containsString(id1));

given().header(CONTENT_TYPE).header(TENANT).header(PERMS)
.get(ACQ_AUDIT_PIECE_PATH + PIECE_ID + ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH +"?sortBy=action_date")
.then().log().all().statusCode(200)
.body(containsString(PIECE_ID))
.body(containsString(id1))
.body(containsString(id3))
.body(containsString(id5));

given().header(CONTENT_TYPE).header(TENANT).header(PERMS)
.get(ACQ_AUDIT_PIECE_PATH + PIECE_ID + ACQ_AUDIT_PIECE_STATUS_CHANGE_HISTORY_PATH + 123)
.then().log().all().statusCode(500)
.body(containsString("UUID string too large"));
}
}
15 changes: 15 additions & 0 deletions mod-audit-server/src/test/java/org/folio/utils/EntityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ public static PieceAuditEvent createPieceAuditEvent(String id) {
.withPieceSnapshot(jsonObject);
}

public static PieceAuditEvent createPieceAuditEvent(String id, String status) {
JsonObject jsonObject = new JsonObject();
jsonObject.put("name", "Test Product");
jsonObject.put("status", status);

return new PieceAuditEvent()
.withId(id)
.withAction(PieceAuditEvent.Action.CREATE)
.withPieceId(PIECE_ID)
.withUserId(UUID.randomUUID().toString())
.withEventDate(new Date())
.withActionDate(new Date())
.withPieceSnapshot(jsonObject);
}

public static PieceAuditEvent createPieceAuditEventWithoutSnapshot() {
return new PieceAuditEvent()
.withId(UUID.randomUUID().toString())
Expand Down
2 changes: 1 addition & 1 deletion ramls/acquisition-events.raml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ traits:
example:
strict: false
value: !include raml-util/examples/errors.sample
/piece/{id}/unique-status:
/piece/{id}/status-change-history:
get:
description: Get list of piece events which have unique status changes by piece_id
is: [
Expand Down

0 comments on commit ecd4f24

Please sign in to comment.