Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UXPROD-5090 Update DCB service point values for the attribute Hold shelf expiration period #142

Merged
merged 32 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8e93c8d
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
538d7ee
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
16c0205
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
aaab1e3
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
643857a
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
3f7d9c7
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
10b764d
UXPROD-5090 initital
AntonAntonich Jan 30, 2025
3335bea
UXPROD-5090 rolled back test code
AntonAntonich Jan 30, 2025
76b6791
UXPROD-5090 rolled back test code
AntonAntonich Jan 30, 2025
3a285f3
UXPROD-5090 fixed existing UT
AntonAntonich Jan 30, 2025
e1e8a89
UXPROD-5090 refactored
AntonAntonich Jan 30, 2025
47e2fd2
UXPROD-5090 add UT
AntonAntonich Jan 30, 2025
06c8906
UXPROD-5090 refactored
AntonAntonich Jan 30, 2025
1eb7a0d
UXPROD-5090 refactored
AntonAntonich Jan 30, 2025
e4297ad
UXPROD-5090 added tests coverage
AntonAntonich Jan 30, 2025
b7f3608
UXPROD-5090 sonar issues
AntonAntonich Jan 30, 2025
d489e65
UXPROD-5090 add additional logic
AntonAntonich Jan 30, 2025
6d98cdd
UXPROD-5090 add additional logic
AntonAntonich Jan 30, 2025
f7fc723
UXPROD-5090 refactored test
AntonAntonich Jan 30, 2025
b3c7c00
UXPROD-5090 add update service point api calling
AntonAntonich Jan 30, 2025
1da1a79
UXPROD-5090 fixed
AntonAntonich Jan 30, 2025
26bdb36
UXPROD-5090 fixed UT
AntonAntonich Jan 30, 2025
58369cf
UXPROD-5090 add time units
AntonAntonich Jan 31, 2025
5ca87d8
UXPROD-5090 changed script
AntonAntonich Jan 31, 2025
ce4d808
Merge branch 'UXPROD-5090_1' into UXPROD-5090
AntonAntonich Jan 31, 2025
60b69cd
UXPROD-5090 extracted service added test cases
AntonAntonich Feb 5, 2025
043ba90
UXPROD-5090 refactored tests
AntonAntonich Feb 5, 2025
7e8af3d
UXPROD-5090 repaired existed tests
AntonAntonich Feb 5, 2025
46842e8
UXPROD-509 sonar issue
AntonAntonich Feb 5, 2025
448d5a2
UXPROD-5090 refactored after review
AntonAntonich Feb 6, 2025
725b215
UXPROD-5090 refactored table
AntonAntonich Feb 7, 2025
22655ca
UXPROD-5090 updated readme file
AntonAntonich Feb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Version 2.0. See the file "[LICENSE](LICENSE)" for more information.
- [Issue tracker](#issue-tracker)
- [API documentation](#api-documentation)
- [Code analysis](#code-analysis)
- [Service point hold shelf period expiration](#service-point-hold-shelf-period-expiration)
- [Other documentation](#other-documentation)

## Introduction
Expand Down Expand Up @@ -113,6 +114,74 @@ This module's [API documentation](https://dev.folio.org/reference/api/#mod-dcb).

### Code analysis

### Service Point Hold Shelf Period Expiration

When creating a **DCB** transaction with the roles **LENDER** or **BORROWING-PICKUP**,
the creation of the **DCB** service point and its property **hold shelf expiration period**
depends on the values stored in the `service_point_expiration_period` table in the database.

- If the table is empty, the **hold shelf expiration period** will be set to the default value of **10 Days**.
- If the table contains a value, the stored value will be used instead.

The **F.S.E. team** is responsible for updating the values in this table.
To update the values, the following PL/pgSQL script can be executed:

```sql
DO
$$
DECLARE
schema_name TEXT;
new_duration INTEGER := 3; -- Duration in weeks
new_interval_id interval_id := 'Weeks'; -- Interval type
raw_id UUID;
sql_query TEXT;
BEGIN
FOR schema_name IN
SELECT schemaname
FROM pg_tables
WHERE tablename = 'service_point_expiration_period'
LOOP
-- Select a single ID into raw_id dynamically
sql_query := format(
'SELECT id FROM %I.service_point_expiration_period LIMIT 1',
schema_name
);
EXECUTE sql_query INTO raw_id;

-- If no record exists, insert one; otherwise, update the existing record
IF raw_id IS NULL THEN
sql_query := format(
'INSERT INTO %I.service_point_expiration_period (id, duration, interval_id)
VALUES (gen_random_uuid(), %L, %L)',
schema_name, new_duration, new_interval_id
);
ELSE
sql_query := format(
'UPDATE %I.service_point_expiration_period
SET duration = %L, interval_id = %L
WHERE id = %L',
schema_name, new_duration, new_interval_id, raw_id
);
END IF;

-- Execute the query
EXECUTE sql_query;
END LOOP;
END;
$$
LANGUAGE plpgsql;
```
**Updating Values in the Table**
To update the values, simply modify the new_duration and new_interval_id variables in the DECLARE section
of the script to reflect the new values.

**Expiration Period Handling**
For Existing Service Points
When creating a new transaction with an existing DCB service point, the hold shelf expiration period
will be checked.
If the value in the transaction payload differs from the value stored
in the database, it will be updated accordingly.

[SonarQube analysis](https://sonarcloud.io/project/overview?id=org.folio:mod-dcb).

## Other documentation
Expand Down
2 changes: 2 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"modulePermissions": [
"inventory-storage.service-points.item.post",
"inventory-storage.service-points.collection.get",
"inventory-storage.service-points.item.put",
"users.collection.get",
"users.item.post",
"usergroups.collection.get",
Expand Down Expand Up @@ -233,6 +234,7 @@
"inventory-storage.holdings.item.post",
"inventory-storage.locations.item.post",
"inventory-storage.service-points.item.post",
"inventory-storage.service-points.item.put",
"inventory-storage.location-units.libraries.collection.get",
"inventory-storage.loan-types.collection.get",
"inventory-storage.loan-types.collection.post",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(name = "service-points", configuration = FeignClientConfiguration.class)
public interface InventoryServicePointClient {

@PutMapping("/{servicepointId}")
void updateServicePointById(@PathVariable ("servicepointId") String servicePointId,
@RequestBody ServicePointRequest servicePointRequest);
@PostMapping
ServicePointRequest createServicePoint(@RequestBody ServicePointRequest pickupServicePoint);
@GetMapping("?query=name=={name}")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.folio.dcb.domain.converter;

import java.util.Arrays;

import org.folio.dcb.domain.dto.IntervalIdEnum;

import jakarta.persistence.AttributeConverter;

public class IntervalIdEnumConverter implements AttributeConverter<IntervalIdEnum, String> {

@Override
public String convertToDatabaseColumn(IntervalIdEnum intervalIdEnum) {
return intervalIdEnum.getValue();
}

@Override
public IntervalIdEnum convertToEntityAttribute(String str) {
return Arrays.stream(IntervalIdEnum.values())
.filter(value -> value.getValue().equals(str))
.findFirst()
.orElse(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.folio.dcb.domain.entity;

import java.io.Serializable;
import java.util.UUID;

import org.folio.dcb.domain.converter.IntervalIdEnumConverter;
import org.folio.dcb.domain.dto.IntervalIdEnum;

import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "service_point_expiration_period")
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ServicePointExpirationPeriodEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
private Integer duration;
@Convert(converter = IntervalIdEnumConverter.class)
private IntervalIdEnum intervalId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.folio.dcb.repository;

import org.folio.dcb.domain.entity.ServicePointExpirationPeriodEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ServicePointExpirationPeriodRepository extends
JpaRepository<ServicePointExpirationPeriodEntity, String> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.folio.dcb.service;

import org.folio.dcb.domain.dto.HoldShelfExpiryPeriod;

public interface ServicePointExpirationPeriodService {
HoldShelfExpiryPeriod getShelfExpiryPeriod();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import org.folio.dcb.client.feign.LocationUnitClient;
import org.folio.dcb.client.feign.LocationsClient;
import org.folio.dcb.domain.dto.Calendar;
import org.folio.dcb.domain.dto.HoldShelfExpiryPeriod;
import org.folio.dcb.domain.dto.NormalHours;
import org.folio.dcb.domain.dto.ServicePointRequest;
import org.folio.dcb.listener.kafka.service.KafkaService;
import org.folio.dcb.service.CalendarService;
import org.folio.dcb.service.ServicePointExpirationPeriodService;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.liquibase.FolioSpringLiquibase;
import org.folio.spring.service.PrepareSystemUserService;
Expand Down Expand Up @@ -73,14 +73,16 @@ public class CustomTenantService extends TenantService {
private final CancellationReasonClient cancellationReasonClient;
private final LoanTypeClient loanTypeClient;
private final CalendarService calendarService;
private final ServicePointExpirationPeriodService servicePointExpirationPeriodService;


public CustomTenantService(JdbcTemplate jdbcTemplate, FolioExecutionContext context, FolioSpringLiquibase folioSpringLiquibase,
PrepareSystemUserService systemUserService, KafkaService kafkaService, InstanceClient inventoryClient,
InstanceTypeClient instanceTypeClient, HoldingsStorageClient holdingsStorageClient,
LocationsClient locationsClient, HoldingSourcesClient holdingSourcesClient,
InventoryServicePointClient servicePointClient, LocationUnitClient locationUnitClient,
LoanTypeClient loanTypeClient, CancellationReasonClient cancellationReasonClient, CalendarService calendarService) {
LoanTypeClient loanTypeClient, CancellationReasonClient cancellationReasonClient, CalendarService calendarService,
ServicePointExpirationPeriodService servicePointExpirationPeriodService) {
super(jdbcTemplate, context, folioSpringLiquibase);

this.systemUserService = systemUserService;
Expand All @@ -95,6 +97,7 @@ public CustomTenantService(JdbcTemplate jdbcTemplate, FolioExecutionContext cont
this.loanTypeClient = loanTypeClient;
this.cancellationReasonClient = cancellationReasonClient;
this.calendarService = calendarService;
this.servicePointExpirationPeriodService = servicePointExpirationPeriodService;
}

@Override
Expand Down Expand Up @@ -215,7 +218,7 @@ private void createServicePoint() {
.code(CODE)
.discoveryDisplayName(NAME)
.pickupLocation(true)
.holdShelfExpiryPeriod(HoldShelfExpiryPeriod.builder().duration(3).intervalId(HoldShelfExpiryPeriod.IntervalIdEnum.DAYS).build())
.holdShelfExpiryPeriod(servicePointExpirationPeriodService.getShelfExpiryPeriod())
.holdShelfClosedLibraryDateManagement(HOLD_SHELF_CLOSED_LIBRARY_DATE_MANAGEMENT)
.build();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.folio.dcb.service.impl;

import static org.folio.dcb.utils.DCBConstants.DEFAULT_PERIOD;

import java.util.List;

import org.folio.dcb.domain.dto.HoldShelfExpiryPeriod;
import org.folio.dcb.domain.entity.ServicePointExpirationPeriodEntity;
import org.folio.dcb.repository.ServicePointExpirationPeriodRepository;
import org.folio.dcb.service.ServicePointExpirationPeriodService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j @RequiredArgsConstructor
@Service
public class ServicePointExpirationPeriodServiceImpl
implements ServicePointExpirationPeriodService {

private final ServicePointExpirationPeriodRepository servicePointExpirationPeriodRepository;

@Override
public HoldShelfExpiryPeriod getShelfExpiryPeriod() {
List<ServicePointExpirationPeriodEntity> periodList = servicePointExpirationPeriodRepository.findAll();
if (CollectionUtils.isEmpty(periodList)) {
log.info("getShelfExpiryPeriod:: default hold shelf expire period will be set: {}",
DEFAULT_PERIOD);
return DEFAULT_PERIOD;
} else {
var customPeriod = getCustomPeriod(periodList.get(0));
log.info("getShelfExpiryPeriod:: custom hold shelf expire period will be set: {}",
customPeriod);
return customPeriod;
}
}

private HoldShelfExpiryPeriod getCustomPeriod(ServicePointExpirationPeriodEntity period) {
return HoldShelfExpiryPeriod.builder()
.duration(period.getDuration())
.intervalId(period.getIntervalId())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.folio.dcb.domain.dto.HoldShelfExpiryPeriod;
import org.folio.dcb.domain.dto.ServicePointRequest;
import org.folio.dcb.service.CalendarService;
import org.folio.dcb.service.ServicePointExpirationPeriodService;
import org.folio.dcb.service.ServicePointService;
import org.folio.util.StringUtil;
import org.springframework.stereotype.Service;
Expand All @@ -19,6 +20,7 @@ public class ServicePointServiceImpl implements ServicePointService {

private final InventoryServicePointClient servicePointClient;
private final CalendarService calendarService;
private final ServicePointExpirationPeriodService servicePointExpirationPeriodService;
public static final String HOLD_SHELF_CLOSED_LIBRARY_DATE_MANAGEMENT = "Keep_the_current_due_date";

@Override
Expand All @@ -28,32 +30,37 @@ public ServicePointRequest createServicePointIfNotExists(DcbPickup pickupService
pickupServicePoint.getServicePointName());
var servicePointRequestList = servicePointClient
.getServicePointByName(StringUtil.cqlEncode(servicePointName)).getResult();
var shelfExpiryPeriod = servicePointExpirationPeriodService.getShelfExpiryPeriod();
if (servicePointRequestList.isEmpty()) {
String servicePointId = UUID.randomUUID().toString();
String servicePointCode = getServicePointCode(pickupServicePoint.getLibraryCode(),
pickupServicePoint.getServicePointName());
log.info("createServicePointIfNotExists:: creating ServicePoint with id {}, name {} and code {}",
servicePointId, servicePointName, servicePointCode);
var servicePointRequest = createServicePointRequest(servicePointId,
servicePointName, servicePointCode);
servicePointName, servicePointCode, shelfExpiryPeriod);
ServicePointRequest servicePointResponse = servicePointClient.createServicePoint(servicePointRequest);
calendarService.addServicePointIdToDefaultCalendar(UUID.fromString(servicePointResponse.getId()));
return servicePointResponse;
} else {
log.info("createServicePointIfNotExists:: servicePoint Exists with name {}, hence reusing it", servicePointName);
calendarService.associateServicePointIdWithDefaultCalendarIfAbsent(UUID.fromString(servicePointRequestList.get(0).getId()));
return servicePointRequestList.get(0);
ServicePointRequest servicePointRequest = servicePointRequestList.get(0);
servicePointRequest.setHoldShelfExpiryPeriod(shelfExpiryPeriod);
servicePointClient.updateServicePointById(servicePointRequest.getId(), servicePointRequest);
return servicePointRequest;
}
}

private ServicePointRequest createServicePointRequest(String id, String name, String code){
private ServicePointRequest createServicePointRequest(String id, String name, String code,
HoldShelfExpiryPeriod shelfExpiryPeriod){
return ServicePointRequest.builder()
.id(id)
.name(name)
.code(code)
.discoveryDisplayName(name)
.pickupLocation(true)
.holdShelfExpiryPeriod(HoldShelfExpiryPeriod.builder().duration(3).intervalId(HoldShelfExpiryPeriod.IntervalIdEnum.DAYS).build())
.holdShelfExpiryPeriod(shelfExpiryPeriod)
.holdShelfClosedLibraryDateManagement(HOLD_SHELF_CLOSED_LIBRARY_DATE_MANAGEMENT)
.build();
}
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/org/folio/dcb/utils/DCBConstants.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.folio.dcb.utils;

import org.folio.dcb.domain.dto.HoldShelfExpiryPeriod;
import org.folio.dcb.domain.dto.IntervalIdEnum;
import org.folio.dcb.domain.dto.ItemStatus;

import java.util.List;
Expand Down Expand Up @@ -37,4 +39,11 @@ private DCBConstants() {}
public static final String HOLDING_SOURCE = "folio";
public static final String DCB_CALENDAR_NAME = "DCB Calendar";
public static final List<ItemStatus.NameEnum> holdItemStatus = List.of(IN_TRANSIT, CHECKED_OUT, PAGED, AWAITING_PICKUP, AWAITING_DELIVERY);
public static final int DEFAULT_SERVICE_POINT_PERIOD_DURATION = 10;
public static final IntervalIdEnum DEFAULT_SERVICE_POINT_PERIOD_INTERVAL = IntervalIdEnum.DAYS;
public static final HoldShelfExpiryPeriod DEFAULT_PERIOD = HoldShelfExpiryPeriod.builder()
.duration(DEFAULT_SERVICE_POINT_PERIOD_DURATION)
.intervalId(DEFAULT_SERVICE_POINT_PERIOD_INTERVAL)
.build();

}
1 change: 1 addition & 0 deletions src/main/resources/db/changelog/changelog-master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
<include file="changes/add-request-to-transaction.xml" relativeToChangelogFile="true"/>
<include file="changes/set-optional-fields-nullable.xml" relativeToChangelogFile="true"/>
<include file="changes/alter-date-datatype.xml" relativeToChangelogFile="true"/>
<include file="changes/create-service-point-expiration-period-table.xml" relativeToChangelogFile="true"/>

</databaseChangeLog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DROP TYPE IF EXISTS interval_id;
CREATE TYPE interval_id AS ENUM ('Minutes', 'Hours', 'Days', 'Weeks', 'Months');
CREATE TABLE IF NOT EXISTS service_point_expiration_period
(
id uuid NOT NULL DEFAULT gen_random_uuid(),
duration integer NOT NULL,
interval_id interval_id NOT NULL,
CONSTRAINT service_point_expiration_period_pkey PRIMARY KEY (id)
);
Loading