@pipedream/harvest 0.1.0 → 1.0.0
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.
- package/actions/create-invoice/create-invoice.mjs +116 -0
- package/actions/create-project/create-project.mjs +138 -0
- package/actions/create-task-assignment/create-task-assignment.mjs +77 -0
- package/actions/create-timesheet-entry/create-timesheet-entry.mjs +34 -38
- package/actions/create-user/create-user.mjs +109 -0
- package/actions/create-user-assignment/create-user-assignment.mjs +85 -0
- package/actions/delete-invoice/delete-invoice.mjs +38 -0
- package/actions/delete-project/delete-project.mjs +38 -0
- package/actions/delete-task-assignment/delete-task-assignment.mjs +45 -0
- package/actions/delete-time-entry/delete-time-entry.mjs +38 -0
- package/actions/delete-user/delete-user.mjs +39 -0
- package/actions/delete-user-assignment/delete-user-assignment.mjs +45 -0
- package/actions/get-invoice/get-invoice.mjs +39 -0
- package/actions/get-me/get-me.mjs +32 -0
- package/actions/get-project/get-project.mjs +39 -0
- package/actions/get-projects/get-projects.mjs +15 -12
- package/actions/get-task-assignment/get-task-assignment.mjs +46 -0
- package/actions/get-time-entry/get-time-entry.mjs +39 -0
- package/actions/get-time-report/get-time-report.mjs +80 -0
- package/actions/get-user/get-user.mjs +40 -0
- package/actions/get-user-assignment/get-user-assignment.mjs +46 -0
- package/actions/list-account-id-options/list-account-id-options.mjs +12 -3
- package/actions/list-clients/list-clients.mjs +57 -0
- package/actions/list-invoices/list-invoices.mjs +86 -0
- package/actions/list-task-assignments/list-task-assignments.mjs +66 -0
- package/actions/list-tasks/list-tasks.mjs +57 -0
- package/actions/list-time-entries/list-time-entries.mjs +150 -0
- package/actions/list-user-assignments/list-user-assignments.mjs +74 -0
- package/actions/list-users/list-users.mjs +57 -0
- package/actions/start-timer/start-timer.mjs +5 -7
- package/actions/stop-timer/stop-timer.mjs +5 -7
- package/actions/update-invoice/update-invoice.mjs +114 -0
- package/actions/update-project/update-project.mjs +140 -0
- package/actions/update-task-assignment/update-task-assignment.mjs +77 -0
- package/actions/update-time-entry/update-time-entry.mjs +92 -0
- package/actions/update-user/update-user.mjs +106 -0
- package/actions/update-user-assignment/update-user-assignment.mjs +84 -0
- package/common/constants.mjs +51 -1
- package/common/utils.mjs +50 -1
- package/harvest.app.mjs +683 -110
- package/package.json +1 -1
- package/sources/new-invoice-entry/new-invoice-entry.mjs +1 -1
- package/sources/new-timesheet-entry/new-timesheet-entry.mjs +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-project",
|
|
5
|
+
name: "Delete Project",
|
|
6
|
+
description: "Permanently delete a project and all time entries and expenses tracked to it (invoices are not deleted). Use **Get Projects** to find a project ID. Example: call with projectId set to a project's ID to permanently remove it. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/projects/#delete-a-project).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
await this.harvest.deleteProject({
|
|
32
|
+
$,
|
|
33
|
+
projectId: this.projectId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully deleted project ${this.projectId}`);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-task-assignment",
|
|
5
|
+
name: "Delete Task Assignment",
|
|
6
|
+
description: "Delete a task assignment from a project (only possible if it has no time entries). Use **List Task Assignments** to find IDs. Example: call with projectId and taskAssignmentId to remove that task from the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/task-assignments/#delete-a-task-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
taskAssignmentId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"taskAssignmentId",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async run({ $ }) {
|
|
37
|
+
await this.harvest.deleteTaskAssignment({
|
|
38
|
+
$,
|
|
39
|
+
projectId: this.projectId,
|
|
40
|
+
taskAssignmentId: this.taskAssignmentId,
|
|
41
|
+
accountId: this.accountId,
|
|
42
|
+
});
|
|
43
|
+
$.export("$summary", `Successfully deleted task assignment ${this.taskAssignmentId}`);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-time-entry",
|
|
5
|
+
name: "Delete Time Entry",
|
|
6
|
+
description: "Permanently delete a time entry. Use **List Time Entries** to find a valid ID. Example: call with timeEntryId set to a mistakenly logged entry's ID to remove it. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#delete-a-time-entry).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
timeEntryId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"timeEntryId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
await this.harvest.deleteTimeEntry({
|
|
32
|
+
$,
|
|
33
|
+
id: this.timeEntryId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully deleted time entry ${this.timeEntryId}`);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-user",
|
|
5
|
+
name: "Delete User",
|
|
6
|
+
description: "Permanently delete a user (only possible if they have no time entries or expenses). Use **List Users** to find a valid ID. Example: call with userId set to a departed team member's ID to remove their Harvest access. [See the documentation](https://help.getharvest.com/api-v2/users-api/users/users/#delete-a-user).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
userId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"userId",
|
|
27
|
+
],
|
|
28
|
+
optional: false,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
async run({ $ }) {
|
|
32
|
+
await this.harvest.deleteUser({
|
|
33
|
+
$,
|
|
34
|
+
userId: this.userId,
|
|
35
|
+
accountId: this.accountId,
|
|
36
|
+
});
|
|
37
|
+
$.export("$summary", `Successfully deleted user ${this.userId}`);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-user-assignment",
|
|
5
|
+
name: "Delete User Assignment",
|
|
6
|
+
description: "Delete a user assignment from a project (only possible if it has no time entries or expenses). Use **List User Assignments** to find IDs. Example: call with projectId and userAssignmentId to unstaff that person from the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/user-assignments/#delete-a-user-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: true,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
userAssignmentId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"userAssignmentId",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async run({ $ }) {
|
|
37
|
+
await this.harvest.deleteUserAssignment({
|
|
38
|
+
$,
|
|
39
|
+
projectId: this.projectId,
|
|
40
|
+
userAssignmentId: this.userAssignmentId,
|
|
41
|
+
accountId: this.accountId,
|
|
42
|
+
});
|
|
43
|
+
$.export("$summary", `Successfully deleted user assignment ${this.userAssignmentId}`);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-invoice",
|
|
5
|
+
name: "Get Invoice",
|
|
6
|
+
description: "Retrieve a single invoice by ID. Use **List Invoices** to find a valid ID. Example: call with invoiceId set to a known invoice's ID to check its amount and payment state. [See the documentation](https://help.getharvest.com/api-v2/invoices-api/invoices/invoices/#retrieve-an-invoice).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
invoiceId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"invoiceId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
const response = await this.harvest.getInvoice({
|
|
32
|
+
$,
|
|
33
|
+
invoiceId: this.invoiceId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully retrieved invoice ${response.id}`);
|
|
37
|
+
return response;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-me",
|
|
5
|
+
name: "Get Me",
|
|
6
|
+
description: "Retrieve the currently authenticated user from `GET /users/me`. Takes no ID input. Example: call with no parameters to answer \"who am I logged in as in Harvest?\". [See the documentation](https://help.getharvest.com/api-v2/users-api/users/users/#retrieve-the-currently-authenticated-user).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
async run({ $ }) {
|
|
25
|
+
const response = await this.harvest.getMe({
|
|
26
|
+
$,
|
|
27
|
+
accountId: this.accountId,
|
|
28
|
+
});
|
|
29
|
+
$.export("$summary", `Successfully retrieved authenticated user ${response.id}: ${response.first_name} ${response.last_name}`);
|
|
30
|
+
return response;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-project",
|
|
5
|
+
name: "Get Project",
|
|
6
|
+
description: "Retrieve a single project by ID. Example: call with projectId set to a known project's ID to see its client, budget, and billing method. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/projects/#retrieve-a-project).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
const response = await this.harvest.getProject({
|
|
32
|
+
$,
|
|
33
|
+
projectId: this.projectId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully retrieved project ${response.id}: ${response.name}`);
|
|
37
|
+
return response;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
import constants from "../../common/constants.mjs";
|
|
2
3
|
import { ConfigurationError } from "@pipedream/platform";
|
|
4
|
+
import {
|
|
5
|
+
mapWithRateLimit, withRetryAfter,
|
|
6
|
+
} from "../../common/utils.mjs";
|
|
3
7
|
|
|
4
8
|
export default {
|
|
5
9
|
key: "harvest-get-projects",
|
|
6
10
|
name: "Get Projects",
|
|
7
|
-
description:
|
|
8
|
-
version: "0.0
|
|
11
|
+
description: `Retrieve one or more projects. Omit Project IDs to list every project in the account (up to ${constants.MAX_AUTO_PAGINATE_RECORDS}) — use this to discover project IDs for other Harvest tools. Provide Project IDs to fetch specific projects instead. Example: call with no Project IDs to find the ID for "Jurassic Park Construction" before creating a task assignment on it. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/projects/#list-all-projects).`,
|
|
12
|
+
version: "0.1.0",
|
|
9
13
|
annotations: {
|
|
10
14
|
destructiveHint: false,
|
|
11
15
|
openWorldHint: true,
|
|
12
16
|
readOnlyHint: true,
|
|
13
17
|
},
|
|
14
18
|
type: "action",
|
|
19
|
+
ai: "optimized",
|
|
15
20
|
props: {
|
|
16
21
|
harvest,
|
|
17
22
|
accountId: {
|
|
@@ -24,12 +29,9 @@ export default {
|
|
|
24
29
|
propDefinition: [
|
|
25
30
|
harvest,
|
|
26
31
|
"projectId",
|
|
27
|
-
(c) => ({
|
|
28
|
-
accountId: c.accountId,
|
|
29
|
-
}),
|
|
30
32
|
],
|
|
31
33
|
type: "string[]",
|
|
32
|
-
description: "Array of project IDs",
|
|
34
|
+
description: "Array of free-form project IDs, e.g. `[\"14308069\"]`. Omit this parameter to retrieve every project instead.",
|
|
33
35
|
optional: true,
|
|
34
36
|
},
|
|
35
37
|
},
|
|
@@ -42,24 +44,25 @@ export default {
|
|
|
42
44
|
throw new ConfigurationError("Project IDs must be an array");
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
let results;
|
|
46
48
|
|
|
47
49
|
if (projectIds) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
results = await mapWithRateLimit(projectIds, (projectId) =>
|
|
51
|
+
withRetryAfter(() => this.harvest.getProject({
|
|
50
52
|
$,
|
|
51
53
|
projectId,
|
|
52
54
|
accountId,
|
|
53
|
-
});
|
|
54
|
-
results.push(project);
|
|
55
|
-
}
|
|
55
|
+
})));
|
|
56
56
|
} else {
|
|
57
|
+
results = [];
|
|
57
58
|
const projects = await this.harvest.listProjectsPaginated({
|
|
58
59
|
page: 1,
|
|
60
|
+
$,
|
|
59
61
|
accountId,
|
|
60
62
|
});
|
|
61
63
|
for await (const project of projects) {
|
|
62
64
|
results.push(project);
|
|
65
|
+
if (results.length >= constants.MAX_AUTO_PAGINATE_RECORDS) break;
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-task-assignment",
|
|
5
|
+
name: "Get Task Assignment",
|
|
6
|
+
description: "Retrieve a single task assignment on a project. Use **List Task Assignments** to find IDs. Example: call with projectId and taskAssignmentId to check whether that task is billable on the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/task-assignments/#retrieve-a-task-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
taskAssignmentId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"taskAssignmentId",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async run({ $ }) {
|
|
37
|
+
const response = await this.harvest.getTaskAssignment({
|
|
38
|
+
$,
|
|
39
|
+
projectId: this.projectId,
|
|
40
|
+
taskAssignmentId: this.taskAssignmentId,
|
|
41
|
+
accountId: this.accountId,
|
|
42
|
+
});
|
|
43
|
+
$.export("$summary", `Successfully retrieved task assignment ${response.id}`);
|
|
44
|
+
return response;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-time-entry",
|
|
5
|
+
name: "Get Time Entry",
|
|
6
|
+
description: "Retrieve a single time entry by ID. Use **List Time Entries** to find a valid ID. Example: call with timeEntryId set to a known entry's ID to see its hours, project, and task. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#retrieve-a-time-entry).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
timeEntryId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"timeEntryId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
const response = await this.harvest.getTimeEntry({
|
|
32
|
+
$,
|
|
33
|
+
id: this.timeEntryId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully retrieved time entry ${response.id}`);
|
|
37
|
+
return response;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
import constants from "../../common/constants.mjs";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
key: "harvest-get-time-report",
|
|
6
|
+
name: "Get Time Report",
|
|
7
|
+
description: `Retrieve total hours logged, aggregated by a chosen dimension (clients, projects, tasks, or team) over a date range, automatically following pagination up to ${constants.MAX_AUTO_PAGINATE_RECORDS} results. Use when the user asks "how many hours were logged/worked on X", "how much time did the team spend on Y", or wants a time report/summary/breakdown — this is the only tool that returns aggregated totals; **List Time Entries** returns individual raw entries you would have to sum yourself. The Report By value selects which \`/reports/time/{dimension}\` endpoint is called. Example: call with reportBy="projects", from="20260901", to="20260930" to see total hours logged per project for the month. [See the documentation](https://help.getharvest.com/api-v2/reports-api/reports/time-reports/)`,
|
|
8
|
+
version: "0.0.1",
|
|
9
|
+
type: "action",
|
|
10
|
+
ai: "optimized",
|
|
11
|
+
annotations: {
|
|
12
|
+
readOnlyHint: true,
|
|
13
|
+
destructiveHint: false,
|
|
14
|
+
openWorldHint: true,
|
|
15
|
+
},
|
|
16
|
+
props: {
|
|
17
|
+
harvest,
|
|
18
|
+
accountId: {
|
|
19
|
+
propDefinition: [
|
|
20
|
+
harvest,
|
|
21
|
+
"accountId",
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
reportBy: {
|
|
25
|
+
type: "string",
|
|
26
|
+
label: "Report By",
|
|
27
|
+
description: "The dimension to group the report by. One of: `clients`, `projects`, `tasks`, `team`.",
|
|
28
|
+
options: constants.REPORT_BY_OPTIONS,
|
|
29
|
+
},
|
|
30
|
+
from: {
|
|
31
|
+
type: "string",
|
|
32
|
+
label: "From",
|
|
33
|
+
description: "Start of the report range, format `YYYYMMDD`, e.g. `20260901`.",
|
|
34
|
+
},
|
|
35
|
+
to: {
|
|
36
|
+
type: "string",
|
|
37
|
+
label: "To",
|
|
38
|
+
description: "End of the report range, format `YYYYMMDD`, e.g. `20260910`.",
|
|
39
|
+
},
|
|
40
|
+
includeFixedFee: {
|
|
41
|
+
type: "boolean",
|
|
42
|
+
label: "Include Fixed Fee",
|
|
43
|
+
description: "Whether to include fixed-fee projects in the report.",
|
|
44
|
+
optional: true,
|
|
45
|
+
},
|
|
46
|
+
includeForecast: {
|
|
47
|
+
type: "boolean",
|
|
48
|
+
label: "Include Forecast",
|
|
49
|
+
description: "Whether to include forecast data (only supported when Report By is `projects` or `team`).",
|
|
50
|
+
optional: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
async run({ $ }) {
|
|
54
|
+
const results = [];
|
|
55
|
+
let page = 1;
|
|
56
|
+
do {
|
|
57
|
+
const response = await this.harvest.getTimeReport({
|
|
58
|
+
$,
|
|
59
|
+
reportBy: this.reportBy,
|
|
60
|
+
accountId: this.accountId,
|
|
61
|
+
from: this.from,
|
|
62
|
+
to: this.to,
|
|
63
|
+
include_fixed_fee: this.includeFixedFee,
|
|
64
|
+
include_forecast: this.includeForecast,
|
|
65
|
+
per_page: constants.PAGE_SIZE,
|
|
66
|
+
page,
|
|
67
|
+
});
|
|
68
|
+
if (!response.results?.length) break;
|
|
69
|
+
const remaining = constants.MAX_AUTO_PAGINATE_RECORDS - results.length;
|
|
70
|
+
results.push(...response.results.slice(0, remaining));
|
|
71
|
+
if (!response.next_page || remaining <= response.results.length) break;
|
|
72
|
+
page += 1;
|
|
73
|
+
} while (true);
|
|
74
|
+
const count = results.length;
|
|
75
|
+
$.export("$summary", `Successfully retrieved time report by ${this.reportBy} with ${count} result${count === 1
|
|
76
|
+
? ""
|
|
77
|
+
: "s"}`);
|
|
78
|
+
return results;
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-user",
|
|
5
|
+
name: "Get User",
|
|
6
|
+
description: "Retrieve a single user by ID. Use **List Users** to find a valid ID. To fetch the authenticated user, use **Get Me** instead. Example: call with userId set to a known user's ID to see their name, email, and role. [See the documentation](https://help.getharvest.com/api-v2/users-api/users/users/#retrieve-a-user).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
userId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"userId",
|
|
27
|
+
],
|
|
28
|
+
optional: false,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
async run({ $ }) {
|
|
32
|
+
const response = await this.harvest.getUser({
|
|
33
|
+
$,
|
|
34
|
+
userId: this.userId,
|
|
35
|
+
accountId: this.accountId,
|
|
36
|
+
});
|
|
37
|
+
$.export("$summary", `Successfully retrieved user ${response.id}: ${response.first_name} ${response.last_name}`);
|
|
38
|
+
return response;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-get-user-assignment",
|
|
5
|
+
name: "Get User Assignment",
|
|
6
|
+
description: "Retrieve a single user assignment on a project. Use **List User Assignments** to find IDs. Example: call with projectId and userAssignmentId to check that person's hourly rate on the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/user-assignments/#retrieve-a-user-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
projectId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"projectId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
userAssignmentId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"userAssignmentId",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async run({ $ }) {
|
|
37
|
+
const response = await this.harvest.getUserAssignment({
|
|
38
|
+
$,
|
|
39
|
+
projectId: this.projectId,
|
|
40
|
+
userAssignmentId: this.userAssignmentId,
|
|
41
|
+
accountId: this.accountId,
|
|
42
|
+
});
|
|
43
|
+
$.export("$summary", `Successfully retrieved user assignment ${response.id}`);
|
|
44
|
+
return response;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -3,9 +3,10 @@ import harvest from "../../harvest.app.mjs";
|
|
|
3
3
|
export default {
|
|
4
4
|
key: "harvest-list-account-id-options",
|
|
5
5
|
name: "List Account ID Options",
|
|
6
|
-
description: "
|
|
7
|
-
version: "0.0.
|
|
6
|
+
description: "List the Harvest accounts (companies) the authenticated user has access to, each with its Account ID. Use this first to find the Account ID required by every other Harvest tool. Example: call with no parameters, then pass the returned id as Account ID on any other Harvest tool call. [See the documentation](https://help.getharvest.com/api-v2/accounts-api/accounts/accounts/#list-all-accounts-for-a-user).",
|
|
7
|
+
version: "0.0.2",
|
|
8
8
|
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
9
10
|
annotations: {
|
|
10
11
|
destructiveHint: false,
|
|
11
12
|
openWorldHint: true,
|
|
@@ -15,7 +16,15 @@ export default {
|
|
|
15
16
|
harvest,
|
|
16
17
|
},
|
|
17
18
|
async run({ $ }) {
|
|
18
|
-
const
|
|
19
|
+
const { accounts } = await this.harvest.listAccounts({
|
|
20
|
+
$,
|
|
21
|
+
});
|
|
22
|
+
const options = accounts.map(({
|
|
23
|
+
id, name, product,
|
|
24
|
+
}) => ({
|
|
25
|
+
label: `${name} (${product})`,
|
|
26
|
+
value: id,
|
|
27
|
+
}));
|
|
19
28
|
$.export("$summary", `Successfully retrieved ${options.length} option${options.length === 1
|
|
20
29
|
? ""
|
|
21
30
|
: "s"}`);
|