Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package uk.gov.hmcts.reform.pcs.ccd.entity.feesandpay;

import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity;
import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyEntity;
import uk.gov.hmcts.reform.pcs.feesandpay.model.PaymentStatus;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;

import static jakarta.persistence.FetchType.LAZY;

@Entity
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "fee_payment")
public class FeePaymentEntity {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "claim_id", nullable = false)
@JsonBackReference
private ClaimEntity claim;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "party_id", nullable = false)
@JsonBackReference
private PartyEntity party;

@CreationTimestamp
@Column(updatable = false, nullable = false)
private LocalDateTime requestDate;

// Service Request Reference from the createRequest
private String requestReference;

private String externalReference;

private BigDecimal amount;

private String paymentStatus;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package uk.gov.hmcts.reform.pcs.ccd.repository.feeandpay;

import org.springframework.data.jpa.repository.JpaRepository;
import uk.gov.hmcts.reform.pcs.ccd.entity.feesandpay.FeePaymentEntity;

import java.util.Optional;
import java.util.UUID;

public interface FeePaymentRepository extends JpaRepository<FeePaymentEntity, UUID> {

Optional<FeePaymentEntity> findByRequestReference(String requestReference);

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ private static boolean isStubEnvironment(String value) {
String lower = value.toLowerCase(Locale.UK);
return lower.contains("dev") || lower.contains("preview") || lower.contains("aat");
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package uk.gov.hmcts.reform.pcs.feesandpay.endpoint;

import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import uk.gov.hmcts.reform.pcs.feesandpay.model.ServiceRequestUpdate;
import uk.gov.hmcts.reform.pcs.feesandpay.service.PaymentService;

import static com.azure.core.http.ContentType.APPLICATION_JSON;

@RestController
@AllArgsConstructor
public class PaymentCallBackController {

private final PaymentService paymentService;

@PostMapping(path = "/service-request-update", consumes = APPLICATION_JSON)
@Operation(description = "Callback to create Fee and Pay service request")
public void ccdSubmitted(
@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authorisation,
@RequestHeader(value = "ServiceAuthorization", required = false) String s2sToken,
@RequestBody ServiceRequestUpdate serviceRequestUpdate) {

paymentService.processPaymentResponse(serviceRequestUpdate);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uk.gov.hmcts.reform.pcs.feesandpay.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Payment {

@JsonProperty("payment_amount")
private BigDecimal paymentAmount;
@JsonProperty("payment_reference")
private String paymentReference;
@JsonProperty("payment_method")
private String paymentMethod;
@JsonProperty("case_reference")
private String caseReference;
@JsonProperty("account_number")
private String accountNumber;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package uk.gov.hmcts.reform.pcs.feesandpay.model;

import lombok.Getter;

@Getter
public enum PaymentStatus {

PAID("Paid"),
NOT_PAID("Not paid"),
PARTIALLY_PAID("Partially paid");

private String value;

public static PaymentStatus fromValue(String value) {
for (PaymentStatus status : values()) {
if (status.value.equalsIgnoreCase(value)) {
return status;
}
}
throw new IllegalArgumentException("Unknown PaymentStatus value: " + value);
}

PaymentStatus(String s) {
value = s;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uk.gov.hmcts.reform.pcs.feesandpay.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ServiceRequestUpdate {

@JsonProperty("service_request_reference")
private String serviceRequestReference;
@JsonProperty("ccd_case_number")
private String ccdCaseNumber;
@JsonProperty("service_request_amount")
private BigDecimal serviceRequestAmount;
@JsonProperty("service_request_status")
private String serviceRequestStatus;
@JsonProperty("payment")
private Payment payment;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package uk.gov.hmcts.reform.pcs.feesandpay.service;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -9,10 +10,21 @@
import uk.gov.hmcts.reform.payments.client.models.FeeDto;
import uk.gov.hmcts.reform.payments.request.CreateServiceRequestDTO;
import uk.gov.hmcts.reform.payments.response.PaymentServiceResponse;
import uk.gov.hmcts.reform.pcs.ccd.entity.ClaimEntity;
import uk.gov.hmcts.reform.pcs.ccd.entity.PcsCaseEntity;
import uk.gov.hmcts.reform.pcs.ccd.entity.feesandpay.FeePaymentEntity;
import uk.gov.hmcts.reform.pcs.ccd.entity.party.ClaimPartyEntity;
import uk.gov.hmcts.reform.pcs.ccd.repository.feeandpay.FeePaymentRepository;
import uk.gov.hmcts.reform.pcs.ccd.service.PcsCaseService;
import uk.gov.hmcts.reform.pcs.feesandpay.mapper.PaymentRequestMapper;
import uk.gov.hmcts.reform.pcs.feesandpay.model.FeeDetails;
import uk.gov.hmcts.reform.pcs.feesandpay.model.PaymentStatus;
import uk.gov.hmcts.reform.pcs.feesandpay.model.ServiceRequestUpdate;
import uk.gov.hmcts.reform.pcs.idam.IdamService;

import java.time.LocalDateTime;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -21,6 +33,8 @@ public class PaymentService {
private final PaymentsClient paymentsClient;
private final PaymentRequestMapper paymentRequestMapper;
private final IdamService idamService;
private final FeePaymentRepository feePaymentRepository;
private final PcsCaseService pcsCaseService;

@Value("${payments.api.callback-url}")
private String callbackUrl;
Expand All @@ -44,17 +58,12 @@ public class PaymentService {
* @param responsibleParty the party responsible for the payment
* @return {@link PaymentServiceResponse} containing the service request reference
*/
public PaymentServiceResponse createServiceRequest(
String caseReference,
String ccdCaseNumber,
FeeDetails feeDetails,
int volume,
String responsibleParty
) {
FeeDto feeDto = paymentRequestMapper.toFeeDto(feeDetails, volume);
@Transactional
public PaymentServiceResponse createServiceRequest(String caseReference, String ccdCaseNumber,
FeeDetails feeDetails, int volume, String responsibleParty) {

CasePaymentRequestDto casePaymentRequest =
paymentRequestMapper.toCasePaymentRequest(responsibleParty);
FeeDto feeDto = paymentRequestMapper.toFeeDto(feeDetails, volume);
CasePaymentRequestDto casePaymentRequest = paymentRequestMapper.toCasePaymentRequest(responsibleParty);

CreateServiceRequestDTO requestDto = CreateServiceRequestDTO.builder()
.callBackUrl(callbackUrl)
Expand All @@ -65,9 +74,51 @@ public PaymentServiceResponse createServiceRequest(
.hmctsOrgId(hmctsOrgId)
.build();

return paymentsClient.createServiceRequest(
idamService.getSystemUserAuthorisation(),
requestDto
);
PaymentServiceResponse paymentServiceResponse = paymentsClient.createServiceRequest(
idamService.getSystemUserAuthorisation(), requestDto);

ClaimEntity claimEntity = retrieveClaimEntity(caseReference);
ClaimPartyEntity claimPartyEntity = retrieveClaimPartyEntity(claimEntity, responsibleParty);
saveNewFeePayment(claimEntity, claimPartyEntity, feeDto, paymentServiceResponse.getServiceRequestReference());

return paymentServiceResponse;
}

public void processPaymentResponse(ServiceRequestUpdate serviceRequestUpdate) {
log.info("ServiceRequestUpdate status: {}", serviceRequestUpdate.getServiceRequestStatus());
Optional<FeePaymentEntity> byCaseReference = feePaymentRepository
.findByRequestReference(serviceRequestUpdate.getServiceRequestReference());
if (byCaseReference.isPresent()) {
FeePaymentEntity feePaymentEntity = byCaseReference.get();
feePaymentEntity.setPaymentStatus(serviceRequestUpdate.getServiceRequestStatus());
feePaymentRepository.save(feePaymentEntity);
}
}

private ClaimPartyEntity retrieveClaimPartyEntity(ClaimEntity claimEntity, String responsibleParty) {
return claimEntity.getClaimParties()
.stream()
.filter(party -> party.getParty().getOrgName().equals(responsibleParty))
.findFirst()
.orElseThrow(() -> new IllegalStateException("Matching PartyEntity not found"));
}

private void saveNewFeePayment(ClaimEntity claimEntity, ClaimPartyEntity claimParty, FeeDto feeDto,
String serviceRequestReference) {
FeePaymentEntity feePaymentEntity = FeePaymentEntity.builder()
.claim(claimEntity)
.requestDate(LocalDateTime.now())
.requestReference(serviceRequestReference)
.amount(feeDto.getCalculatedAmount())
.party(claimParty.getParty())
.build();
feePaymentRepository.save(feePaymentEntity);
}

private ClaimEntity retrieveClaimEntity(String caseReference) {
PcsCaseEntity pcsCaseEntity = pcsCaseService.loadCase(Long.parseLong(caseReference));
// Assuming 1 claim per PcsCase
return pcsCaseEntity.getClaims().getFirst();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ public CustomTask<FeesAndPayTaskData> feePaymentTask() {
}
});
}

}
6 changes: 3 additions & 3 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,12 @@ access-code:

payments:
api:
url: ${PAYMENT_API_URL:http://localhost:8083}
callback-url: ${PAY_CALLBACK_URL:http://host.docker.internal:8096/service-request-update}
url: ${PAYMENT_API_URL:http://localhost:8083/payments}
callback-url: ${PAY_CALLBACK_URL:http://host.docker.internal:3206/service-request-update}
params:
organisationUrn: Mortgage and Landlord Possession Claims
hmctsOrgId: ${hmcts.hmctsOrgId}

core_case_data:
api:
url: ${CCD_DATA_STORE_URL:localhost:4452}
url: ${CCD_DATA_STORE_URL:localhost:4452}
14 changes: 14 additions & 0 deletions src/main/resources/db/migration/V075__fee_payment.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CREATE TABLE fee_payment (
id UUID NOT NULL,
claim_id UUID NOT NULL,
party_id UUID NOT NULL,
request_date TIMESTAMP NOT NULL,
request_reference VARCHAR(255),
external_reference VARCHAR(255),
amount NUMERIC(19, 2),
payment_status VARCHAR(50),

CONSTRAINT pk_fee_payment PRIMARY KEY (id),
CONSTRAINT fk_fee_payment_claim FOREIGN KEY (claim_id) REFERENCES claim (id),
CONSTRAINT fk_fee_payment_party FOREIGN KEY (party_id) REFERENCES party (id)
);
Loading
Loading