Skip to content

Commit

Permalink
Merge pull request #851 from alphagov/PP-6758-csv-consumer-uses-flat-…
Browse files Browse the repository at this point in the history
…refunds

PP-6758 CSV consumer uses flat refunds
  • Loading branch information
kbottla authored Jul 24, 2020
2 parents 1d4775c + e328172 commit 5ab9cb1
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class TransactionDao {
"ORDER BY t.created_date DESC OFFSET :offset LIMIT :limit";

private static final String SEARCH_TRANSACTIONS_CURSOR =
SEARCH_TRANSACTIONS_WITH_PARENT_BASE +
"SELECT * FROM transaction t " +
":searchExtraFields " +
":cursorFields " +
"ORDER BY t.created_date DESC, t.id DESC LIMIT :limit";
Expand Down Expand Up @@ -295,7 +295,7 @@ public List<TransactionEntity> cursorTransactionSearch(TransactionSearchParams s
query.bind("startingAfterId", startingAfterId);
query.bind("limit", cursorPageSize);

return query.map(new TransactionWithParentMapper()).list();
return query.map(new TransactionMapper()).list();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static java.math.BigDecimal.valueOf;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.lowerCase;
import static org.apache.commons.lang3.StringUtils.replaceChars;
import static org.apache.commons.text.WordUtils.capitalizeFully;
import static uk.gov.pay.ledger.util.JsonParser.safeGetAsLong;
Expand Down Expand Up @@ -81,29 +82,30 @@ public Map<String, Object> toMap(TransactionEntity transactionEntity) {

if (TransactionType.PAYMENT.toString().equals(transactionEntity.getTransactionType())) {
result.putAll(
getPaymentTransactionAttributes(transactionEntity)
getPaymentTransactionAttributes(transactionEntity, transactionDetails)
);

result.put(FIELD_GOVUK_PAYMENT_ID, transactionEntity.getExternalId());
result.put(FIELD_AMOUNT, penceToCurrency(transactionEntity.getAmount()));
result.put(FIELD_TOTAL_AMOUNT, penceToCurrency(totalAmount));
result.put(FIELD_NET, penceToCurrency(netAmount));
result.put(FIELD_FEE, penceToCurrency(transactionEntity.getFee()));
result.put(FIELD_STATE, PaymentState.getDisplayName(transactionEntity.getState()));
result.put(FIELD_MOTO, transactionEntity.isMoto());
}
if (TransactionType.REFUND.toString().equals(transactionEntity.getTransactionType())) {
if (transactionEntity.getParentTransactionEntity() != null) {
result.putAll(
getPaymentTransactionAttributes(transactionEntity.getParentTransactionEntity())
);
}

result.putAll(
getPaymentTransactionAttributes(transactionEntity, transactionDetails.get("payment_details"))
);
result.put(FIELD_GOVUK_PAYMENT_ID, transactionEntity.getParentExternalId());
result.put(FIELD_AMOUNT, penceToCurrency(transactionEntity.getAmount() * -1));
result.put(FIELD_NET, penceToCurrency(netAmount * -1));
result.put(FIELD_TOTAL_AMOUNT, penceToCurrency(totalAmount * -1));
result.put(FIELD_ISSUED_BY, safeGetAsString(transactionDetails, "user_email"));
result.put(FIELD_STATE, RefundState.getDisplayName(transactionEntity.getState()));
}

result.put(FIELD_PROVIDER_ID, sanitiseAgainstSpreadsheetFormulaInjection(transactionEntity.getGatewayTransactionId()));
result.put(FIELD_DATE_CREATED, dateCreated);
result.put(FIELD_TIME_CREATED, timeCreated);
result.put(FIELD_CORPORATE_CARD_SURCHARGE, penceToCurrency(
Expand All @@ -130,28 +132,24 @@ public Map<String, Object> toMap(TransactionEntity transactionEntity) {
return result;
}

private Map<String, Object> getPaymentTransactionAttributes(TransactionEntity transactionEntity) throws IOException {
Map<String, Object> result = new HashMap<>();
private Map<String, Object> getPaymentTransactionAttributes(TransactionEntity transactionEntity, JsonNode details) {

JsonNode transactionDetails = objectMapper.readTree(
Optional.ofNullable(transactionEntity.getTransactionDetails()).orElse("{}"));
Map<String, Object> result = new HashMap<>();

result.put(FIELD_REFERENCE, sanitiseAgainstSpreadsheetFormulaInjection(transactionEntity.getReference()));
result.put(FIELD_DESC, sanitiseAgainstSpreadsheetFormulaInjection(transactionEntity.getDescription()));
result.put(FIELD_EMAIL, sanitiseAgainstSpreadsheetFormulaInjection(transactionEntity.getEmail()));
result.put(FIELD_CARDHOLDER_NAME, sanitiseAgainstSpreadsheetFormulaInjection(transactionEntity.getCardholderName()));
result.put(FIELD_CARD_NUMBER, transactionEntity.getLastDigitsCardNumber());
result.put(FIELD_GOVUK_PAYMENT_ID, transactionEntity.getExternalId());

result.put(FIELD_CARD_BRAND, safeGetAsString(transactionDetails, "card_brand_label"));
result.put(FIELD_CARD_EXPIRY_DATE, safeGetAsString(transactionDetails, "expiry_date"));
result.put(FIELD_PROVIDER_ID, safeGetAsString(transactionDetails, "gateway_transaction_id"));
result.put(FIELD_CARD_TYPE, StringUtils.lowerCase(safeGetAsString(transactionDetails, "card_type")));
result.put(FIELD_MOTO, transactionEntity.isMoto());

result.put(FIELD_WALLET_TYPE, capitalizeFully(
replaceChars(safeGetAsString(transactionDetails, "wallet"), '_', ' '))
);
if (details != null) {
result.put(FIELD_CARD_BRAND, safeGetAsString(details, "card_brand_label"));
result.put(FIELD_CARD_EXPIRY_DATE, safeGetAsString(details, "expiry_date"));
result.put(FIELD_CARD_TYPE, lowerCase(safeGetAsString(details, "card_type")));
result.put(FIELD_WALLET_TYPE, capitalizeFully(
replaceChars(safeGetAsString(details, "wallet"), '_', ' '))
);
}

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,14 @@ public void setUp() {
.withState(TransactionState.FAILED_REJECTED)
.withTransactionType(TransactionType.PAYMENT.name())
.withAmount(100L)
.withGatewayTransactionId("gateway-transaction-id")
.withCreatedDate(ZonedDateTime.parse("2018-03-12T16:25:01.123456Z"))
.withTotalAmount(123L)
.withTransactionDetails(
new GsonBuilder().create()
.toJson(ImmutableMap.builder()
.put("expiry_date", "10/24")
.put("user_email", "refundedbyuser@example.org")
.put("corporate_surcharge", 23)
.put("wallet", "APPLE_PAY")
.put("card_type", "DEBIT")
.put("card_brand_label", "Visa")
.build())
);
.withMoto(true)
.withCorporateCardSurcharge(23)
.withCardBrandLabel("Visa")
.withDefaultCardDetails()
.withDefaultTransactionDetails();
}

@Test
Expand All @@ -58,6 +53,8 @@ public void toMapShouldReturnMapWithCorrectCsvDataForPaymentTransaction() {
assertPaymentDetails(csvDataMap, transactionEntity);

assertThat(csvDataMap.get("Amount"), is("1.00"));
assertThat(csvDataMap.get("GOV.UK Payment ID"), is(transactionEntity.getExternalId()));
assertThat(csvDataMap.get("Provider ID"), is(transactionEntity.getGatewayTransactionId()));
assertThat(csvDataMap.get("State"), is("Declined"));
assertThat(csvDataMap.get("Finished"), is(true));
assertThat(csvDataMap.get("Error Code"), is("P0010"));
Expand All @@ -66,27 +63,30 @@ public void toMapShouldReturnMapWithCorrectCsvDataForPaymentTransaction() {
assertThat(csvDataMap.get("Time Created"), is("16:25:01"));
assertThat(csvDataMap.get("Corporate Card Surcharge"), is("0.23"));
assertThat(csvDataMap.get("Total Amount"), is("1.23"));
assertThat(csvDataMap.get("MOTO"), is(true));
}

@Test
public void toMapShouldReturnMapWithCorrectCsvDataForRefundTransaction() {

TransactionEntity transactionEntity = transactionFixture
.withMoto(true)
.toEntity();
TransactionEntity refundTransactionEntity = transactionFixture.withTransactionType("REFUND")
TransactionFixture refundTransactionFixture = aTransactionFixture()
.withCreatedDate(ZonedDateTime.parse("2018-03-12T16:25:01.123456Z"))
.withTransactionType("REFUND")
.withAmount(99L)
.withTotalAmount(99L)
.withState(TransactionState.ERROR)
.withParentTransactionEntity(transactionEntity)
.withTransactionDetails(new GsonBuilder().create()
.toJson(ImmutableMap.builder().put("user_email", "refundedbyuser@example.org").build()))
.toEntity();
.withGatewayTransactionId("refund-gateway-transaction-id")
.withRefundedByUserEmail("refundedbyuser@example.org")
.withParentExternalId("parent-external-id")
.withDefaultPaymentDetails()
.withDefaultTransactionDetails();

Map<String, Object> csvDataMap = csvTransactionFactory.toMap(refundTransactionEntity);
Map<String, Object> csvDataMap = csvTransactionFactory.toMap(refundTransactionFixture.toEntity());

assertPaymentDetails(csvDataMap, refundTransactionEntity.getParentTransactionEntity());
assertPaymentDetails(csvDataMap, refundTransactionFixture.toEntity());
assertThat(csvDataMap.get("Amount"), is("-0.99"));
assertThat(csvDataMap.get("Provider ID"), is(refundTransactionFixture.getGatewayTransactionId()));
assertThat(csvDataMap.get("GOV.UK Payment ID"), is(refundTransactionFixture.getParentExternalId()));
assertThat(csvDataMap.get("State"), is("Refund error"));
assertThat(csvDataMap.get("Finished"), is(true));
assertThat(csvDataMap.get("Error Code"), is("P0050"));
Expand All @@ -96,7 +96,7 @@ public void toMapShouldReturnMapWithCorrectCsvDataForRefundTransaction() {
assertThat(csvDataMap.get("Corporate Card Surcharge"), is("0.00"));
assertThat(csvDataMap.get("Total Amount"), is("-0.99"));
assertThat(csvDataMap.get("Net"), is("-0.99"));
assertThat(csvDataMap.get("MOTO"), is(true));
assertThat(csvDataMap.get("MOTO"), is(nullValue()));
}

@Test
Expand Down Expand Up @@ -206,11 +206,9 @@ private void assertPaymentDetails(Map<String, Object> csvDataMap, TransactionEnt
assertThat(csvDataMap.get("Email"), is(transactionEntity.getEmail()));
assertThat(csvDataMap.get("Card Brand"), is("Visa"));
assertThat(csvDataMap.get("Cardholder Name"), is(transactionEntity.getCardholderName()));
assertThat(csvDataMap.get("Card Expiry Date"), is("10/24"));
assertThat(csvDataMap.get("Card Expiry Date"), is("10/21"));
assertThat(csvDataMap.get("Card Number"), is(transactionEntity.getLastDigitsCardNumber()));
assertThat(csvDataMap.get("Provider ID"), is(transactionEntity.getGatewayTransactionId()));
assertThat(csvDataMap.get("GOV.UK Payment ID"), is(transactionEntity.getExternalId()));
assertThat(csvDataMap.get("Card Type"), is("debit"));
assertThat(csvDataMap.get("Card Type"), is("credit"));
assertThat(csvDataMap.get("Wallet Type"), is("Apple Pay"));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package uk.gov.pay.ledger.transaction.resource;

import com.google.common.collect.ImmutableMap;
import io.dropwizard.testing.junit5.DropwizardExtensionsSupport;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import uk.gov.pay.ledger.extension.AppWithPostgresAndSqsExtension;
import uk.gov.pay.ledger.metadatakey.dao.MetadataKeyDao;
Expand Down Expand Up @@ -75,7 +73,7 @@ public void shouldGetAllTransactionsAsCSVWithAcceptType() throws IOException {
.withGatewayAccountId(otherGatewayAccountId)
.insert(rule.getJdbi());

aTransactionFixture()
TransactionFixture refundTransactionFixture = aTransactionFixture()
.withTransactionType("REFUND")
.withParentExternalId(transactionFixture.getExternalId())
.withGatewayAccountId(transactionFixture.getGatewayAccountId())
Expand All @@ -84,6 +82,8 @@ public void shouldGetAllTransactionsAsCSVWithAcceptType() throws IOException {
.withAmount(100L)
.withTotalAmount(100L)
.withState(TransactionState.ERROR_GATEWAY)
.withGatewayTransactionId("refund-gateway-transaction-id")
.withDefaultPaymentDetails()
.withDefaultTransactionDetails()
.insert(rule.getJdbi());

Expand All @@ -110,8 +110,10 @@ public void shouldGetAllTransactionsAsCSVWithAcceptType() throws IOException {

CSVRecord paymentRecord = csvRecords.get(0);
assertThat(paymentRecord.size(), is(22));
assertPaymentTransactionDetails(paymentRecord, transactionFixture);
assertCommonPaymentFields(paymentRecord, transactionFixture);
assertThat(paymentRecord.get("Amount"), is("1.23"));
assertThat(paymentRecord.get("GOV.UK Payment ID"), is(transactionFixture.getExternalId()));
assertThat(paymentRecord.get("Provider ID"), is(transactionFixture.getGatewayTransactionId()));
assertThat(paymentRecord.get("State"), is("Error"));
assertThat(paymentRecord.get("Finished"), is("true"));
assertThat(paymentRecord.get("Error Code"), is("P0050"));
Expand All @@ -127,8 +129,10 @@ public void shouldGetAllTransactionsAsCSVWithAcceptType() throws IOException {
assertThat(paymentRecord.isMapped("MOTO"), is(false));

CSVRecord refundRecord = csvRecords.get(1);
assertPaymentTransactionDetails(refundRecord, transactionFixture);
assertCommonPaymentFields(refundRecord, refundTransactionFixture);
assertThat(refundRecord.get("Amount"), is("-1.00"));
assertThat(refundRecord.get("GOV.UK Payment ID"), is(refundTransactionFixture.getParentExternalId()));
assertThat(refundRecord.get("Provider ID"), is(refundTransactionFixture.getGatewayTransactionId()));
assertThat(refundRecord.get("State"), is("Refund error"));
assertThat(refundRecord.get("Finished"), is("true"));
assertThat(refundRecord.get("Error Code"), is("P0050"));
Expand All @@ -139,6 +143,7 @@ public void shouldGetAllTransactionsAsCSVWithAcceptType() throws IOException {
assertThat(refundRecord.get("Total Amount"), is("-1.00"));
assertThat(refundRecord.get("Wallet Type"), is("Apple Pay"));
assertThat(refundRecord.get("Issued By"), is("refund-by-user-email@example.org"));
assertThat(refundRecord.isMapped("MOTO"), is(false));
}

@Test
Expand Down Expand Up @@ -364,16 +369,14 @@ public void shouldGetAllTransactionsForAGivenGatewayPayoutId() throws IOExceptio
assertThat(paymentRecord.get("GOV.UK Payment ID"), is(transactionFixture.getExternalId()));
}

private void assertPaymentTransactionDetails(CSVRecord csvRecord, TransactionFixture transactionFixture) {
private void assertCommonPaymentFields(CSVRecord csvRecord, TransactionFixture transactionFixture) {
assertThat(csvRecord.get("Reference"), is(transactionFixture.getReference()));
assertThat(csvRecord.get("Description"), is(transactionFixture.getDescription()));
assertThat(csvRecord.get("Email"), is("someone@example.org"));
assertThat(csvRecord.get("Card Brand"), is("Diners Club"));
assertThat(csvRecord.get("Cardholder Name"), is("J Doe"));
assertThat(csvRecord.get("Card Brand"), is(transactionFixture.getCardBrandLabel()));
assertThat(csvRecord.get("Cardholder Name"), is(transactionFixture.getCardholderName()));
assertThat(csvRecord.get("Card Expiry Date"), is("10/21"));
assertThat(csvRecord.get("Card Number"), is("1234"));
assertThat(csvRecord.get("Provider ID"), is("gateway-transaction-id"));
assertThat(csvRecord.get("GOV.UK Payment ID"), is(transactionFixture.getExternalId()));
assertThat(csvRecord.get("Card Type"), is("credit"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ public Long getId() {
return id;
}

public String getCardExpiryDate() {
return cardExpiryDate;
}

public TransactionFixture withId(Long id) {
this.id = id;
return this;
Expand Down Expand Up @@ -221,12 +225,18 @@ public String getCardBrand() {
return cardBrand;
}

public String getCardBrandLabel() {
return cardBrandLabel;
}

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

public boolean isMoto() { return moto;}
public boolean isMoto() {
return moto;
}

public TransactionFixture withMoto(boolean moto) {
this.moto = moto;
Expand Down Expand Up @@ -378,6 +388,10 @@ public TransactionFixture insert(Jdbi jdbi) {
@NotNull
private JsonObject getTransactionDetail() {
JsonObject transactionDetails = new JsonObject();
JsonObject refundPaymentDetails = new JsonObject();

String defaultCardType = String.valueOf(CREDIT);
String defaultWalletType = "APPLE_PAY";

transactionDetails.addProperty("language", language);
transactionDetails.addProperty("return_url", returnUrl);
Expand All @@ -387,8 +401,17 @@ private JsonObject getTransactionDetail() {
transactionDetails.addProperty("corporate_surcharge", corporateCardSurcharge);
transactionDetails.addProperty("refunded_by", refundedById);
transactionDetails.addProperty("user_email", refundedByUserEmail);
transactionDetails.addProperty("card_type", String.valueOf(CREDIT));
transactionDetails.addProperty("wallet", "APPLE_PAY");
transactionDetails.addProperty("card_type", defaultCardType);
transactionDetails.addProperty("wallet", defaultWalletType);

if ("REFUND".equals(transactionType)) {
refundPaymentDetails.addProperty("card_brand_label", cardBrandLabel);
refundPaymentDetails.addProperty("expiry_date", cardExpiryDate);
refundPaymentDetails.addProperty("card_type", defaultCardType);
refundPaymentDetails.addProperty("wallet", defaultWalletType);
transactionDetails.add("payment_details", refundPaymentDetails);
}

Optional.ofNullable(cardBrandLabel)
.ifPresent(cardBrandLabel -> transactionDetails.addProperty("card_brand_label", cardBrandLabel));
Optional.ofNullable(externalMetadata)
Expand Down Expand Up @@ -593,4 +616,13 @@ public TransactionFixture withRefundedByUserEmail(String refundedByUserEmail) {
this.refundedByUserEmail = refundedByUserEmail;
return this;
}

public TransactionFixture withDefaultPaymentDetails() {
// default values are already assigned for cardBrand, cardholderName, reference, description, email

this.firstDigitsCardNumber = "123456";
this.lastDigitsCardNumber = "1234";
this.cardBrandLabel = "Visa";
return this;
}
}

0 comments on commit 5ab9cb1

Please sign in to comment.