Skip to content

✨ server: support many cards in the statement#893

Open
nfmelendez wants to merge 1 commit intomainfrom
statement
Open

✨ server: support many cards in the statement#893
nfmelendez wants to merge 1 commit intomainfrom
statement

Conversation

@nfmelendez
Copy link
Copy Markdown
Contributor

@nfmelendez nfmelendez commented Mar 16, 2026

closes #880

Summary by CodeRabbit

  • New Features

    • Statements now support multiple cards, grouping purchases per card and including a separate payments section; exports (PDF/JSON) include per-card identifiers and aggregated totals.
  • UI

    • Redesigned statement layout: account header, period/due dates, summary totals, per-card purchase tables, payments area, and formatted currency/dates.
  • Tests

    • Tests updated to cover multi-card purchases, payments scenarios, and new rendering expectations.

Open with Devin

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 16, 2026

🦋 Changeset detected

Latest commit: c33064d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Reworks statement generation to support multiple cards: Activity API now queries credential cards and nests transactions as purchases per card, extracts payments separately, and the Statement component signature/layout changed to accept account, cards (with purchases), maturity, and payments for PDF/JSON output.

Changes

Cohort / File(s) Summary
Changeset Entry
.changeset/soft-trains-dig.md
Adds a patch changeset for @exactly/server with note: "✨ support multiple cards in statement".
Activity API
server/api/activity.ts
Replaces prior card-centric query with fetching credential cards (id, lastFour) and nested transactions; builds hash→cardId lookup, injects cardId into items, groups purchases by card, and extracts payments for statement assembly (affects PDF/JSON output flow).
Statement Component
server/utils/Statement.tsx
Public API changed from {data,lastFour,maturity} to {account, cards[], maturity, payments[]}; adds currency/date formatting, per-card purchases tables, summary totals (totalSpent, totalPayments, dueBalance), payments table with discount/penalty chips, and significant layout/style updates.
Tests / Fixtures
server/test/api/activity.test.ts, server/test/utils/statement.test.ts
Test fixtures changed to two-card setup; transactions assigned per-card; new test for empty maturity/card case; statement tests updated to validate multi-card rendering, payments, summaries, and now write PDF outputs to runtime path.
Other / Internal
server/...
PDF construction and internal aggregation refactored to consume purchases-by-card and separate payments; removed previous statementCards cardinality checks and statementCurrency usage.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant API as Activity API
    participant DB as Database
    participant Statement as Statement Component
    participant Output as PDF/JSON Output

    Client->>API: Request statement (account, format, maturity)
    API->>DB: Query credential cards (id, lastFour) for account
    DB-->>API: Cards list
    API->>DB: Query transactions/items (filter by hashes/credential)
    DB-->>API: Transactions/items
    API->>API: Attach cardId to items, group purchases by card, extract payments
    API->>Statement: Send payload {account, cards[{id,lastFour,purchases[]}], maturity, payments}
    Statement->>Statement: Compute totals, format dates/currency, render pages
    Statement->>Output: Emit PDF or JSON
    Output-->>Client: Return statement
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • cruzdanilo
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive Unable to assess compliance with issue #880 requirements as the full issue details were not provided; only the issue title 'server: uphold card statement' is available. Provide complete details of issue #880 including all coding requirements and acceptance criteria to validate compliance.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'support many cards in the statement' accurately reflects the primary changes made throughout the codebase to enable multi-card statement support.
Out of Scope Changes check ✅ Passed All changes focus on refactoring activity data loading, statement assembly, and rendering to support multiple cards; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch statement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enables the generation of comprehensive user statements that can include transactions from multiple cards. The changes involve updating the data retrieval process in the API to fetch all relevant card data and refactoring the PDF rendering component to display this multi-card information in a structured and user-friendly format. This enhancement provides users with a more complete overview of their financial activity across all their associated cards.

