Skip to content

Commit

Permalink
fix(mt942): set right amount (0.0) for missing debit floor mark
Browse files Browse the repository at this point in the history
  • Loading branch information
qoomon committed Nov 15, 2020
1 parent 97d0824 commit ca9f3d0
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
Expand Down Expand Up @@ -96,4 +97,18 @@ public String getContent() {
throw new IllegalStateException("Invalid field values within " + getClass().getSimpleName() + " instance", e);
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FloorLimitIndicator that = (FloorLimitIndicator) o;
return debitCreditMark.equals(that.debitCreditMark) &&
amount.equals(that.amount);
}

@Override
public int hashCode() {
return Objects.hash(debitCreditMark, amount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,33 @@ public MT942Page(
Preconditions.checkArgument(accountIdentification != null, "accountIdentification can't be null");
Preconditions.checkArgument(statementNumber != null, "statementNumber can't be null");

Preconditions.checkArgument(floorLimitIndicatorDebit != null, "floorLimitIndicatorDebit can't be null");
Optional<DebitCreditMark> debitMark = floorLimitIndicatorDebit.getDebitCreditMark();
debitMark.ifPresent(mark -> Preconditions.checkArgument(mark == DEBIT,
"floorLimitIndicatorDebit type can't be " + mark));

Preconditions.checkArgument(floorLimitIndicatorCredit != null, "floorLimitIndicatorCredit can't be null");
Optional<DebitCreditMark> creditMark = floorLimitIndicatorCredit.getDebitCreditMark();
creditMark.ifPresent(mark -> Preconditions.checkArgument(mark == CREDIT,
"floorLimitIndicatorCredit type can't be " + mark));

Preconditions.checkArgument(debitMark.isPresent() == creditMark.isPresent(),
"floorLimitIndicatorDebit and floorLimitIndicatorCredit debit credit marks needs to be both empty or DEBIT and CREDIT");
{
Preconditions.checkArgument(floorLimitIndicatorDebit != null, "floorLimitIndicatorDebit can't be null");
DebitCreditMark debitMark = floorLimitIndicatorDebit.getDebitCreditMark().orElse(null);
Preconditions.checkArgument(debitMark == null || debitMark == DEBIT,
"floorLimitIndicatorDebit mark can't be " + debitMark);

Preconditions.checkArgument(floorLimitIndicatorCredit != null, "floorLimitIndicatorCredit can't be null");
DebitCreditMark creditMark = floorLimitIndicatorCredit.getDebitCreditMark().orElse(null);
Preconditions.checkArgument(creditMark == null || creditMark == CREDIT,
"floorLimitIndicatorCredit mark can't be " + creditMark);

Preconditions.checkArgument((debitMark == null) == (creditMark == null),
"floorLimitIndicatorDebit and floorLimitIndicatorCredit marks need to be both blank or DEBIT and CREDIT");

if (debitMark == null) {
Preconditions.checkArgument(floorLimitIndicatorDebit.getAmount().equals(floorLimitIndicatorCredit.getAmount()),
"floorLimitIndicatorDebit and floorLimitIndicatorCredit amounts needs to be equal, if marks are blank");
}
}

Preconditions.checkArgument(dateTimeIndicator != null, "dateTimeIndicator can't be null");
Preconditions.checkArgument(transactionGroupList != null, "transactionGroupList can't be null");

// ensure matching currencies
CurrencyUnit statementCurrency = floorLimitIndicatorDebit.getAmount().getCurrencyUnit();
String statementFundsCode = statementCurrency.getCode().substring(2, 3);

{
// check floorLimitIndicatorCredit currency
CurrencyUnit currency = floorLimitIndicatorCredit.getAmount().getCurrencyUnit();
Expand Down Expand Up @@ -142,7 +149,7 @@ public MT942Page(
this.accountIdentification = accountIdentification;
this.statementNumber = statementNumber;
this.floorLimitIndicatorDebit = floorLimitIndicatorDebit;
this.floorLimitIndicatorCredit = Optional.ofNullable(floorLimitIndicatorCredit).orElse(floorLimitIndicatorDebit);
this.floorLimitIndicatorCredit = floorLimitIndicatorCredit;
this.dateTimeIndicator = dateTimeIndicator;
this.transactionGroupList = transactionGroupList;
this.transactionSummaryDebit = Optional.ofNullable(transactionSummaryDebit);
Expand Down Expand Up @@ -201,7 +208,7 @@ public String getContent() {
contentBuilder.append(swiftTextOf(accountIdentification)).append("\n");
contentBuilder.append(swiftTextOf(statementNumber)).append("\n");
contentBuilder.append(swiftTextOf(floorLimitIndicatorDebit)).append("\n");
if (floorLimitIndicatorDebit.getDebitCreditMark().isPresent()) {
if (!floorLimitIndicatorCredit.equals(floorLimitIndicatorDebit)) {
contentBuilder.append(swiftTextOf(floorLimitIndicatorCredit)).append("\n");
}
contentBuilder.append(swiftTextOf(dateTimeIndicator)).append("\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
import com.qoomon.banking.swift.submessage.exception.PageParserException;
import com.qoomon.banking.swift.submessage.field.*;
import com.qoomon.banking.swift.submessage.field.subfield.DebitCreditMark;
import org.joda.money.BigMoney;
import org.joda.money.CurrencyUnit;

import java.io.Reader;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import static com.qoomon.banking.swift.submessage.field.subfield.DebitCreditMark.CREDIT;
import static com.qoomon.banking.swift.submessage.field.subfield.DebitCreditMark.DEBIT;

/**
* Parser for {@link MT942Page}
*/
Expand Down Expand Up @@ -104,30 +109,46 @@ public MT942Page read() throws SwiftMessageParseException {
}
case FloorLimitIndicator.FIELD_TAG_34F: {
FloorLimitIndicator floorLimitIndicator = FloorLimitIndicator.of(currentField);
if (floorLimitIndicatorDebit == null) {
if(!floorLimitIndicator.getDebitCreditMark().isPresent()
|| floorLimitIndicator.getDebitCreditMark().get() == DebitCreditMark.DEBIT) {
floorLimitIndicatorDebit = floorLimitIndicator;
floorLimitIndicatorCredit = new FloorLimitIndicator(
floorLimitIndicator.getDebitCreditMark().isPresent()
? DebitCreditMark.CREDIT
: null,
floorLimitIndicator.getAmount()
);
nextValidFieldSet = ImmutableSet.of(
FloorLimitIndicator.FIELD_TAG_34F,
DateTimeIndicator.FIELD_TAG_13D);
} else {
// handle missing debit floor indicator
floorLimitIndicatorDebit = new FloorLimitIndicator(
DebitCreditMark.DEBIT,
floorLimitIndicator.getAmount()
);
floorLimitIndicatorCredit = floorLimitIndicator;
nextValidFieldSet = ImmutableSet.of(
DateTimeIndicator.FIELD_TAG_13D);
DebitCreditMark debitCreditMark = floorLimitIndicator.getDebitCreditMark().orElse(null);

// second occurrence of field 34F
if (floorLimitIndicatorDebit != null) {
if (debitCreditMark != CREDIT) {
throw new PageParserException(
"Expected Field '" + DateTimeIndicator.FIELD_TAG_13D + " (second occurrence) with CREDIT mark'," +
" but mark was '" + (debitCreditMark) + "'", fieldReader.getFieldLineNumber());
}
}

if (debitCreditMark != null) {
CurrencyUnit currencyUnit = floorLimitIndicator.getAmount().getCurrencyUnit();
switch (debitCreditMark) {
case DEBIT: {
floorLimitIndicatorDebit = floorLimitIndicator;
// preset optional credit floor indicator
floorLimitIndicatorCredit = new FloorLimitIndicator(CREDIT,
BigMoney.zero(currencyUnit));
nextValidFieldSet = ImmutableSet.of(
FloorLimitIndicator.FIELD_TAG_34F,
DateTimeIndicator.FIELD_TAG_13D);
break;
}
case CREDIT: {
floorLimitIndicatorCredit = floorLimitIndicator;
// handle missing debit floor indicator
if (floorLimitIndicatorDebit == null) {
floorLimitIndicatorDebit = new FloorLimitIndicator(DEBIT,
BigMoney.zero(currencyUnit));
}
nextValidFieldSet = ImmutableSet.of(
DateTimeIndicator.FIELD_TAG_13D);
break;
}
default:
throw new IllegalStateException("Unexpected value: " + debitCreditMark);
}
} else {
floorLimitIndicatorDebit = floorLimitIndicator;
floorLimitIndicatorCredit = floorLimitIndicator;
nextValidFieldSet = ImmutableSet.of(
DateTimeIndicator.FIELD_TAG_13D);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,57 @@ public void parse_WHEN_parse_many_valid_file_RETURN_message() throws Exception {
}

@Test
public void parse_WHEN_parse_file_with_credit_floor_RETURN_message() throws Exception {
public void parse_WHEN_parse_without_specific_floor_mark_RETURN_message() throws Exception {

// Given
String mt942MessageText = "" +
":20:02761\n" +
":25:6-9412771\n" +
":28C:1/1\n" +
":34F:USDC123,\n" +
":34F:USD123,\n" +
":13D:0001032359+0500\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:multiline info\n" +
"-info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:singleline info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":90D:75475USD123,\n" +
":90C:75475USD123,\n" +
":86:multiline summary\n" +
"summary\n" +
"-";

MT942PageReader classUnderTest = new MT942PageReader(new StringReader(mt942MessageText));

// When
List<MT942Page> pageList = TestUtils.collectUntilNull(classUnderTest::read);

// Then
assertThat(pageList).hasSize(1);
MT942Page MT942Page = pageList.get(0);
assertThat(MT942Page.getTransactionGroupList()).hasSize(3);
assertThat(MT942Page.getStatementNumber().getStatementNumber()).isEqualTo("1");
assertThat(MT942Page.getStatementNumber().getSequenceNumber()).contains("1");

FloorLimitIndicator debitFloorLimitIndicator = MT942Page.getFloorLimitIndicatorDebit();
assertThat(debitFloorLimitIndicator.getDebitCreditMark()).isEmpty();
assertThat(debitFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("123")));

FloorLimitIndicator creditFloorLimitIndicator = MT942Page.getFloorLimitIndicatorCredit();
assertThat(creditFloorLimitIndicator.getDebitCreditMark()).isEmpty();
assertThat(creditFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("123")));
}

@Test
public void parse_WHEN_parse_with_debit_floor_but_not_credit_floor_RETURN_message() throws Exception {

// Given
String mt942MessageText = "" +
":20:02761\n" +
":25:6-9412771\n" +
":28C:1/1\n" +
":34F:USDD123,\n" +
":13D:0001032359+0500\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:multiline info\n" +
Expand Down Expand Up @@ -202,6 +245,93 @@ public void parse_WHEN_parse_file_with_credit_floor_RETURN_message() throws Exce
assertThat(debitFloorLimitIndicator.getDebitCreditMark()).hasValue(DEBIT);
assertThat(debitFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("123")));

FloorLimitIndicator creditFloorLimitIndicator = MT942Page.getFloorLimitIndicatorCredit();
assertThat(creditFloorLimitIndicator.getDebitCreditMark()).hasValue(CREDIT);
assertThat(creditFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.zero(USD));
}

@Test
public void parse_WHEN_parse_with_debit_floor_snd_credit_floor_RETURN_message() throws Exception {

// Given
String mt942MessageText = "" +
":20:02761\n" +
":25:6-9412771\n" +
":28C:1/1\n" +
":34F:USDD123,\n" +
":34F:USDC789,\n" +
":13D:0001032359+0500\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:multiline info\n" +
"-info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:singleline info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":90D:75475USD123,\n" +
":90C:75475USD123,\n" +
":86:multiline summary\n" +
"summary\n" +
"-";

MT942PageReader classUnderTest = new MT942PageReader(new StringReader(mt942MessageText));

// When
List<MT942Page> pageList = TestUtils.collectUntilNull(classUnderTest::read);

// Then
assertThat(pageList).hasSize(1);
MT942Page MT942Page = pageList.get(0);
assertThat(MT942Page.getTransactionGroupList()).hasSize(3);
assertThat(MT942Page.getStatementNumber().getStatementNumber()).isEqualTo("1");
assertThat(MT942Page.getStatementNumber().getSequenceNumber()).contains("1");

FloorLimitIndicator debitFloorLimitIndicator = MT942Page.getFloorLimitIndicatorDebit();
assertThat(debitFloorLimitIndicator.getDebitCreditMark()).hasValue(DEBIT);
assertThat(debitFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("123")));

FloorLimitIndicator creditFloorLimitIndicator = MT942Page.getFloorLimitIndicatorCredit();
assertThat(creditFloorLimitIndicator.getDebitCreditMark()).hasValue(CREDIT);
assertThat(creditFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("789")));
}

@Test
public void parse_WHEN_parse_with_missing_debit_floor_but_credit_floor_RETURN_message() throws Exception {

// Given
String mt942MessageText = "" +
":20:02761\n" +
":25:6-9412771\n" +
":28C:1/1\n" +
":34F:USDC123,\n" +
":13D:0001032359+0500\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:multiline info\n" +
"-info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":86:singleline info\n" +
":61:0312091211D880,FTRFBPHP/081203/0003//59512112915002\n" +
":90D:75475USD123,\n" +
":90C:75475USD123,\n" +
":86:multiline summary\n" +
"summary\n" +
"-";

MT942PageReader classUnderTest = new MT942PageReader(new StringReader(mt942MessageText));

// When
List<MT942Page> pageList = TestUtils.collectUntilNull(classUnderTest::read);

// Then
assertThat(pageList).hasSize(1);
MT942Page MT942Page = pageList.get(0);
assertThat(MT942Page.getTransactionGroupList()).hasSize(3);
assertThat(MT942Page.getStatementNumber().getStatementNumber()).isEqualTo("1");
assertThat(MT942Page.getStatementNumber().getSequenceNumber()).contains("1");

FloorLimitIndicator debitFloorLimitIndicator = MT942Page.getFloorLimitIndicatorDebit();
assertThat(debitFloorLimitIndicator.getDebitCreditMark()).hasValue(DEBIT);
assertThat(debitFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.zero(USD));

FloorLimitIndicator creditFloorLimitIndicator = MT942Page.getFloorLimitIndicatorCredit();
assertThat(creditFloorLimitIndicator.getDebitCreditMark()).hasValue(CREDIT);
assertThat(creditFloorLimitIndicator.getAmount()).isEqualTo(BigMoney.of(USD, new BigDecimal("123")));
Expand Down

0 comments on commit ca9f3d0

Please sign in to comment.