Skip to content

Commit

Permalink
PP-2696 Reinstate Transactions list with charges and refunds
Browse files Browse the repository at this point in the history
     - Add _@Transactional_ annotation to TransactionDao since this is
     causing issues, so PP-2515 can be added back:
         google/guice#730

     - Reinstante PP-2515 Implementation of `TransactionDao`

    The implementation of `TransactionDao` is meant to be used a as
    drop-in replacement for `ChargeDao` when we want to take refunds into
    consideration while searching.

      - A transaction can be of two types `charge` or `refund`. Depending
        on whether we want to search for only charges or refunds, an
        optional payment type can be specified in the filtering
        criteria. The absence of a payment type in the search criteria
        implies all types are considered during the search.
      - The filtering criteria has been augmented to allow searching by
        refund status or charge status or any combination of both.
      - Technical note: Performance being an overriding concern when
        searching for transactions, the underlying query required to be
        hand-optimized in order to get a decent execution plan out of a
        SQL UNION with pagination. Since JPA tend to get in the way
        because of its lack of support for UNION query, we were forced to
        resort to using a native query constructed dynamically with the
        support of jOOQ's query DSL API.
        https://www.jooq.org/doc/3.9/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/
  • Loading branch information
rauligs committed Oct 2, 2017
1 parent a24aef5 commit fdb2498
Show file tree
Hide file tree
Showing 12 changed files with 1,704 additions and 33 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.9.5</version>
</dependency>
<!-- testing -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/uk/gov/pay/connector/dao/ChargeDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ private List<Predicate> buildParamPredicates(ChargeSearchParams params, Criteria
predicates.add(likePredicate(cb, charge.get(REFERENCE), params.getReference()));
if (StringUtils.isNotBlank(params.getEmail()))
predicates.add(likePredicate(cb, charge.get(EMAIL), params.getEmail()));
if (params.getChargeStatuses() != null && !params.getChargeStatuses().isEmpty())
predicates.add(charge.get(STATUS).in(params.getChargeStatuses()));
if (params.getInternalChargeStatuses() != null && !params.getInternalChargeStatuses().isEmpty())
predicates.add(charge.get(STATUS).in(params.getInternalChargeStatuses()));
if (StringUtils.isNotBlank(params.getCardBrand()))
predicates.add(charge.get(CARD_DETAILS).get("cardBrand").in(params.getCardBrand()));
if (params.getFromDate() != null)
Expand Down
114 changes: 92 additions & 22 deletions src/main/java/uk/gov/pay/connector/dao/ChargeSearchParams.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
package uk.gov.pay.connector.dao;

import uk.gov.pay.connector.model.api.ExternalChargeState;
import uk.gov.pay.connector.model.api.ExternalRefundStatus;
import uk.gov.pay.connector.model.domain.ChargeStatus;
import uk.gov.pay.connector.model.domain.RefundStatus;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

public class ChargeSearchParams {

private String transactionType;
private Long gatewayAccountId;
private String reference;
private String email;
private ZonedDateTime fromDate;
private ZonedDateTime toDate;
private Long page;
private Long displaySize;
private Set<ChargeStatus> chargeStatuses = new HashSet<>();
private String externalChargeState;
private String cardBrand;
private Set<ChargeStatus> internalChargeStatuses = new HashSet<>();
private Set<RefundStatus> internalRefundStatuses = new HashSet<>();

public Long getGatewayAccountId() {
return gatewayAccountId;
}

public ChargeSearchParams withTransactionType(String transactionType) {
this.transactionType = transactionType;
return this;
}

public ChargeSearchParams withGatewayAccountId(Long gatewayAccountId) {
this.gatewayAccountId = gatewayAccountId;
return this;
Expand All @@ -38,26 +48,77 @@ public ChargeSearchParams withEmailLike(String email) {
return this;
}

public Set<ChargeStatus> getChargeStatuses() {
return chargeStatuses;
public Set<String> getExternalChargeStates() {
return this.internalChargeStatuses.stream()
.map(s -> s.toExternal().getStatus())
.collect(Collectors.toSet());
}

public Set<String> getExternalRefundStates() {
return this.internalRefundStatuses.stream()
.map(s -> s.toExternal().getStatus())
.collect(Collectors.toSet());
}

public Set<ChargeStatus> getInternalChargeStatuses() {
return this.internalChargeStatuses;
}

public Set<RefundStatus> getInternalRefundStatuses() {
return this.internalRefundStatuses;
}

public ChargeSearchParams withExternalChargeStates(Set<String> state) {
state.stream().forEach(this::withExternalChargeState);
return this;
}

public ChargeSearchParams withExternalChargeState(String state) {
if (state != null) {
this.externalChargeState = state;
for (ExternalChargeState externalState : parseState(state)) {
this.chargeStatuses.addAll(ChargeStatus.fromExternal(externalState));
}
this.internalChargeStatuses.addAll(
parseChargeState(state).stream()
.map(ChargeStatus::fromExternal)
.flatMap(l -> l.stream())
.collect(Collectors.toSet()));
}
return this;
}

public ChargeSearchParams withInternalChargeStatuses(List<ChargeStatus> statuses) {
this.internalChargeStatuses.addAll(statuses);
return this;
}

public ChargeSearchParams withExternalRefundStates(Set<String> state) {
state.stream().forEach(this::withExternalRefundState);
return this;
}

public ChargeSearchParams withExternalRefundState(String state) {
if (state != null) {
this.internalRefundStatuses.addAll(
parseRefundState(state).stream()
.map(RefundStatus::fromExternal)
.flatMap(l -> l.stream())
.collect(Collectors.toSet()));
}
return this;
}

public ChargeSearchParams withInternalRefundStatuses(List<RefundStatus> statuses) {
this.internalRefundStatuses.addAll(statuses);
return this;
}

public ChargeSearchParams withCardBrand(String cardBrand) {
this.cardBrand = cardBrand;
return this;
}

public String getTransactionType() {
return transactionType;
}

public String getReference() {
return reference;
}
Expand Down Expand Up @@ -111,18 +172,15 @@ public ChargeSearchParams withDisplaySize(Long displaySize) {
return this;
}

public ChargeSearchParams withInternalChargeStatuses(List<ChargeStatus> statuses) {
this.chargeStatuses = new HashSet<>(statuses);
return this;
}

public String getCardBrand() {
return cardBrand;
}

public String buildQueryParams() {
StringBuilder builder = new StringBuilder();

if (isNotBlank(transactionType)) {
builder.append("&transaction_type=" + transactionType);
}
if (isNotBlank(reference))
builder.append("&reference=" + reference);
if (email != null)
Expand All @@ -135,20 +193,32 @@ public String buildQueryParams() {
builder.append("&page=" + page);
if (displaySize != null)
builder.append("&display_size=" + displaySize);
if (isNotBlank(externalChargeState)) {
builder.append("&state=" + externalChargeState);
}

getExternalChargeStates().stream()
.findFirst()
.ifPresent(state -> builder.append("&charge_state=" + state));

getExternalRefundStates().stream()
.findFirst()
.ifPresent(state -> builder.append("&refund_state=" + state));

if (isNotBlank(cardBrand)) {
builder.append("&card_brand=" + cardBrand);
}
return builder.toString().replaceFirst("&", "");
}

private List<ExternalChargeState> parseState(String state) {
List<ExternalChargeState> externalStates = new ArrayList<>();
if (isNotBlank(state)) {
externalStates.addAll(ExternalChargeState.fromStatusString(state));
private List<ExternalChargeState> parseChargeState(String state) {
if (isBlank(state)) {
new ArrayList<>();
}
return ExternalChargeState.fromStatusString(state);
}

private List<ExternalRefundStatus> parseRefundState(String state) {
if (isBlank(state)) {
new ArrayList<>();
}
return externalStates;
return ExternalRefundStatus.fromStatusString(state);
}
}
Loading

0 comments on commit fdb2498

Please sign in to comment.