Highlights

  • Multi-Card Statement Support: The server-side logic and PDF generation for user statements have been updated to support displaying transactions from multiple cards within a single statement.
  • API Refactoring: The activity.ts API endpoint was refactored to correctly query and aggregate transaction data for all cards associated with a credential, removing a previous limitation to a single card for PDF statements.
  • Enhanced PDF Statement Layout: The Statement.tsx component was significantly redesigned to present a clear, organized view of purchases grouped by individual cards, along with a summary of total spending and payments.
  • Comprehensive Testing: API and statement rendering tests were expanded to include scenarios with multiple cards, ensuring the new functionality works as expected.
Changelog
  • .changeset/soft-trains-dig.md
    • Added a new changeset entry for multi-card statement support.
  • server/api/activity.ts
    • Modified the cards query to explicitly select id and lastFour.
    • Refactored the logic for fetching card purchases to support multiple cards and their associated transactions.
    • Updated the PDF generation to process and group purchases by card.
    • Removed the restriction that prevented PDF generation for statements with more than one card.
  • server/test/api/activity.test.ts
    • Added a second card to the test setup.
    • Updated transaction assignments to distribute them across multiple cards for testing.
  • server/test/utils/statement.test.ts
    • Updated existing test cases to match the new statement data structure.
    • Added a new test case to verify rendering of statements with multiple cards.
    • Modified assertions to reflect changes in the rendered PDF text.
  • server/utils/Statement.tsx
    • Updated the Statement component's props to accept account, an array of cards, maturity, and payments.
    • Implemented new rendering logic to display purchases grouped by individual cards.
    • Introduced a summary section for total spent and due balance.
    • Refactored date formatting functions.
    • Updated styling for a more structured and multi-card friendly layout.
Activity
  • The pull request was created by nfmelendez.
  • A new changeset file was added, indicating a patch release for @exactly/server.
  • The core logic for generating activity statements was updated to handle multiple cards.
  • Corresponding test files were modified to reflect and validate the new multi-card statement functionality.
  • The UI component responsible for rendering PDF statements was significantly refactored to display the new multi-card data structure.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

gemini-code-assist[bot]

This comment was marked as resolved.

@sentry
Copy link
Copy Markdown

sentry bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 88.88889% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.76%. Comparing base (c01dd09) to head (c33064d).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
server/api/activity.ts 81.81% 0 Missing and 4 partials ⚠️
server/utils/Statement.tsx 95.65% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #893      +/-   ##
==========================================
+ Coverage   71.69%   71.76%   +0.07%     
==========================================
  Files         228      228              
  Lines        8277     8285       +8     
  Branches     2661     2657       -4     
==========================================
+ Hits         5934     5946      +12     
  Misses       2113     2113              
+ Partials      230      226       -4     
Flag Coverage Δ
e2e 52.31% <0.00%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (2)
server/utils/Statement.tsx (2)

99-111: 🧹 Nitpick | 🔵 Trivial

Duplicate cardTotal calculation; consider extracting.

The same cardTotal reduction appears at lines 100-103 and 125-127. Pre-compute card totals once to avoid duplication and improve maintainability.

♻️ Suggested refactor
+  const cardsWithTotals = cards.map((card) => ({
+    ...card,
+    total: card.purchases.reduce((s, p) => s + p.installments.reduce((a, i) => a + i.amount, 0), 0),
+  }));
+  const totalSpent = cardsWithTotals.reduce((sum, card) => sum + card.total, 0);
-  const totalSpent = cards.reduce(
-    (sum, card) =>
-      sum +
-      card.purchases.reduce((s, p) => s + p.installments.reduce((a, installment) => a + installment.amount, 0), 0),
-    0,
-  );

Then use cardsWithTotals in both the summary and per-card sections, referencing card.total directly.

Also applies to: 124-128


105-105: ⚠️ Potential issue | 🟡 Minor

Consider a more unique React key.

Using card.lastFour as the key could cause issues if two cards share the same last four digits. Since the component doesn't receive a unique card ID, consider using the array index as a fallback:

-<View key={card.lastFour} style={styles.summaryRow}>
+<View key={`${card.lastFour}-${index}`} style={styles.summaryRow}>

Apply similarly at line 130.

