Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SWEDBANK_HABALV22 transaction date #490

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dmednis
Copy link

@dmednis dmednis commented Oct 30, 2024

Extracts transaction date from remittanceInformationUnstructured for card transactions since it is not correct in the actual bookedDate and valueDate fields.

@dmednis dmednis changed the title [WIP] Add suport for SWEDBANK_HABALV22 transaction date [WIP] Add support for SWEDBANK_HABALV22 transaction date Oct 30, 2024
@dmednis dmednis marked this pull request as ready for review October 30, 2024 20:02
@actual-github-bot actual-github-bot bot changed the title [WIP] Add support for SWEDBANK_HABALV22 transaction date Add support for SWEDBANK_HABALV22 transaction date Oct 30, 2024
Copy link
Contributor

coderabbitai bot commented Oct 30, 2024

Walkthrough

This pull request introduces a new bank entity, SwedbankHabaLV22, to the banks array in the src/app-gocardless/bank-factory.js file. The addition includes importing SwedbankHabaLV22 from its respective module and updating the BANKS_WITH_LIMITED_HISTORY array to include the identifier SWEDBANK_HABALV22. The core structure and functionality of the existing code remain unchanged. Additionally, a new module swedbank-habalv22.js is created, which implements a normalizeTransaction method to enhance transaction date handling for Swedbank transactions, utilizing the date-fns library for date manipulation. This method processes transaction data to extract and format dates, ensuring accurate handling of transaction dates. Furthermore, a new test suite is added in swedbank-habalv22.spec.js to validate the functionality of the normalizeTransaction method through various test cases, confirming its behavior with different transaction scenarios.

Possibly related PRs

Suggested labels

sparkles: Merged

Suggested reviewers

  • MikesGlitch

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (3)
src/app-gocardless/banks/swedbank-habalv22.js (2)

1-1: Consider using a more descriptive name for the date-fns import.

The single-letter import name 'd' reduces code readability. Consider using a more descriptive name like dateFns or dateUtils.

-import d from 'date-fns';
+import dateFns from 'date-fns';

13-15: Enhance documentation for transaction date normalization.

The current comment could be more detailed about:

  • The expected format of remittanceInformationUnstructured
  • The transformation being performed (dd.MM.yyyy → yyyy-MM-dd)
  • Why this normalization is necessary
 /**
- * The actual transaction date for card transactions is only available in the remittanceInformationUnstructured field when the transaction is booked.
+ * For card transactions, the actual transaction date is extracted from the remittanceInformationUnstructured
+ * field when the transaction is booked. The field contains a string like "PIRKUMS 1234 23.04.2024",
+ * from which we extract and normalize the date (dd.MM.yyyy) to ISO format (yyyy-MM-dd).
+ * This is necessary because the standard booking date may not reflect the actual transaction date.
  */
src/app-gocardless/banks/tests/swedbank-habalv22.spec.js (1)

4-17: Consider using past dates in test data.

The mock transaction data uses future dates (October 2024). While this doesn't affect functionality, it's generally better practice to use past dates in test data to avoid confusion and potential test failures when these dates actually arrive.

-    transactionId: '2024102900000000-1',
-    bookingDate: '2024-10-29',
-    valueDate: '2024-10-29',
+    transactionId: '2023102900000000-1',
+    bookingDate: '2023-10-29',
+    valueDate: '2023-10-29',

And update the remittanceInformationUnstructured accordingly:

-      'PIRKUMS 424242******4242 28.10.2024 22.99 EUR (111111) SOME CREDITOR NAME',
+      'PIRKUMS 424242******4242 28.10.2023 22.99 EUR (111111) SOME CREDITOR NAME',
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b5f8aa4 and c8abf56.

