Skip to content

Commit 17c0b6f

Browse files
committed
new component
1 parent 212cd8b commit 17c0b6f

File tree

4 files changed

+268
-4
lines changed

4 files changed

+268
-4
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.2",
6+
version: "0.0.3",
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/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.2",
7+
version: "0.0.3",
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: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
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 a report to a PDF file. [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 a`pprovedAfter` 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+
markAsExportedFilter: {
56+
type: "boolean",
57+
label: "Mark as Exported (Filter)",
58+
description: "Filters out reports that have already been exported with that label out",
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: "The reports will be exported from that the specified employee email",
78+
optional: true,
79+
},
80+
policyIds: {
81+
propDefinition: [
82+
expensify,
83+
"policyIds",
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",
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+
const onFinish = [];
140+
if (this.emailRecipients) {
141+
onFinish.push({
142+
actionName: "email",
143+
recipients: this.emailRecipients.join(","),
144+
});
145+
}
146+
147+
if (this.markAsExported) {
148+
onFinish.push({
149+
actionName: "markAsExported",
150+
label: this.markAsExported,
151+
});
152+
}
153+
154+
const data = {
155+
type: "file",
156+
credentials: {
157+
partnerUserID: this.expensify._partnerUserId(),
158+
partnerUserSecret: this.expensify._partnerUserSecret(),
159+
},
160+
onReceive: {
161+
immediateResponse: [
162+
"returnRandomFileName",
163+
],
164+
},
165+
inputSettings: {
166+
type: "combinedReportData",
167+
filters: {
168+
reportIDList: this.reportIds
169+
? this.reportIds.join(",")
170+
: undefined,
171+
startDate: this.startDate,
172+
endDate: this.endDate,
173+
approvedAfter: this.approvedAfter,
174+
markAsExported: this.markAsExportedFilter,
175+
policyIDList: this.policyIds
176+
? this.policyIds.join(",")
177+
: undefined,
178+
},
179+
reportStates: this.reportStates
180+
? this.reportStates.join(",")
181+
: undefined,
182+
employeeEmail: this.employeeEmail,
183+
limit: this.limit,
184+
},
185+
outputSettings: {
186+
fileExtension: this.fileExtension,
187+
fileBaseName: this.fileBaseName,
188+
includeFullPageReceiptsPdf: this.includeFullPageReceiptsPdf,
189+
},
190+
onFinish,
191+
test: this.test,
192+
};
193+
194+
let fileName;
195+
const args = {
196+
method: "post",
197+
url: `${this.expensify._apiUrl()}`,
198+
};
199+
200+
if (!this.templatePath) {
201+
fileName = await axios($, {
202+
...args,
203+
data: qs.stringify({
204+
requestJobDescription: JSON.stringify(data),
205+
template: "default",
206+
}),
207+
});
208+
} else {
209+
fileName = await axios($, {
210+
...args,
211+
data: qs.stringify({
212+
requestJobDescription: JSON.stringify(data),
213+
template: fs.readFileSync(this.templatePath.includes("tmp/")
214+
? this.templatePath
215+
: `/tmp/${this.templatePath}`, "utf8"),
216+
}),
217+
headers: {
218+
"Content-Type": "application/x-www-form-urlencoded",
219+
},
220+
});
221+
}
222+
223+
const fileBuffer = await this.expensify.downloadFile({
224+
$,
225+
fileName,
226+
});
227+
228+
const path = `/tmp/${fileName}`;
229+
230+
await fs.writeFileSync(path, fileBuffer);
231+
232+
if (fileBuffer) {
233+
$.export("$summary", `Successfully exported report in ${path}`);
234+
}
235+
236+
return path;
237+
},
238+
});

components/expensify/app/expensify.app.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,23 @@ import qs from "qs";
55
export default defineApp({
66
type: "app",
77
app: "expensify",
8-
propDefinitions: {},
8+
propDefinitions: {
9+
policyIds: {
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+
},
24+
},
925
methods: {
1026
_partnerUserId() {
1127
return this.$auth.partnerUserId;
@@ -87,7 +103,17 @@ export default defineApp({
87103
},
88104
}, $);
89105
},
90-
106+
async listPolicies({ $ = this } = {}) {
107+
return this._makeRequest({
108+
method: "post",
109+
data: {
110+
type: "get",
111+
inputSettings: {
112+
type: "policyList",
113+
},
114+
},
115+
}, $);
116+
},
91117
async downloadFile({
92118
$, fileName,
93119
}) {

0 commit comments

Comments
 (0)