Also applies to: 130-130


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 85ea069e-c24d-4dbc-919a-71cb4c2744bf

📥 Commits

Reviewing files that changed from the base of the PR and between cb5448d and ec562a5.

📒 Files selected for processing (5)
  • .changeset/soft-trains-dig.md
  • server/api/activity.ts
  • server/test/api/activity.test.ts
  • server/test/utils/statement.test.ts
  • server/utils/Statement.tsx

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
server/utils/Statement.tsx (1)

99-128: 🧹 Nitpick | 🔵 Trivial

Duplicate cardTotal calculation.

The same calculation appears at lines 100-103 (Summary section) and lines 125-128 (per-card section). Consider computing card totals once during initial data processing.

Additionally, using card.lastFour as the React key (lines 105, 130) could cause issues if two cards share the same last four digits.

♻️ Suggested refactor
+  const cardsWithTotals = cards.map((card) => ({
+    ...card,
+    total: card.purchases.reduce((s, p) => s + p.installments.reduce((a, i) => a + i.amount, 0), 0),
+  }));
+  const totalSpent = cardsWithTotals.reduce((sum, card) => sum + card.total, 0);
-  const totalSpent = cards.reduce(
-    (sum, card) =>
-      sum +
-      card.purchases.reduce((s, p) => s + p.installments.reduce((a, installment) => a + installment.amount, 0), 0),
-    0,
-  );

Then reference cardsWithTotals and card.total directly in both sections.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 17e1f6dc-adbd-449f-9f30-770174c13e19

📥 Commits

Reviewing files that changed from the base of the PR and between ec562a5 and a733910.

📒 Files selected for processing (5)
  • .changeset/soft-trains-dig.md
  • server/api/activity.ts
  • server/test/api/activity.test.ts
  • server/test/utils/statement.test.ts
  • server/utils/Statement.tsx

@cruzdanilo cruzdanilo marked this pull request as ready for review March 18, 2026 17:25
@cruzdanilo cruzdanilo self-requested a review as a code owner March 18, 2026 17:25
sentry[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@nfmelendez nfmelendez force-pushed the statement branch 2 times, most recently from 6842c51 to a0e9a6c Compare March 25, 2026 12:18
sentry[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 tsconfig.json include list doesn't explicitly cover .tsx files

The server tsconfig.json include patterns use **/*.ts (e.g., utils/**/*.ts) which does not glob-match .tsx files. Statement.tsx is the only .tsx file in the server package. It is still type-checked because it's transitively imported from api/activity.ts, but adding utils/**/*.tsx to the include list would make this explicit and prevent the file from being silently excluded if the import chain were to change.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@nfmelendez
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
server/utils/Statement.tsx (1)

101-113: 🧹 Nitpick | 🔵 Trivial

Duplicate cardTotal calculation still present.

This was flagged in a previous review. The same reduction logic appears twice (lines 102-105 and 127-130). Consider computing card totals once during initial processing.

♻️ Optional refactor
+  const cardsWithTotals = cards.map((card) => ({
+    ...card,
+    total: card.purchases.reduce((s, p) => s + p.installments.reduce((a, i) => a + i.amount, 0), 0),
+  }));
-  const totalSpent = cards.reduce(
-    (sum, card) =>
-      sum +
-      card.purchases.reduce((s, p) => s + p.installments.reduce((a, installment) => a + installment.amount, 0), 0),
-    0,
-  );
+  const totalSpent = cardsWithTotals.reduce((sum, card) => sum + card.total, 0);

Then use cardsWithTotals and card.total in both the summary and per-card sections.

Also applies to: 126-130


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ad2f03be-c2dd-47f2-929d-8c5c4d3bc5fd

📥 Commits

Reviewing files that changed from the base of the PR and between ec562a5 and c33064d.

📒 Files selected for processing (5)
  • .changeset/soft-trains-dig.md
  • server/api/activity.ts
  • server/test/api/activity.test.ts
  • server/test/utils/statement.test.ts
  • server/utils/Statement.tsx

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

server: uphold card statement

1 participant