Skip to content

Commit 194d1ef

Browse files
authored
Expensify - export report (PipedreamHQ#18320)
* new component * versions * updates * updates * updates * updates
1 parent d1c1f7a commit 194d1ef

File tree

6 files changed

+279
-7
lines changed

6 files changed

+279
-7
lines changed

components/expensify/actions/create-expense/create-expense.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import expensify from "../../app/expensify.app";
33

44
export default defineAction({
55
key: "expensify-create-expense",
6-
version: "0.0.3",
6+
version: "0.0.4",
77
name: "Create Expense",
88
description: "Creates a new expense. [See docs here](https://integrations.expensify.com/Integration-Server/doc/#expense-creator)",
99
type: "action",

components/expensify/actions/create-report/create-report.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import utils from "../../common/utils";
44

55
export default defineAction({
66
key: "expensify-create-report",
7-
version: "0.0.1",
7+
version: "0.0.2",
88
name: "Create Report",
99
description: "Creates a new report with transactions in a user's account. [See docs here](https://integrations.expensify.com/Integration-Server/doc/#report-creator)",
1010
type: "action",

components/expensify/actions/export-report-to-pdf/export-report-to-pdf.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import fs from "fs";
44

55
export default defineAction({
66
key: "expensify-export-report-to-pdf",
7-
version: "0.0.3",
7+
version: "0.0.4",
88
name: "Export Report To PDF",
99
description: "Export a report to PDF. [See docs here](https://integrations.expensify.com/Integration-Server/doc/#report-exporter)",
1010
type: "action",
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import { defineAction } from "@pipedream/types";
2+
import expensify from "../../app/expensify.app";
3+
import fs from "fs";
4+
import {
5+
axios, ConfigurationError,
6+
} from "@pipedream/platform";
7+
import qs from "qs";
8+
9+
export default defineAction({
10+
key: "expensify-export-report",
11+
name: "Export Report",
12+
description: "Export Expensify reports to a file (csv, xls, xlsx, txt, pdf, json, xml). [See the documentation](https://integrations.expensify.com/Integration-Server/doc/#report-exporter)",
13+
version: "0.0.1",
14+
type: "action",
15+
props: {
16+
expensify,
17+
reportIds: {
18+
type: "string[]",
19+
label: "Report IDs",
20+
description: "The IDs of the reports to be exported. Required if `startDate` or `approvedAfter` are not specified.",
21+
optional: true,
22+
},
23+
startDate: {
24+
type: "string",
25+
label: "Start Date",
26+
description: "The start date of the report. Format: YYYY-MM-DD. Required if `reportIds` or `approvedAfter ` are not specified.",
27+
optional: true,
28+
},
29+
endDate: {
30+
type: "string",
31+
label: "End Date",
32+
description: "The end date of the report. Format: YYYY-MM-DD. Conditionally required, if either `startDate` or `approvedAfter` is more than one year ago.",
33+
optional: true,
34+
},
35+
approvedAfter: {
36+
type: "string",
37+
label: "Approved After",
38+
description: "Filters out all reports approved before the given date, whichever occurred last (inclusive). Required if `reportIds` or `startDate` are not specified",
39+
optional: true,
40+
},
41+
fileExtension: {
42+
type: "string",
43+
label: "File Extension",
44+
description: "Specifies the format of the generated report",
45+
options: [
46+
"csv",
47+
"xls",
48+
"xlsx",
49+
"txt",
50+
"pdf",
51+
"json",
52+
"xml",
53+
],
54+
},
55+
markedAsExported: {
56+
type: "string",
57+
label: "Marked as Exported Label (Filter)",
58+
description: "Filters out reports that have already been exported with that label",
59+
optional: true,
60+
},
61+
reportStates: {
62+
type: "string[]",
63+
label: "Report States",
64+
description: "Only the reports matching the specified status(es) will be exported",
65+
options: [
66+
"OPEN",
67+
"SUBMITTED",
68+
"APPROVED",
69+
"REIMBURSED",
70+
"ARCHIVED",
71+
],
72+
optional: true,
73+
},
74+
employeeEmail: {
75+
type: "string",
76+
label: "Employee Email",
77+
description: "Export reports for the specified employee email",
78+
optional: true,
79+
},
80+
policyIds: {
81+
propDefinition: [
82+
expensify,
83+
"policyExportIds",
84+
],
85+
},
86+
fileBaseName: {
87+
type: "string",
88+
label: "File Base Name",
89+
description: "The base name of the file to be exported",
90+
optional: true,
91+
},
92+
includeFullPageReceiptsPdf: {
93+
type: "boolean",
94+
label: "Include Full Page Receipts PDF",
95+
description: "Specifies whether generated PDFs should include full page receipts. This parameter is used only if fileExtension contains pdf.",
96+
optional: true,
97+
},
98+
emailRecipients: {
99+
type: "string[]",
100+
label: "Email Recipients",
101+
description: "People to email at the end of the export",
102+
optional: true,
103+
},
104+
markAsExported: {
105+
type: "string",
106+
label: "Mark as Exported",
107+
description: "Mark the reports as exported with the given label",
108+
optional: true,
109+
},
110+
templatePath: {
111+
type: "string",
112+
label: "Template Path",
113+
description: "The path in the /tmp directory to the template to use for the export. Required if `fileExtension` is `csv`, `txt`, `json`, or `xml`.",
114+
optional: true,
115+
},
116+
limit: {
117+
type: "string",
118+
label: "Limit",
119+
description: "Maximum number of reports to export",
120+
optional: true,
121+
},
122+
test: {
123+
type: "boolean",
124+
label: "Test Mode",
125+
description: "If set to true, actions defined in `onFinish` (i.e. email, markAsExported) will not be executed",
126+
optional: true,
127+
},
128+
syncDir: {
129+
type: "dir",
130+
accessMode: "write",
131+
sync: true,
132+
},
133+
},
134+
async run({ $ }) {
135+
if (!this.reportIds && !this.startDate && !this.approvedAfter) {
136+
throw new ConfigurationError("At least one of `reportIds`, `startDate`, or `approvedAfter` must be specified");
137+
}
138+
139+
if ([
140+
"csv",
141+
"txt",
142+
"json",
143+
"xml",
144+
].includes(this.fileExtension) && !this.templatePath) {
145+
throw new ConfigurationError(`Template path is required for file extension: ${this.fileExtension}`);
146+
}
147+
148+
const onFinish = [];
149+
if (this.emailRecipients) {
150+
onFinish.push({
151+
actionName: "email",
152+
recipients: this.emailRecipients.join(","),
153+
});
154+
}
155+
156+
if (this.markAsExported) {
157+
onFinish.push({
158+
actionName: "markAsExported",
159+
label: this.markAsExported,
160+
});
161+
}
162+
163+
const data = {
164+
type: "file",
165+
credentials: {
166+
partnerUserID: this.expensify._partnerUserId(),
167+
partnerUserSecret: this.expensify._partnerUserSecret(),
168+
},
169+
onReceive: {
170+
immediateResponse: [
171+
"returnRandomFileName",
172+
],
173+
},
174+
inputSettings: {
175+
type: "combinedReportData",
176+
filters: {
177+
reportIDList: this.reportIds
178+
? this.reportIds.join(",")
179+
: undefined,
180+
startDate: this.startDate,
181+
endDate: this.endDate,
182+
approvedAfter: this.approvedAfter,
183+
markedAsExported: this.markedAsExported,
184+
policyIDList: this.policyIds
185+
? this.policyIds.join(",")
186+
: undefined,
187+
},
188+
reportState: this.reportStates
189+
? this.reportStates.join(",")
190+
: undefined,
191+
employeeEmail: this.employeeEmail,
192+
limit: this.limit,
193+
},
194+
outputSettings: {
195+
fileExtension: this.fileExtension,
196+
fileBasename: this.fileBaseName,
197+
includeFullPageReceiptsPdf: this.includeFullPageReceiptsPdf,
198+
},
199+
onFinish,
200+
test: this.test,
201+
};
202+
203+
let fileName;
204+
const args = {
205+
method: "post",
206+
url: `${this.expensify._apiUrl()}`,
207+
};
208+
209+
if (!this.templatePath) {
210+
fileName = await axios($, {
211+
...args,
212+
data: qs.stringify({
213+
requestJobDescription: JSON.stringify(data),
214+
template: "default",
215+
}),
216+
});
217+
} else {
218+
fileName = await axios($, {
219+
...args,
220+
data: qs.stringify({
221+
requestJobDescription: JSON.stringify(data),
222+
template: fs.readFileSync(this.templatePath.includes("tmp/")
223+
? this.templatePath
224+
: `/tmp/${this.templatePath}`, "utf8"),
225+
}),
226+
headers: {
227+
"Content-Type": "application/x-www-form-urlencoded",
228+
},
229+
});
230+
}
231+
232+
const fileBuffer = await this.expensify.downloadFile({
233+
$,
234+
fileName,
235+
});
236+
237+
const path = `/tmp/${fileName}`;
238+
239+
await fs.writeFileSync(path, fileBuffer);
240+
241+
if (fileBuffer) {
242+
$.export("$summary", `Successfully exported report in ${path}`);
243+
}
244+
245+
return path;
246+
},
247+
});

components/expensify/app/expensify.app.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,30 @@ export default defineApp({
66
type: "app",
77
app: "expensify",
88
propDefinitions: {
9+
policyExportIds: {
10+
type: "string[]",
11+
label: "Policy IDs",
12+
description: "The IDs of the policies to export",
13+
optional: true,
14+
async options() {
15+
const { policyList } = await this.listPolicies();
16+
return policyList?.map(({
17+
id, name,
18+
}) => ({
19+
label: name,
20+
value: id,
21+
})) || [];
22+
},
23+
},
924
employeeEmail: {
1025
type: "string",
1126
label: "Employee Email",
12-
description: "The expenses will be created in this account.",
27+
description: "The expenses will be created in this account",
1328
},
1429
policyId: {
1530
type: "string",
1631
label: "Policy ID",
17-
description: "Select the policy where the report will be created.",
32+
description: "Select the policy where the report will be created",
1833
async options({ userEmail }) {
1934
const { policyList } = await this.getPolicyList({
2035
userEmail,
@@ -152,7 +167,17 @@ export default defineApp({
152167
},
153168
}, $);
154169
},
155-
170+
async listPolicies({ $ = this } = {}) {
171+
return this._makeRequest({
172+
method: "post",
173+
data: {
174+
type: "get",
175+
inputSettings: {
176+
type: "policyList",
177+
},
178+
},
179+
}, $);
180+
},
156181
async downloadFile({
157182
$, fileName,
158183
}) {

components/expensify/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/expensify",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Pipedream Expensify Components",
55
"main": "dist/app/expensify.app.mjs",
66
"keywords": [

0 commit comments

Comments
 (0)