Skip to content

Conversation

jcortes
Copy link
Collaborator

@jcortes jcortes commented Sep 5, 2025

WHY

Resolves #18190

Summary by CodeRabbit

  • New Features
    • Added “Create Report” action to generate reports with expenses and optional custom fields.
    • Added in-app method to fetch selectable Policy ID options filtered by employee email.
  • Enhancements
    • Improved parsing for JSON arrays/objects for expenses and report fields.
    • More robust request handling with clearer error feedback.
    • Standardized Employee Email selection across actions for a consistent setup.
  • Chores
    • Bumped action versions and Expensify package to 0.1.0.

@jcortes jcortes self-assigned this Sep 5, 2025
Copy link

vercel bot commented Sep 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
pipedream-docs Ignored Ignored Sep 5, 2025 10:09pm
pipedream-docs-redirect-do-not-edit Ignored Ignored Sep 5, 2025 10:09pm

Copy link
Contributor

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds a new Expensify "Create Report" action and supporting utilities; extends the Expensify app with propDefinitions, getPolicyList and createReport methods, refactors request handling, adds JSON/array parsing helpers, and updates several action versions and package version.

Changes

Cohort / File(s) Summary
New action: Create Report
components/expensify/actions/create-report/create-report.ts
Adds expensify-create-report action (v0.0.1). Parses reportFields and expenses, builds payload, calls app.createReport, sets a success summary and returns API response.
App: propDefinitions + API helpers
components/expensify/app/expensify.app.ts
Adds propDefinitions.employeeEmail and propDefinitions.policyId (async options), refactors _makeRequest to merge extra form data and error on non-2xx, and adds public createReport and getPolicyList methods.
Common utilities
components/expensify/common/utils.ts
New default-exported helpers parseJson and parseArray to safely parse nested JSON/arrays with depth and cycle protection.
PropDefinition refactor (existing action)
components/expensify/actions/create-expense/create-expense.ts
Bumps action version to 0.0.3 and replaces inline employeeEmail prop with propDefinition: [expensify, "employeeEmail"]; runtime behavior unchanged.
Version bumps / package
components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts, components/expensify/package.json
Updates export-report action version to 0.0.3 and package version to 0.1.0. No functional changes to logic.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Action as Create Report Action
  participant Utils as common/utils
  participant App as Expensify App
  participant API as Expensify Integration Server

  User->>Action: provide employeeEmail, policyId, reportTitle, reportFields?, expenses[]
  Action->>Utils: parseJson(reportFields) and parseArray(expenses)
  Utils-->>Action: parsed fields & expenses
  Action->>App: createReport({ employeeEmail, policyID, report:{ title, fields? }, expenses })
  App->>API: _makeRequest(job submit with inputSettings.type="report", data)
  API-->>App: response (reportID, reportName, ...)
  App-->>Action: response
  Action-->>User: summary + response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Implement Expensify create_report action with API per docs, returning created report (#18190)
Include inputs: employeeEmail, policyID, report.title, optional report.fields, expenses array (#18190)
Ensure inputSettings.type is "report" when submitting job (#18190)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
PropDefinition refactor and version bump in create-expense (components/expensify/actions/create-expense/create-expense.ts) Not required by #18190; unrelated prop metadata refactor and version increment.
Version bump in export-report-to-pdf (components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts) Version metadata change unrelated to create_report objective.
Package version bump (components/expensify/package.json) Repository/package version update is not part of the create_report feature requirements.

Poem

I hop, I parse, I stitch each field,
A carrot-coded JSON yield;
Reports assembled, policies found,
I thump with joy—requests unbound.
Cheers, little rabbit, code deployed—🥕✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d1efda3 and 89d2d1d.

📒 Files selected for processing (6)
  • components/expensify/actions/create-expense/create-expense.ts (1 hunks)
  • components/expensify/actions/create-report/create-report.ts (1 hunks)
  • components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts (1 hunks)
  • components/expensify/app/expensify.app.ts (3 hunks)
  • components/expensify/common/utils.ts (1 hunks)
  • components/expensify/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/expensify/actions/create-report/create-report.ts
  • components/expensify/app/expensify.app.ts
  • components/expensify/common/utils.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (4)
components/expensify/package.json (1)

3-3: Semver bump looks right.

Minor version bump to 0.1.0 aligns with adding a new action and app API changes.

components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts (1)

7-7: Version bump only — OK.

components/expensify/actions/create-expense/create-expense.ts (2)

6-6: Version bump — OK.


13-16: Good move to shared propDefinition.

Reusing expensify’s employeeEmail prop centralizes metadata and options.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch expensify-create-report-action

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/expensify/actions/create-expense/create-expense.ts (1)

46-67: Await the API call; current code returns a Promise and accesses its properties.

This will break the summary and condition check.

-    const response = this.expensify.createExpense({
+    const response = await this.expensify.createExpense({
       $,
       data: {
         employeeEmail: this.employeeEmail,
         transactionList: [
           {
             created: this.created,
             comment: this.comment,
             currency: this.currency,
             amount: this.amount,
             merchant: this.merchant,
           },
         ],
       },
     });
🧹 Nitpick comments (6)
components/expensify/app/expensify.app.ts (3)

8-30: Confirm propDefinition wiring for policyId options.

The options function expects a userEmail. Ensure actions pass it via propDefinition mapping, e.g.:

- policyId: {
+ policyId: {
   // ...
   async options({ userEmail }) {
     const { policyList } = await this.getPolicyList({
       userEmail,
     });
     // ...
   },
 }

And in the action using it:

policyId: {
  propDefinition: [
    expensify,
    "policyId",
    ({ employeeEmail }) => ({ userEmail: employeeEmail }),
  ],
}

Can you confirm the create-report action supplies userEmail like above so the policy dropdown populates correctly?


62-66: Avoid responseCode check for non-JSON responses.

downloadFile (arraybuffer) and file-name responses (string) won’t have responseCode; current check silently no-ops but is confusing. Guard the check.

-      if (response.responseCode < 200 || response.responseCode >= 300) {
-        throw new Error(JSON.stringify(response, null, 2));
-      }
+      if (response && typeof response === "object" && "responseCode" in response) {
+        const { responseCode } = response as { responseCode: number };
+        if (responseCode < 200 || responseCode >= 300) {
+          throw new Error(JSON.stringify(response, null, 2));
+        }
+      }

96-110: Fix linter warning and improve readability.

Expand the conditional spread across lines.

-            ...(userEmail && { userEmail }),
+            ...(userEmail && {
+              userEmail,
+            }),
components/expensify/actions/create-report/create-report.ts (3)

97-103: Make JSON parsing resilient to both object and string inputs; parse expenses once.

Avoid double-parsing or runtime errors if reportFields arrives as an object and ensure expenses are parsed once and validated.

Apply:

   async run({ $ }) {
     const {
       policyId,
       employeeEmail,
       reportTitle,
       reportFields,
       expenses,
     } = this;

+    // Parse inputs safely
+    const parsedReportFields = typeof reportFields === "string"
+      ? utils.parseJson(reportFields)
+      : reportFields;
+    const parsedExpenses = utils.parseArray(expenses);
+    if (!Array.isArray(parsedExpenses) || parsedExpenses.length === 0) {
+      throw new Error("At least one expense is required.");
+    }
 
     const response = await this.app.createReport({
       $,
       data: {
         employeeEmail,
         policyID: policyId,
         report: {
           title: reportTitle,
-          ...(reportFields && {
-            fields: utils.parseJson(reportFields),
+          ...(parsedReportFields && {
+            fields: parsedReportFields,
           }),
         },
-        expenses: utils.parseArray(expenses),
+        expenses: parsedExpenses,
       },
     });

Also applies to: 82-90


34-61: Align the “Expenses” prop doc with the prop type (string[])

Doc shows a full JSON array, but the prop is string[] (one item per expense). Update the example to a single expense JSON object to reduce confusion.

Apply:

-**Example:**
-```json
-[
-  {
-    "date": "2024-01-15",
-    "currency": "USD", 
-    "merchant": "Hotel ABC",
-    "amount": 15000
-  },
-  {
-    "date": "2024-01-16",
-    "currency": "USD",
-    "merchant": "Restaurant XYZ", 
-    "amount": 5000
-  }
-]
-```
+Note: Add one expense per list item.
+**Example (one item):**
+```json
+{
+  "date": "2024-01-15",
+  "currency": "USD",
+  "merchant": "Hotel ABC",
+  "amount": 15000
+}
+```

39-43: Minor doc polish: use ISO-8601 date and clarify amount units

Tighten phrasing to prevent user error.

Apply:

-- `date`: The date the expense was made (format yyyy-mm-dd)
+- `date`: The date the expense was made (ISO 8601, YYYY-MM-DD)
 - `currency`: Three-letter currency code (e.g., "USD", "EUR", "CAD")
 - `merchant`: The name of the merchant
-- `amount`: The amount in cents (e.g., 2500 for $25.00)
+- `amount`: Integer amount in cents (e.g., 2500 for $25.00)

Also applies to: 67-69

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a08f3ca and d1efda3.

📒 Files selected for processing (6)
  • components/expensify/actions/create-expense/create-expense.ts (1 hunks)
  • components/expensify/actions/create-report/create-report.ts (1 hunks)
  • components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts (1 hunks)
  • components/expensify/app/expensify.app.ts (3 hunks)
  • components/expensify/common/utils.ts (1 hunks)
  • components/expensify/package.json (1 hunks)
🧰 Additional context used
🪛 GitHub Check: Lint Code Base
components/expensify/common/utils.ts

[failure] 16-16:
'e' is defined but never used

components/expensify/app/expensify.app.ts

[failure] 106-106:
Expected a line break before this closing brace


[failure] 106-106:
Expected a line break after this opening brace

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (5)
components/expensify/package.json (1)

3-3: Semver bump looks good.

Minor version bump aligns with adding a new action. No further changes needed here.

components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts (1)

7-7: Version bump acknowledged.

Action metadata updated to 0.0.3. No logic changes in this PR segment.

components/expensify/actions/create-report/create-report.ts (3)

20-28: Ensure policyId options refresh after selecting employeeEmail

Dynamic dependency looks correct; confirm the UI updates options when employeeEmail changes.

You can quickly validate by opening the action in the UI and switching emails, or by checking the propDefinition for policyId in expensify.app.ts to ensure it consumes the userEmail param.


5-11: Overall: solid action structure and prop wiring

Good use of propDefinitions, clear descriptions, and clean payload assembly. Once the small parsing/docs tweaks are in, this looks ready.


106-108: Keep original $summary export: Expensify createReport always returns top-level reportName and reportID. (integrations.expensify.com)

Copy link
Collaborator

@luancazarine luancazarine left a comment

Choose a reason for hiding this comment

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

Hi @jcortes, LGTM! Ready for QA!

@vunguyenhung vunguyenhung merged commit 24c0cbe into master Sep 9, 2025
10 checks passed
@vunguyenhung vunguyenhung deleted the expensify-create-report-action branch September 9, 2025 01:59
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.

[ACTION] Expensify | Create Report

3 participants