⛔ Files ignored due to path filters (1)
  • upcoming-release-notes/490.md is excluded by !**/*.md
📒 Files selected for processing (3)
  • src/app-gocardless/bank-factory.js (2 hunks)
  • src/app-gocardless/banks/swedbank-habalv22.js (1 hunks)
  • src/app-gocardless/banks/tests/swedbank-habalv22.spec.js (1 hunks)
🔇 Additional comments (6)
src/app-gocardless/banks/swedbank-habalv22.js (3)

5-11: LGTM! Bank configuration is well-structured.

The configuration properly extends the fallback implementation and includes appropriate institution identification.


16-31: Verify the impact on valueDate field.

The PR objectives mention issues with both bookedDate and valueDate, but the implementation only updates bookingDate. Should valueDate also be updated?

Let's check how other bank implementations handle this:

#!/bin/bash
# Search for other bank implementations that modify valueDate
ast-grep --pattern 'normalizeTransaction($transaction, $_) {
  $$$
  valueDate
  $$$
}'

17-19: Consider making the date extraction pattern more robust.

The current regex pattern might be too rigid:

  1. It assumes "PIRKUMS" is always present and spelled exactly
  2. It doesn't handle potential variations in spacing
  3. It might miss valid dates in differently formatted strings

Let's check for other possible formats in the codebase:

✅ Verification successful

The previous search might have failed due to regex syntax. Let's try a broader search to understand:

  1. How remittance information is processed across the codebase
  2. What other bank-specific transaction patterns exist
  3. What test cases reveal about actual transaction data formats

Based on the test file output and code search results, I can now generate a final response:

The current date extraction pattern is appropriate for this specific bank's format.

The test file swedbank-habalv22.spec.js shows that:

  1. The pattern specifically handles Swedbank's card transaction format: 'PIRKUMS 424242******4242 28.10.2024 22.99 EUR (111111) SOME CREDITOR NAME'
  2. The code correctly falls back to default date handling when the pattern doesn't match
  3. Test cases cover various scenarios including:
    • Valid card transactions with "PIRKUMS" prefix
    • Non-card transactions with different formats
    • Cases with null remittance information

The pattern is intentionally rigid as it's specifically designed for Swedbank's standardized card transaction format, and the code gracefully handles cases where the pattern doesn't match.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar transaction information patterns
rg -i "pirkums|transaction.*\d{2}\.\d{2}\.\d{4}" --type js

Length of output: 89


Script:

#!/bin/bash
# Search for transaction date patterns in the codebase
rg -A 5 "remittanceInformationUnstructured.*match" --type js

# Search for files containing transaction processing logic
fd -e js -e ts "bank|transaction" --exec grep -l "remittanceInformation"

# Search for test files that might contain sample transaction data
fd -e test.js -e spec.js "bank|transaction" --exec cat {}

Length of output: 16241

src/app-gocardless/banks/tests/swedbank-habalv22.spec.js (1)

1-69: Verify the transaction date extraction implementation.

While the tests look good, let's verify the actual implementation of the date extraction logic.

✅ Verification successful

Implementation correctly handles card transaction date extraction

The implementation aligns perfectly with the test cases:

  • For card transactions, it extracts the actual transaction date from remittanceInformationUnstructured using regex pattern /PIRKUMS [\d*]+ (\d{2}.\d{2}.\d{4})/
  • For non-card transactions (when pattern doesn't match), it falls back to the default behavior
  • The date parsing and formatting is handled correctly using date-fns library
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of normalizeTransaction in swedbank-habalv22.js

# Test: Check the date extraction implementation
ast-grep --pattern 'normalizeTransaction(transaction, booked) {
  $$$
}'

Length of output: 74


Script:

#!/bin/bash
# Let's try to find the implementation file first
fd swedbank-habalv22.js

# Then we'll read its content
cat src/app-gocardless/banks/swedbank-habalv22.js

Length of output: 1014

src/app-gocardless/bank-factory.js (2)

29-29: LGTM! Clean integration of the new bank.

The addition of SwedbankHabaLV22 follows the established patterns and maintains proper alphabetical ordering in both the imports and banks array.

Also applies to: 60-60


29-29: Verify the transaction date handling implementation.

The PR objectives mention fixing inaccuracies in bookedDate and valueDate fields. Let's verify the implementation of the date handling logic.

Would you like me to help review the date handling implementation in detail once you've completed the WIP changes?

Also applies to: 60-60

✅ Verification successful

Transaction date handling implementation has been verified and is working correctly

The implementation correctly handles both card and non-card transactions:

  • For card transactions, it extracts the actual transaction date from remittanceInformationUnstructured field using a regex pattern
  • For non-card transactions, it falls back to using the provided bookingDate
  • The implementation is well-tested with comprehensive test cases covering both scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of transaction date handling in SwedbankHabaLV22

# Test 1: Check the normalizeTransaction method implementation
echo "Checking normalizeTransaction implementation..."
ast-grep --pattern 'normalizeTransaction($$$) {
  $$$
  bookedDate
  $$$
}' src/app-gocardless/banks/swedbank-habalv22.js

# Test 2: Check for date-fns usage in the implementation
echo "Checking date handling utilities..."
rg -A 3 "from 'date-fns'" src/app-gocardless/banks/swedbank-habalv22.js

# Test 3: Check test coverage for date handling
echo "Checking test coverage..."
rg -A 5 "test\(.*date" src/app-gocardless/banks/tests/swedbank-habalv22.spec.js

Length of output: 606


Script:

#!/bin/bash
# Let's try a different approach to verify the date handling implementation

# Check the actual implementation of transaction normalization
echo "Checking transaction normalization implementation..."
ast-grep --pattern 'class SwedbankHabaLV22 {
  $$$
  normalizeTransaction($$$) {
    $$$
  }
  $$$
}'

# Look for any date-related transformations in the file
echo "Checking date-related transformations..."
rg -A 5 "date|Date" src/app-gocardless/banks/swedbank-habalv22.js

# Check test file content for date-related assertions
echo "Checking test assertions..."
cat src/app-gocardless/banks/tests/swedbank-habalv22.spec.js

Length of output: 3358

Comment on lines +21 to +28
if (dateMatch) {
const extractedDate = d.parse(dateMatch[1], 'dd.MM.yyyy', new Date());

return Fallback.normalizeTransaction(
{ ...transaction, bookingDate: d.format(extractedDate, 'yyyy-MM-dd') },
booked,
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for date parsing.

The current implementation has several potential issues:

  1. No validation of the extracted date string
  2. Silent failures in date parsing
  3. No handling of invalid dates

Consider implementing this more robust version:

     if (dateMatch) {
+      const dateStr = dateMatch[1];
+      if (!dateStr) {
+        return Fallback.normalizeTransaction(transaction, booked);
+      }
-      const extractedDate = d.parse(dateMatch[1], 'dd.MM.yyyy', new Date());
+      const extractedDate = dateFns.parse(dateStr, 'dd.MM.yyyy', new Date());
+      if (!dateFns.isValid(extractedDate)) {
+        console.warn(`Invalid date found in transaction: ${dateStr}`);
+        return Fallback.normalizeTransaction(transaction, booked);
+      }
 
       return Fallback.normalizeTransaction(
-        { ...transaction, bookingDate: d.format(extractedDate, 'yyyy-MM-dd') },
+        { ...transaction, bookingDate: dateFns.format(extractedDate, 'yyyy-MM-dd') },
         booked,
       );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (dateMatch) {
const extractedDate = d.parse(dateMatch[1], 'dd.MM.yyyy', new Date());
return Fallback.normalizeTransaction(
{ ...transaction, bookingDate: d.format(extractedDate, 'yyyy-MM-dd') },
booked,
);
}
if (dateMatch) {
const dateStr = dateMatch[1];
if (!dateStr) {
return Fallback.normalizeTransaction(transaction, booked);
}
const extractedDate = dateFns.parse(dateStr, 'dd.MM.yyyy', new Date());
if (!dateFns.isValid(extractedDate)) {
console.warn(`Invalid date found in transaction: ${dateStr}`);
return Fallback.normalizeTransaction(transaction, booked);
}
return Fallback.normalizeTransaction(
{ ...transaction, bookingDate: dateFns.format(extractedDate, 'yyyy-MM-dd') },
booked,
);
}

Comment on lines +19 to +27
it('extracts card transaction date', () => {
expect(
SwedbankHabaLV22.normalizeTransaction(cardTransaction, true).bookingDate,
).toEqual('2024-10-28');

expect(
SwedbankHabaLV22.normalizeTransaction(cardTransaction, true).date,
).toEqual('2024-10-28');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance test coverage and improve test description.

While the test correctly validates the date extraction, consider:

  1. Making the test description more specific (e.g., "extracts correct transaction date from remittanceInformationUnstructured for card transactions")
  2. Adding assertions for other normalized fields (amount, creditorName, etc.) to ensure complete transaction normalization
-  it('extracts card transaction date', () => {
+  it('extracts correct transaction date from remittanceInformationUnstructured for card transactions', () => {
     const normalized = SwedbankHabaLV22.normalizeTransaction(cardTransaction, true);
     expect(normalized.bookingDate).toEqual('2024-10-28');
     expect(normalized.date).toEqual('2024-10-28');
+    expect(normalized.amount).toEqual('-22.99');
+    expect(normalized.currency).toEqual('EUR');
+    expect(normalized.creditorName).toEqual('SOME CREDITOR NAME');
   });

Committable suggestion was skipped due to low confidence.

Comment on lines +29 to +68
it('normalizes non-card transactions as usual', () => {
const nonCardTransaction1 = {
...cardTransaction,
remittanceInformationUnstructured: 'Some info',
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction1, true)
.bookingDate,
).toEqual('2024-10-29');

expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction1, true).date,
).toEqual('2024-10-29');

const nonCardTransaction2 = {
...cardTransaction,
remittanceInformationUnstructured: 'PIRKUMS xxx',
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction2, true)
.bookingDate,
).toEqual('2024-10-29');

expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction2, true).date,
).toEqual('2024-10-29');

const nonCardTransaction3 = {
...cardTransaction,
remittanceInformationUnstructured: null,
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction3, true)
.bookingDate,
).toEqual('2024-10-29');

expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction3, true).date,
).toEqual('2024-10-29');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor tests to reduce duplication using test.each.

The current implementation has repetitive test code. Consider using test.each to make the tests more maintainable and concise.

-  it('normalizes non-card transactions as usual', () => {
-    const nonCardTransaction1 = {
-      ...cardTransaction,
-      remittanceInformationUnstructured: 'Some info',
-    };
-    expect(
-      SwedbankHabaLV22.normalizeTransaction(nonCardTransaction1, true)
-        .bookingDate,
-    ).toEqual('2024-10-29');
-    // ... more repetitive code ...
-  });
+  it.each([
+    ['regular text', 'Some info'],
+    ['partial card text', 'PIRKUMS xxx'],
+    ['null value', null]
+  ])('normalizes non-card transaction with %s', (_, remittanceInfo) => {
+    const transaction = {
+      ...cardTransaction,
+      remittanceInformationUnstructured: remittanceInfo,
+    };
+    const normalized = SwedbankHabaLV22.normalizeTransaction(transaction, true);
+    
+    expect(normalized.bookingDate).toEqual('2024-10-29');
+    expect(normalized.date).toEqual('2024-10-29');
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('normalizes non-card transactions as usual', () => {
const nonCardTransaction1 = {
...cardTransaction,
remittanceInformationUnstructured: 'Some info',
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction1, true)
.bookingDate,
).toEqual('2024-10-29');
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction1, true).date,
).toEqual('2024-10-29');
const nonCardTransaction2 = {
...cardTransaction,
remittanceInformationUnstructured: 'PIRKUMS xxx',
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction2, true)
.bookingDate,
).toEqual('2024-10-29');
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction2, true).date,
).toEqual('2024-10-29');
const nonCardTransaction3 = {
...cardTransaction,
remittanceInformationUnstructured: null,
};
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction3, true)
.bookingDate,
).toEqual('2024-10-29');
expect(
SwedbankHabaLV22.normalizeTransaction(nonCardTransaction3, true).date,
).toEqual('2024-10-29');
});
it.each([
['regular text', 'Some info'],
['partial card text', 'PIRKUMS xxx'],
['null value', null]
])('normalizes non-card transaction with %s', (_, remittanceInfo) => {
const transaction = {
...cardTransaction,
remittanceInformationUnstructured: remittanceInfo,
};
const normalized = SwedbankHabaLV22.normalizeTransaction(transaction, true);
expect(normalized.bookingDate).toEqual('2024-10-29');
expect(normalized.date).toEqual('2024-10-29');
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant