Skip to content

Conversation

@nieldw
Copy link
Contributor

@nieldw nieldw commented Dec 4, 2020

Currently this library resolves the year of a statement line entry date according to the rule that if the entry date month is before the value date month the year is the following year:

// calculate entry year
int entryYear = entryMonthDay.getMonthValue() >= valueDate.getMonthValue()
       ? valueDate.getYear()
       : valueDate.getYear() + 1;

That rule works well if the entry date is always after the value date. However, if the value date is after the entry (as may be frequently the case) it yields unexpected results. For example, if the entry date is --07-29 and the value date is 2020-08-01 the rule yields an entry date of 2021-07-29.

This PR introduces the EntryDateResolutionStrategy. Users of MT940PageReader and MT942PageReader may now supply an EntryDateResolutionStrategy to define how statement line entry dates are resolved, based on the value date.

To maintain backwards compatibility the ability to supply the strategy is introduced through method overloads. Because users of the library may rely on the existing behaviour the default strategy is the EarlierMonthImpliesFollowingYearEntryDateResolutionStrategy which implements the exiting strategy, discussed above.

A ShortestDeltaEntryDateResolutionStrategy is also provided. This strategy views the MonthDay timeline as a circle, like the hours on a clock. If the shortest delta around the circle does not span 31 December, the entry date's year is the same as that of the value date. Otherwise it is either the previous year if the entry date is before the value date on the circular timeline, or the next year if the entry date is after the value date. This strategy may be most suitable if statements are delivered more frequently.

Unfortunately there is no perfect strategy for determining the correct year of the entry date. For a discussion on possible approaches, please see this thread: wolph/mt940#17

Example usage:

MT942PageReader reader = new MT942PageReader(new StringReader(msg.textBlock.text), new ShortestDeltaEntryDateResolutionStrategy());

Users of MT940PageReader and MT942PageReader may supply an EntryDateResolutionStrategy to define how statement line entry dates are resolved, based on the value date.

The default is EarlierMonthImpliesFollowingYearEntryDateResolutionStrategy. ShortestDeltaEntryDateResolutionStrategy is also provided.
@qoomon
Copy link
Owner

qoomon commented Dec 4, 2020

LGTM however I am a little confused that there is no clear definition of this problem.
the other project seems to go with this logic what do you think about that strategy? Would this fits your needs as well?

@nieldw
Copy link
Contributor Author

nieldw commented Dec 4, 2020

date = data['date'] = models.Date(**data)
// ...
entry_date = data['entry_date'] = models.Date(
    day=data.get('entry_day'),
    month=data.get('entry_month'),
    year=str(data['date'].year),
)
// ...
if date > entry_date and (date - entry_date).days >= 330:
    year = 1
elif entry_date > date and (entry_date - date).days >= 330:
    year = -1
else:
    year = 0

As far as I can tell date is the statement date, but we don't have access to that value while processing statement lines.

Secondly, this solution only caters for the December/January case. If the difference is less than 11 months (or, more than one month in the real world) the same year is assumed. For example, if the statement date is in February, and the entry month is December, the result will be that the entry date will be December of the same year, rather than the previous year:

date = 2020-02-29
entry_daymonth = --12-15

Then, entry_date = 2020-12-15

entry_date > date; but (entry_date - date) = 290 days < 330; 

Therefore the same year is selected:
entry_date = 2020-12-15

return of(field, new EarlierMonthImpliesFollowingYearEntryDateResolutionStrategy());
}

public static StatementLine of(GeneralField field, EntryDateResolutionStrategy entryDateResolutionStrategy) throws FieldNotationParseException {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is easier if we just pass the EntryDate year as parameter here.

@qoomon
Copy link
Owner

qoomon commented Dec 5, 2020

I think we should just pass the statement date/year to the StatementLine.of(field, statementDate) method within the MTXXX Parsers, then it's possible to check if statementDate and entryDate are the same.

This way we would have a proper solution and can get rid of multiple strategies, WDYT?

@nieldw
Copy link
Contributor Author

nieldw commented Dec 7, 2020

I think passing in the statement date and looking at the shortest delta between the statement date and the entry date will be the best solution.

Is it okay to change the current behaviour?

@qoomon
Copy link
Owner

qoomon commented Dec 7, 2020

Sounds good for me, cause my implementation is wrong actually :-D.

@nieldw
Copy link
Contributor Author

nieldw commented Dec 7, 2020

This approach will work well for interim statements that explicitly set the statement date, but final statements don't have this field, instead we will have to infer the date from the open/closing balance fields. The opening balance date is probably not what we want, and the closing balance is at the end of the file - after we processed all the statement lines. Any ideas how we can get the closing balance date, or maybe a date from the message header before processing the lines?

@qoomon
Copy link
Owner

qoomon commented Dec 8, 2020

We may can add some transactionList transform logic at line 161 at MT940PageReader to set the right dates.
At this point we already have access to closingBalance.

@qoomon
Copy link
Owner

qoomon commented Dec 14, 2020

WDYT?

@nieldw
Copy link
Contributor Author

nieldw commented Dec 14, 2020

Hi @qoomon , I've been a bit occupied the last few days. Yes, I think that's the only logical way to do it. I've given it some thought. This approach means we will have to do one of two things - either accept an incorrect value during line processing which then get updated after we have a date (this is my preference), or we need to update the data structure to reflect the fact that the data is incomplete. That might have other repercussions, so I'd rather not go down that road.

@qoomon
Copy link
Owner

qoomon commented Dec 14, 2020

I totally agree to your preference.

@nieldw
Copy link
Contributor Author

nieldw commented Jan 8, 2022

Implemented the agreed approach in PR #117

@nieldw nieldw closed this Jan 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants