@pipedream/harvest 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,20 +10,32 @@ export default {
10
10
  description: `Creates a new time entry object.
11
11
  [Create a time entry via duration documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#create-a-time-entry-via-duration),
12
12
  [Create a time entry via start and end time documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#create-a-time-entry-via-start-and-end-time)`,
13
- version: "0.0.1",
13
+ version: "0.0.2",
14
14
  type: "action",
15
15
  props: {
16
16
  harvest,
17
+ accountId: {
18
+ propDefinition: [
19
+ harvest,
20
+ "accountId",
21
+ ],
22
+ },
17
23
  projectId: {
18
24
  propDefinition: [
19
25
  harvest,
20
26
  "projectId",
27
+ (c) => ({
28
+ accountId: c.accountId,
29
+ }),
21
30
  ],
22
31
  },
23
32
  taskId: {
24
33
  propDefinition: [
25
34
  harvest,
26
35
  "taskId",
36
+ (c) => ({
37
+ accountId: c.accountId,
38
+ }),
27
39
  ],
28
40
  },
29
41
  spentDate: {
@@ -35,6 +47,9 @@ export default {
35
47
  propDefinition: [
36
48
  harvest,
37
49
  "userId",
50
+ (c) => ({
51
+ accountId: c.accountId,
52
+ }),
38
53
  ],
39
54
  },
40
55
  specifyStartEndTime: {
@@ -80,12 +95,13 @@ export default {
80
95
  task_id: this.taskId,
81
96
  user_id: this.userId,
82
97
  spent_date: this.spentDate,
83
- started_time: this.startedTime.replace(/\s/g, ""),
84
- ended_time: this.endedTime.replace(/\s/g, ""),
98
+ started_time: this.startedTime?.replace(/\s/g, ""),
99
+ ended_time: this.endedTime?.replace(/\s/g, ""),
85
100
  });
86
101
  const response = await this.harvest.createTimeEntry({
87
102
  $,
88
103
  params,
104
+ accountId: this.accountId,
89
105
  });
90
106
  response && $.export("$summary", "Successfully created time entry");
91
107
  return response;
@@ -0,0 +1,64 @@
1
+ import harvest from "../../harvest.app.mjs";
2
+ import { ConfigurationError } from "@pipedream/platform";
3
+
4
+ export default {
5
+ key: "harvest-get-projects",
6
+ name: "Get Projects",
7
+ description: "Retrieve data for a project or projects. [See docs here](https://help.getharvest.com/api-v2/projects-api/projects/projects/#list-all-projects)",
8
+ version: "0.0.1",
9
+ type: "action",
10
+ props: {
11
+ harvest,
12
+ accountId: {
13
+ propDefinition: [
14
+ harvest,
15
+ "accountId",
16
+ ],
17
+ },
18
+ projectIds: {
19
+ propDefinition: [
20
+ harvest,
21
+ "projectId",
22
+ (c) => ({
23
+ accountId: c.accountId,
24
+ }),
25
+ ],
26
+ type: "string[]",
27
+ description: "Array of project IDs",
28
+ optional: true,
29
+ },
30
+ },
31
+ async run({ $ }) {
32
+ const {
33
+ accountId, projectIds,
34
+ } = this;
35
+
36
+ if (projectIds && !Array.isArray(projectIds)) {
37
+ throw new ConfigurationError("Project IDs must be an array");
38
+ }
39
+
40
+ const results = [];
41
+
42
+ if (projectIds) {
43
+ for (const projectId of projectIds) {
44
+ const project = await this.harvest.getProject({
45
+ $,
46
+ projectId,
47
+ accountId,
48
+ });
49
+ results.push(project);
50
+ }
51
+ } else {
52
+ const projects = await this.harvest.listProjectsPaginated({
53
+ page: 1,
54
+ accountId,
55
+ });
56
+ for await (const project of projects) {
57
+ results.push(project);
58
+ }
59
+ }
60
+
61
+ results && $.export("$summary", `Successfully retrieved ${results?.length} project(s).`);
62
+ return results;
63
+ },
64
+ };
@@ -4,16 +4,23 @@ export default {
4
4
  key: "harvest-start-timer",
5
5
  name: "Start Time Entry",
6
6
  description: "Restart a stopped timer entry. [See docs here](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#restart-a-stopped-time-entry)",
7
- version: "0.0.1",
7
+ version: "0.0.2",
8
8
  type: "action",
9
9
  props: {
10
10
  harvest,
11
+ accountId: {
12
+ propDefinition: [
13
+ harvest,
14
+ "accountId",
15
+ ],
16
+ },
11
17
  timeEntryId: {
12
18
  propDefinition: [
13
19
  harvest,
14
20
  "timeEntryId",
15
- () => ({
21
+ (c) => ({
16
22
  isRunning: false,
23
+ accountId: c.accountId,
17
24
  }),
18
25
  ],
19
26
  },
@@ -22,6 +29,7 @@ export default {
22
29
  const response = await this.harvest.restartTimeEntry({
23
30
  $,
24
31
  id: this.timeEntryId,
32
+ accountId: this.accountId,
25
33
  });
26
34
  response && $.export("$summary", "Successfully started the time entry");
27
35
  return response;
@@ -4,16 +4,23 @@ export default {
4
4
  key: "harvest-stop-timer",
5
5
  name: "Stop Time Entry",
6
6
  description: "Stop a timer entry. [See docs here](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#stop-a-running-time-entry)",
7
- version: "0.0.2",
7
+ version: "0.0.3",
8
8
  type: "action",
9
9
  props: {
10
10
  harvest,
11
+ accountId: {
12
+ propDefinition: [
13
+ harvest,
14
+ "accountId",
15
+ ],
16
+ },
11
17
  timeEntryId: {
12
18
  propDefinition: [
13
19
  harvest,
14
20
  "timeEntryId",
15
- () => ({
21
+ (c) => ({
16
22
  isRunning: true,
23
+ accountId: c.accountId,
17
24
  }),
18
25
  ],
19
26
  },
@@ -22,6 +29,7 @@ export default {
22
29
  const response = await this.harvest.stopTimeEntry({
23
30
  $,
24
31
  id: this.timeEntryId,
32
+ accountId: this.accountId,
25
33
  });
26
34
  response && $.export("$summary", "Successfully ended the time entry");
27
35
  return response;
package/harvest.app.mjs CHANGED
@@ -13,10 +13,13 @@ export default {
13
13
  label: "Project ID",
14
14
  description: "The ID of the project to associate with the time entry",
15
15
  useQuery: true,
16
- async options({ page }) {
16
+ async options({
17
+ page, accountId,
18
+ }) {
17
19
  const response = await this.listProjects({
18
20
  perPage: constants.PAGE_SIZE,
19
21
  page: page + 1,
22
+ accountId,
20
23
  });
21
24
  return response.projects.map((project) => ({
22
25
  label: project.name,
@@ -29,10 +32,13 @@ export default {
29
32
  label: "Task ID",
30
33
  description: "The ID of the task to associate with the time entry",
31
34
  useQuery: true,
32
- async options({ page }) {
35
+ async options({
36
+ page, accountId,
37
+ }) {
33
38
  const response = await this.listTasks({
34
39
  perPage: constants.PAGE_SIZE,
35
40
  page: page + 1,
41
+ accountId,
36
42
  });
37
43
  return response.tasks.map((task) => ({
38
44
  label: task.name,
@@ -46,10 +52,13 @@ export default {
46
52
  description: "The ID of the user to associate with the time entry",
47
53
  useQuery: true,
48
54
  optional: true,
49
- async options({ page }) {
55
+ async options({
56
+ page, accountId,
57
+ }) {
50
58
  const response = await this.listUsers({
51
59
  perPage: constants.PAGE_SIZE,
52
60
  page: page + 1,
61
+ accountId,
53
62
  });
54
63
  return response.users.map((user) => ({
55
64
  label: `${user.first_name} ${user.last_name}`,
@@ -63,10 +72,13 @@ export default {
63
72
  description: "The ID of the client to associate with time entries",
64
73
  useQuery: true,
65
74
  optional: true,
66
- async options({ page }) {
75
+ async options({
76
+ page, accountId,
77
+ }) {
67
78
  const response = await this.listClients({
68
79
  perPage: constants.PAGE_SIZE,
69
80
  page: page + 1,
81
+ accountId,
70
82
  });
71
83
  return response.clients.map((client) => ({
72
84
  label: client.name,
@@ -80,12 +92,13 @@ export default {
80
92
  description: "The ID of the time entry.",
81
93
  useQuery: true,
82
94
  async options({
83
- page, isRunning,
95
+ page, isRunning, accountId,
84
96
  }) {
85
97
  const response = await this.listTimeEntries({
86
98
  perPage: constants.PAGE_SIZE,
87
99
  page: page + 1,
88
100
  is_running: isRunning,
101
+ accountId,
89
102
  });
90
103
  return response.time_entries.map((entry) => ({
91
104
  label: `Project: ${entry.project.name}, Task: ${entry.task.name}, Spend date: ${entry.spent_date} ${entry.started_time || ""} ${entry.ended_time
@@ -95,6 +108,20 @@ export default {
95
108
  }));
96
109
  },
97
110
  },
111
+ accountId: {
112
+ type: "string",
113
+ label: "Account ID",
114
+ description: "The ID of your account",
115
+ async options() {
116
+ const { accounts } = await this.listAccounts({});
117
+ return accounts.map(({
118
+ id, name,
119
+ }) => ({
120
+ label: name,
121
+ value: id,
122
+ }));
123
+ },
124
+ },
98
125
  },
99
126
  methods: {
100
127
  setLastDateChecked(db, value) {
@@ -103,11 +130,16 @@ export default {
103
130
  getLastDateChecked(db) {
104
131
  return db && db.get(constants.DB_LAST_DATE_CHECK);
105
132
  },
106
- _getHeaders() {
133
+ _getAuthorizationHeader() {
107
134
  return {
108
- "Content-Type": "application/json",
109
135
  "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
110
- "Harvest-Account-Id": this.$auth.account_id,
136
+ };
137
+ },
138
+ _getHeaders(accountId) {
139
+ return {
140
+ "Content-Type": "application/json",
141
+ "Harvest-Account-Id": accountId,
142
+ ...this._getAuthorizationHeader(),
111
143
  };
112
144
  },
113
145
  _getUrl(path) {
@@ -125,16 +157,23 @@ export default {
125
157
  path,
126
158
  params,
127
159
  data,
160
+ accountId,
128
161
  } = args;
129
162
  const config = {
130
163
  method,
131
164
  url: this._getUrl(path),
132
- headers: this._getHeaders(),
165
+ headers: this._getHeaders(accountId),
133
166
  params,
134
167
  data,
135
168
  };
136
169
  return axios($ ?? this, config);
137
170
  },
171
+ async listAccounts({ $ = this }) {
172
+ return axios($, {
173
+ url: "https://id.getharvest.com/api/v2/accounts",
174
+ headers: this._getAuthorizationHeader(),
175
+ });
176
+ },
138
177
  _isRetriableStatusCode(statusCode) {
139
178
  constants.retriableStatusCodes.includes(statusCode);
140
179
  },
@@ -161,7 +200,7 @@ export default {
161
200
  }, retryOpts);
162
201
  },
163
202
  async *listTimeEntriesPaginated({
164
- page, updatedSince,
203
+ page, updatedSince, accountId,
165
204
  }) {
166
205
  do {
167
206
  const response = await this._withRetries(
@@ -169,6 +208,7 @@ export default {
169
208
  per_page: constants.PAGE_SIZE,
170
209
  page,
171
210
  updated_since: updatedSince,
211
+ accountId,
172
212
  }),
173
213
  );
174
214
 
@@ -185,7 +225,7 @@ export default {
185
225
  } while (true);
186
226
  },
187
227
  async *listInvoicesPaginated({
188
- page, updatedSince,
228
+ page, updatedSince, accountId,
189
229
  }) {
190
230
  do {
191
231
  const response = await this._withRetries(
@@ -193,6 +233,7 @@ export default {
193
233
  per_page: constants.PAGE_SIZE,
194
234
  page,
195
235
  updated_since: updatedSince,
236
+ accountId,
196
237
  }),
197
238
  );
198
239
 
@@ -208,8 +249,42 @@ export default {
208
249
  page += 1;
209
250
  } while (true);
210
251
  },
252
+ async *listProjectsPaginated({
253
+ page, $, accountId,
254
+ }) {
255
+ do {
256
+ const response = await this._withRetries(
257
+ () => this.listProjects({
258
+ accountId,
259
+ per_page: constants.PAGE_SIZE,
260
+ page,
261
+ $,
262
+ }),
263
+ );
264
+
265
+ if (response.projects.length === 0) {
266
+ return;
267
+ }
268
+ for (const project of response.projects) {
269
+ yield project;
270
+ }
271
+ if (!response.next_page) {
272
+ return;
273
+ }
274
+ page += 1;
275
+ } while (true);
276
+ },
277
+ async getProject({
278
+ $, projectId, accountId,
279
+ }) {
280
+ return this._makeRequest({
281
+ $,
282
+ path: `/projects/${projectId}`,
283
+ accountId,
284
+ });
285
+ },
211
286
  async listProjects({
212
- $, perPage, page,
287
+ $, perPage, page, accountId,
213
288
  }) {
214
289
  return this._makeRequest({
215
290
  $,
@@ -218,10 +293,11 @@ export default {
218
293
  per_page: perPage,
219
294
  page,
220
295
  },
296
+ accountId,
221
297
  });
222
298
  },
223
299
  async listTasks({
224
- $, perPage, page,
300
+ $, perPage, page, accountId,
225
301
  }) {
226
302
  return this._makeRequest({
227
303
  $,
@@ -230,10 +306,11 @@ export default {
230
306
  per_page: perPage,
231
307
  page,
232
308
  },
309
+ accountId,
233
310
  });
234
311
  },
235
312
  async listUsers({
236
- $, perPage, page,
313
+ $, perPage, page, accountId,
237
314
  }) {
238
315
  return this._makeRequest({
239
316
  $,
@@ -242,10 +319,11 @@ export default {
242
319
  per_page: perPage,
243
320
  page,
244
321
  },
322
+ accountId,
245
323
  });
246
324
  },
247
325
  async listClients({
248
- $, perPage, page,
326
+ $, perPage, page, accountId,
249
327
  }) {
250
328
  return this._makeRequest({
251
329
  $,
@@ -254,52 +332,58 @@ export default {
254
332
  per_page: perPage,
255
333
  page,
256
334
  },
335
+ accountId,
257
336
  });
258
337
  },
259
338
  async createTimeEntry({
260
- $, params,
339
+ $, params, accountId,
261
340
  }) {
262
341
  return this._makeRequest({
263
342
  $,
264
343
  path: "/time_entries",
265
344
  params,
266
345
  method: "post",
346
+ accountId,
267
347
  });
268
348
  },
269
349
  async listTimeEntries({
270
- $, ...params
350
+ $, accountId, ...params
271
351
  }) {
272
352
 
273
353
  return this._makeRequest({
274
354
  $,
275
355
  path: "/time_entries",
356
+ accountId,
276
357
  params,
277
358
  });
278
359
  },
279
360
  async restartTimeEntry({
280
- $, id,
361
+ $, id, accountId,
281
362
  }) {
282
363
  return this._makeRequest({
283
364
  $,
284
365
  path: `/time_entries/${id}/restart`,
285
366
  method: "patch",
367
+ accountId,
286
368
  });
287
369
  },
288
370
  async stopTimeEntry({
289
- $, id,
371
+ $, id, accountId,
290
372
  }) {
291
373
  return this._makeRequest({
292
374
  $,
293
375
  path: `/time_entries/${id}/stop`,
294
376
  method: "patch",
377
+ accountId,
295
378
  });
296
379
  },
297
380
  async listInvoices({
298
- $, ...params
381
+ $, accountId, ...params
299
382
  }) {
300
383
  return this._makeRequest({
301
384
  $,
302
385
  path: "/invoices",
386
+ accountId,
303
387
  params,
304
388
  });
305
389
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/harvest",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Pipedream Harvest Components",
5
5
  "main": "harvest.app.mjs",
6
6
  "keywords": [
@@ -5,7 +5,7 @@ export default {
5
5
  key: "harvest-new-invoice-entry",
6
6
  name: "New Invoice Entry",
7
7
  description: "Emit new notifications when a new invoice is created",
8
- version: "0.0.3",
8
+ version: "0.0.4",
9
9
  type: "source",
10
10
  props: {
11
11
  harvest,
@@ -18,6 +18,12 @@ export default {
18
18
  },
19
19
  },
20
20
  db: "$.service.db",
21
+ accountId: {
22
+ propDefinition: [
23
+ harvest,
24
+ "accountId",
25
+ ],
26
+ },
21
27
  },
22
28
  dedupe: "unique",
23
29
  async run() {
@@ -30,6 +36,7 @@ export default {
30
36
  const invoices = await this.harvest.listInvoicesPaginated({
31
37
  page: 1,
32
38
  updatedSince: lastDateChecked,
39
+ accountId: this.accountId,
33
40
  });
34
41
  for await (const invoice of invoices) {
35
42
  data.push(invoice);
@@ -5,7 +5,7 @@ export default {
5
5
  key: "harvest-new-timesheet-entry",
6
6
  name: "New Timesheet Entry",
7
7
  description: "Emit new notifications when a new timesheet entry is created",
8
- version: "0.0.3",
8
+ version: "0.0.4",
9
9
  type: "source",
10
10
  props: {
11
11
  harvest,
@@ -18,6 +18,12 @@ export default {
18
18
  },
19
19
  },
20
20
  db: "$.service.db",
21
+ accountId: {
22
+ propDefinition: [
23
+ harvest,
24
+ "accountId",
25
+ ],
26
+ },
21
27
  },
22
28
  dedupe: "unique",
23
29
  async run() {
@@ -30,6 +36,7 @@ export default {
30
36
  const entries = await this.harvest.listTimeEntriesPaginated({
31
37
  page: 1,
32
38
  updatedSince: lastDateChecked,
39
+ accountId: this.accountId,
33
40
  });
34
41
  for await (const entry of entries) {
35
42
  data.push(entry);