@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,116 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-create-invoice",
|
|
5
|
+
name: "Create Invoice",
|
|
6
|
+
description: "Create a new free-form invoice for a client. Provide Line Items as a JSON array to itemize the invoice. Example: call with clientId set to InGen Corp's client ID, subject=\"Consulting Services\", lineItems=`[{\"kind\":\"Service\",\"description\":\"Genetics consulting\",\"unit_price\":2000,\"quantity\":1}]`. [See the documentation](https://help.getharvest.com/api-v2/invoices-api/invoices/invoices/#create-a-free-form-invoice).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
clientId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"clientId",
|
|
27
|
+
],
|
|
28
|
+
optional: false,
|
|
29
|
+
},
|
|
30
|
+
subject: {
|
|
31
|
+
propDefinition: [
|
|
32
|
+
harvest,
|
|
33
|
+
"subject",
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
number: {
|
|
37
|
+
propDefinition: [
|
|
38
|
+
harvest,
|
|
39
|
+
"invoiceNumber",
|
|
40
|
+
],
|
|
41
|
+
description: "The invoice number, e.g. `1000`. Defaults to the next sequential number if omitted.",
|
|
42
|
+
},
|
|
43
|
+
purchaseOrder: {
|
|
44
|
+
propDefinition: [
|
|
45
|
+
harvest,
|
|
46
|
+
"purchaseOrder",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
tax: {
|
|
50
|
+
propDefinition: [
|
|
51
|
+
harvest,
|
|
52
|
+
"tax",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
discount: {
|
|
56
|
+
propDefinition: [
|
|
57
|
+
harvest,
|
|
58
|
+
"discount",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
notes: {
|
|
62
|
+
propDefinition: [
|
|
63
|
+
harvest,
|
|
64
|
+
"invoiceNotes",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
currency: {
|
|
68
|
+
type: "string",
|
|
69
|
+
label: "Currency",
|
|
70
|
+
description: "The currency code, e.g. `USD`.",
|
|
71
|
+
optional: true,
|
|
72
|
+
},
|
|
73
|
+
issueDate: {
|
|
74
|
+
propDefinition: [
|
|
75
|
+
harvest,
|
|
76
|
+
"issueDate",
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
dueDate: {
|
|
80
|
+
propDefinition: [
|
|
81
|
+
harvest,
|
|
82
|
+
"dueDate",
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
lineItems: {
|
|
86
|
+
type: "string",
|
|
87
|
+
label: "Line Items",
|
|
88
|
+
description: "JSON array of line item objects. Example: `[{\"kind\":\"Service\",\"description\":\"Consulting\",\"unit_price\":100,\"quantity\":5}]`. Each item requires `kind` and `unit_price`.",
|
|
89
|
+
optional: true,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
async run({ $ }) {
|
|
93
|
+
const lineItems = this.lineItems
|
|
94
|
+
? JSON.parse(this.lineItems)
|
|
95
|
+
: undefined;
|
|
96
|
+
const response = await this.harvest.createInvoice({
|
|
97
|
+
$,
|
|
98
|
+
accountId: this.accountId,
|
|
99
|
+
data: {
|
|
100
|
+
client_id: this.clientId,
|
|
101
|
+
subject: this.subject,
|
|
102
|
+
number: this.number,
|
|
103
|
+
purchase_order: this.purchaseOrder,
|
|
104
|
+
tax: this.tax,
|
|
105
|
+
discount: this.discount,
|
|
106
|
+
notes: this.notes,
|
|
107
|
+
currency: this.currency,
|
|
108
|
+
issue_date: this.issueDate,
|
|
109
|
+
due_date: this.dueDate,
|
|
110
|
+
line_items: lineItems,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
$.export("$summary", `Successfully created invoice ${response.id}`);
|
|
114
|
+
return response;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-create-project",
|
|
5
|
+
name: "Create Project",
|
|
6
|
+
description: "Create a new project. Example: call with clientId set to InGen Corp's client ID, projectName=\"Compound Perimeter Fence Upgrade\", isBillable=true, billBy=\"Project\", budgetBy=\"none\". [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/projects/#create-a-project).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
clientId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"clientId",
|
|
27
|
+
],
|
|
28
|
+
optional: false,
|
|
29
|
+
},
|
|
30
|
+
projectName: {
|
|
31
|
+
propDefinition: [
|
|
32
|
+
harvest,
|
|
33
|
+
"projectName",
|
|
34
|
+
],
|
|
35
|
+
optional: false,
|
|
36
|
+
},
|
|
37
|
+
isBillable: {
|
|
38
|
+
propDefinition: [
|
|
39
|
+
harvest,
|
|
40
|
+
"isBillable",
|
|
41
|
+
],
|
|
42
|
+
optional: false,
|
|
43
|
+
},
|
|
44
|
+
billBy: {
|
|
45
|
+
propDefinition: [
|
|
46
|
+
harvest,
|
|
47
|
+
"billBy",
|
|
48
|
+
],
|
|
49
|
+
optional: false,
|
|
50
|
+
},
|
|
51
|
+
budgetBy: {
|
|
52
|
+
propDefinition: [
|
|
53
|
+
harvest,
|
|
54
|
+
"budgetBy",
|
|
55
|
+
],
|
|
56
|
+
optional: false,
|
|
57
|
+
},
|
|
58
|
+
code: {
|
|
59
|
+
propDefinition: [
|
|
60
|
+
harvest,
|
|
61
|
+
"code",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
isActive: {
|
|
65
|
+
propDefinition: [
|
|
66
|
+
harvest,
|
|
67
|
+
"isActive",
|
|
68
|
+
],
|
|
69
|
+
description: "Whether the project is active.",
|
|
70
|
+
},
|
|
71
|
+
isFixedFee: {
|
|
72
|
+
propDefinition: [
|
|
73
|
+
harvest,
|
|
74
|
+
"isFixedFee",
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
hourlyRate: {
|
|
78
|
+
propDefinition: [
|
|
79
|
+
harvest,
|
|
80
|
+
"projectHourlyRate",
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
budget: {
|
|
84
|
+
propDefinition: [
|
|
85
|
+
harvest,
|
|
86
|
+
"projectBudget",
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
costBudget: {
|
|
90
|
+
propDefinition: [
|
|
91
|
+
harvest,
|
|
92
|
+
"costBudget",
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
notes: {
|
|
96
|
+
propDefinition: [
|
|
97
|
+
harvest,
|
|
98
|
+
"projectNotes",
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
startsOn: {
|
|
102
|
+
propDefinition: [
|
|
103
|
+
harvest,
|
|
104
|
+
"startsOn",
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
endsOn: {
|
|
108
|
+
propDefinition: [
|
|
109
|
+
harvest,
|
|
110
|
+
"endsOn",
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
async run({ $ }) {
|
|
115
|
+
const response = await this.harvest.createProject({
|
|
116
|
+
$,
|
|
117
|
+
accountId: this.accountId,
|
|
118
|
+
data: {
|
|
119
|
+
client_id: this.clientId,
|
|
120
|
+
name: this.projectName,
|
|
121
|
+
is_billable: this.isBillable,
|
|
122
|
+
bill_by: this.billBy,
|
|
123
|
+
budget_by: this.budgetBy,
|
|
124
|
+
code: this.code,
|
|
125
|
+
is_active: this.isActive,
|
|
126
|
+
is_fixed_fee: this.isFixedFee,
|
|
127
|
+
hourly_rate: this.hourlyRate,
|
|
128
|
+
budget: this.budget,
|
|
129
|
+
cost_budget: this.costBudget,
|
|
130
|
+
notes: this.notes,
|
|
131
|
+
starts_on: this.startsOn,
|
|
132
|
+
ends_on: this.endsOn,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
$.export("$summary", `Successfully created project ${response.id}: ${response.name}`);
|
|
136
|
+
return response;
|
|
137
|
+
},
|
|
138
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-create-task-assignment",
|
|
5
|
+
name: "Create Task Assignment",
|
|
6
|
+
description: "Assign a task to a project. Use **Get Projects** to find a project ID and **List Tasks** to find a task ID. Example: call with projectId set to the Jurassic Park Construction project's ID and taskId set to the Genetics Research task's ID to put that task on the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/task-assignments/#create-a-task-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
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
|
+
taskId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"taskId",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
isActive: {
|
|
36
|
+
propDefinition: [
|
|
37
|
+
harvest,
|
|
38
|
+
"isActive",
|
|
39
|
+
],
|
|
40
|
+
description: "Whether the task assignment is active.",
|
|
41
|
+
},
|
|
42
|
+
billable: {
|
|
43
|
+
propDefinition: [
|
|
44
|
+
harvest,
|
|
45
|
+
"billable",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
hourlyRate: {
|
|
49
|
+
propDefinition: [
|
|
50
|
+
harvest,
|
|
51
|
+
"taskAssignmentHourlyRate",
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
budget: {
|
|
55
|
+
propDefinition: [
|
|
56
|
+
harvest,
|
|
57
|
+
"taskAssignmentBudget",
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
async run({ $ }) {
|
|
62
|
+
const response = await this.harvest.createTaskAssignment({
|
|
63
|
+
$,
|
|
64
|
+
projectId: this.projectId,
|
|
65
|
+
accountId: this.accountId,
|
|
66
|
+
data: {
|
|
67
|
+
task_id: this.taskId,
|
|
68
|
+
is_active: this.isActive,
|
|
69
|
+
billable: this.billable,
|
|
70
|
+
hourly_rate: this.hourlyRate,
|
|
71
|
+
budget: this.budget,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
$.export("$summary", `Successfully created task assignment ${response.id}`);
|
|
75
|
+
return response;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
@@ -7,16 +7,15 @@ import {
|
|
|
7
7
|
export default {
|
|
8
8
|
key: "harvest-create-timesheet-entry",
|
|
9
9
|
name: "Create Timesheet Entry",
|
|
10
|
-
description:
|
|
11
|
-
|
|
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.3",
|
|
10
|
+
description: "Create a new time entry. Two ways to log time, matching the account's Company setting: on **duration-based** accounts (`wants_timestamp_timers` is `false` — the common case) set **Hours** to log a completed entry directly. On **timestamp-based** accounts (`wants_timestamp_timers` is `true`) leave **Hours** blank and use **Started Time**/**Ended Time** instead — leave both time fields blank too to start a running timer now, or set both to log a completed entry with explicit start/end times. Passing Started/Ended Time on a duration-based account is silently ignored by Harvest (it starts a running timer instead) — if that happens, switch to **Hours**. Use **Get Projects** to find a Project ID, **List Tasks** to find a Task ID, and **List Users** to find a User ID. Example (duration-based): call with projectId, taskId, spentDate=\"2026-09-17\", hours=3.5. Example (timestamp-based): the same call with hours omitted and startedTime/endedTime set instead. [See the documentation](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#create-a-time-entry-via-duration) and [start/end time variant](https://help.getharvest.com/api-v2/timesheets-api/timesheets/time-entries/#create-a-time-entry-via-start-and-end-time).",
|
|
11
|
+
version: "1.0.0",
|
|
14
12
|
annotations: {
|
|
15
13
|
destructiveHint: false,
|
|
16
14
|
openWorldHint: true,
|
|
17
15
|
readOnlyHint: false,
|
|
18
16
|
},
|
|
19
17
|
type: "action",
|
|
18
|
+
ai: "optimized",
|
|
20
19
|
props: {
|
|
21
20
|
harvest,
|
|
22
21
|
accountId: {
|
|
@@ -29,57 +28,43 @@ export default {
|
|
|
29
28
|
propDefinition: [
|
|
30
29
|
harvest,
|
|
31
30
|
"projectId",
|
|
32
|
-
(c) => ({
|
|
33
|
-
accountId: c.accountId,
|
|
34
|
-
}),
|
|
35
31
|
],
|
|
36
32
|
},
|
|
37
33
|
taskId: {
|
|
38
34
|
propDefinition: [
|
|
39
35
|
harvest,
|
|
40
36
|
"taskId",
|
|
41
|
-
(c) => ({
|
|
42
|
-
accountId: c.accountId,
|
|
43
|
-
}),
|
|
44
37
|
],
|
|
45
38
|
},
|
|
46
39
|
spentDate: {
|
|
47
40
|
type: "string",
|
|
48
41
|
label: "Spent date (YYYY-MM-DD)",
|
|
49
|
-
description: "The ISO 8601 formatted date on which the time entry was spent.
|
|
42
|
+
description: "The ISO 8601 formatted date on which the time entry was spent, e.g. `2019-07-26`.",
|
|
50
43
|
},
|
|
51
44
|
userId: {
|
|
52
45
|
propDefinition: [
|
|
53
46
|
harvest,
|
|
54
47
|
"userId",
|
|
55
|
-
(c) => ({
|
|
56
|
-
accountId: c.accountId,
|
|
57
|
-
}),
|
|
58
48
|
],
|
|
59
49
|
},
|
|
60
|
-
|
|
61
|
-
type: "
|
|
62
|
-
label: "
|
|
63
|
-
description: "
|
|
64
|
-
|
|
50
|
+
hours: {
|
|
51
|
+
type: "string",
|
|
52
|
+
label: "Hours",
|
|
53
|
+
description: "Duration in hours, e.g. `3.5`. Use this on duration-based accounts (the common case) to log a completed entry in one call. Leave blank if using **Started Time**/**Ended Time** instead.",
|
|
54
|
+
optional: true,
|
|
55
|
+
},
|
|
56
|
+
startedTime: {
|
|
57
|
+
type: "string",
|
|
58
|
+
label: "Started time (H:MM am/pm)",
|
|
59
|
+
description: "Timestamp-based accounts only. The time the entry started, e.g. `8:00am`. Leave this and **Ended Time** blank to start a running timer now instead of logging a completed entry.",
|
|
60
|
+
optional: true,
|
|
61
|
+
},
|
|
62
|
+
endedTime: {
|
|
63
|
+
type: "string",
|
|
64
|
+
label: "Ended time (H:MM am/pm)",
|
|
65
|
+
description: "Timestamp-based accounts only. The time the entry ended, e.g. `5:00pm`. Only used when **Started Time** is also set.",
|
|
66
|
+
optional: true,
|
|
65
67
|
},
|
|
66
|
-
},
|
|
67
|
-
async additionalProps() {
|
|
68
|
-
const props = {};
|
|
69
|
-
if (this.specifyStartEndTime === true) {
|
|
70
|
-
props.startedTime = {
|
|
71
|
-
type: "string",
|
|
72
|
-
label: "Start time(H:MM am/pm)",
|
|
73
|
-
description: "The time the entry started. Defaults to the current time. Example: 8:00am.",
|
|
74
|
-
};
|
|
75
|
-
props.endedTime = {
|
|
76
|
-
type: "string",
|
|
77
|
-
label: "End time(H:MM am/pm)",
|
|
78
|
-
description: "The time the entry ended. Defaults to the current time. Example: 8:00am.",
|
|
79
|
-
optional: true,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
return props;
|
|
83
68
|
},
|
|
84
69
|
async run({ $ }) {
|
|
85
70
|
|
|
@@ -95,17 +80,28 @@ export default {
|
|
|
95
80
|
throw new ConfigurationError("Invalid end time. Ensure format is (H:MM am/pm)");
|
|
96
81
|
}
|
|
97
82
|
|
|
98
|
-
|
|
83
|
+
if (this.endedTime && !this.startedTime) {
|
|
84
|
+
throw new ConfigurationError("Started Time is required when Ended Time is set");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (this.hours && (this.startedTime || this.endedTime)) {
|
|
88
|
+
throw new ConfigurationError("Set either Hours (duration-based accounts) or Started/Ended Time (timestamp-based accounts), not both");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const data = removeNullEntries({
|
|
99
92
|
project_id: this.projectId,
|
|
100
93
|
task_id: this.taskId,
|
|
101
94
|
user_id: this.userId,
|
|
102
95
|
spent_date: this.spentDate,
|
|
96
|
+
hours: this.hours !== undefined && this.hours !== null && this.hours !== ""
|
|
97
|
+
? Number(this.hours)
|
|
98
|
+
: undefined,
|
|
103
99
|
started_time: this.startedTime?.replace(/\s/g, ""),
|
|
104
100
|
ended_time: this.endedTime?.replace(/\s/g, ""),
|
|
105
101
|
});
|
|
106
102
|
const response = await this.harvest.createTimeEntry({
|
|
107
103
|
$,
|
|
108
|
-
|
|
104
|
+
data,
|
|
109
105
|
accountId: this.accountId,
|
|
110
106
|
});
|
|
111
107
|
response && $.export("$summary", "Successfully created time entry");
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-create-user",
|
|
5
|
+
name: "Create User",
|
|
6
|
+
description: "Create a new user in the Harvest account. Example: call with firstName=\"Ian\", lastName=\"Malcolm\", email=\"ian.malcolm@example.com\" to add a new team member. [See the documentation](https://help.getharvest.com/api-v2/users-api/users/users/#create-a-user).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
},
|
|
15
|
+
props: {
|
|
16
|
+
harvest,
|
|
17
|
+
accountId: {
|
|
18
|
+
propDefinition: [
|
|
19
|
+
harvest,
|
|
20
|
+
"accountId",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
firstName: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"firstName",
|
|
27
|
+
],
|
|
28
|
+
optional: false,
|
|
29
|
+
},
|
|
30
|
+
lastName: {
|
|
31
|
+
propDefinition: [
|
|
32
|
+
harvest,
|
|
33
|
+
"lastName",
|
|
34
|
+
],
|
|
35
|
+
optional: false,
|
|
36
|
+
},
|
|
37
|
+
email: {
|
|
38
|
+
propDefinition: [
|
|
39
|
+
harvest,
|
|
40
|
+
"email",
|
|
41
|
+
],
|
|
42
|
+
optional: false,
|
|
43
|
+
},
|
|
44
|
+
timezone: {
|
|
45
|
+
propDefinition: [
|
|
46
|
+
harvest,
|
|
47
|
+
"timezone",
|
|
48
|
+
],
|
|
49
|
+
description: "The user's IANA timezone name, e.g. `America/Chicago`. Defaults to the company timezone if omitted.",
|
|
50
|
+
},
|
|
51
|
+
isContractor: {
|
|
52
|
+
propDefinition: [
|
|
53
|
+
harvest,
|
|
54
|
+
"isContractor",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
isActive: {
|
|
58
|
+
propDefinition: [
|
|
59
|
+
harvest,
|
|
60
|
+
"isActive",
|
|
61
|
+
],
|
|
62
|
+
description: "Whether the user is active.",
|
|
63
|
+
},
|
|
64
|
+
weeklyCapacity: {
|
|
65
|
+
propDefinition: [
|
|
66
|
+
harvest,
|
|
67
|
+
"weeklyCapacity",
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
defaultHourlyRate: {
|
|
71
|
+
propDefinition: [
|
|
72
|
+
harvest,
|
|
73
|
+
"defaultHourlyRate",
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
costRate: {
|
|
77
|
+
type: "string",
|
|
78
|
+
label: "Cost Rate",
|
|
79
|
+
description: "Cost rate, decimal, e.g. `100` or `100.00`.",
|
|
80
|
+
optional: true,
|
|
81
|
+
},
|
|
82
|
+
accessRoles: {
|
|
83
|
+
propDefinition: [
|
|
84
|
+
harvest,
|
|
85
|
+
"accessRoles",
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
async run({ $ }) {
|
|
90
|
+
const response = await this.harvest.createUser({
|
|
91
|
+
$,
|
|
92
|
+
accountId: this.accountId,
|
|
93
|
+
data: {
|
|
94
|
+
first_name: this.firstName,
|
|
95
|
+
last_name: this.lastName,
|
|
96
|
+
email: this.email,
|
|
97
|
+
timezone: this.timezone,
|
|
98
|
+
is_contractor: this.isContractor,
|
|
99
|
+
is_active: this.isActive,
|
|
100
|
+
weekly_capacity: this.weeklyCapacity,
|
|
101
|
+
default_hourly_rate: this.defaultHourlyRate,
|
|
102
|
+
cost_rate: this.costRate,
|
|
103
|
+
access_roles: this.accessRoles,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
$.export("$summary", `Successfully created user ${response.id}: ${response.first_name} ${response.last_name}`);
|
|
107
|
+
return response;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-create-user-assignment",
|
|
5
|
+
name: "Create User Assignment",
|
|
6
|
+
description: "Assign a user to a project. Use **Get Projects** to find a project ID, and **List Users** to find user IDs. Example: call with projectId and userId set to staff that person on the project. [See the documentation](https://help.getharvest.com/api-v2/projects-api/projects/user-assignments/#create-a-user-assignment).",
|
|
7
|
+
version: "0.0.1",
|
|
8
|
+
type: "action",
|
|
9
|
+
ai: "optimized",
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: false,
|
|
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
|
+
userId: {
|
|
30
|
+
propDefinition: [
|
|
31
|
+
harvest,
|
|
32
|
+
"userId",
|
|
33
|
+
],
|
|
34
|
+
optional: false,
|
|
35
|
+
},
|
|
36
|
+
isActive: {
|
|
37
|
+
propDefinition: [
|
|
38
|
+
harvest,
|
|
39
|
+
"isActive",
|
|
40
|
+
],
|
|
41
|
+
description: "Whether the user assignment is active.",
|
|
42
|
+
},
|
|
43
|
+
isProjectManager: {
|
|
44
|
+
propDefinition: [
|
|
45
|
+
harvest,
|
|
46
|
+
"isProjectManager",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
useDefaultRates: {
|
|
50
|
+
propDefinition: [
|
|
51
|
+
harvest,
|
|
52
|
+
"useDefaultRates",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
hourlyRate: {
|
|
56
|
+
propDefinition: [
|
|
57
|
+
harvest,
|
|
58
|
+
"userAssignmentHourlyRate",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
budget: {
|
|
62
|
+
propDefinition: [
|
|
63
|
+
harvest,
|
|
64
|
+
"userAssignmentBudget",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
async run({ $ }) {
|
|
69
|
+
const response = await this.harvest.createUserAssignment({
|
|
70
|
+
$,
|
|
71
|
+
projectId: this.projectId,
|
|
72
|
+
accountId: this.accountId,
|
|
73
|
+
data: {
|
|
74
|
+
user_id: this.userId,
|
|
75
|
+
is_active: this.isActive,
|
|
76
|
+
is_project_manager: this.isProjectManager,
|
|
77
|
+
use_default_rates: this.useDefaultRates,
|
|
78
|
+
hourly_rate: this.hourlyRate,
|
|
79
|
+
budget: this.budget,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
$.export("$summary", `Successfully created user assignment ${response.id}`);
|
|
83
|
+
return response;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import harvest from "../../harvest.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "harvest-delete-invoice",
|
|
5
|
+
name: "Delete Invoice",
|
|
6
|
+
description: "Permanently delete an invoice. Use **List Invoices** to find a valid ID. Example: call with invoiceId set to a draft invoice's ID to remove it before it's sent. [See the documentation](https://help.getharvest.com/api-v2/invoices-api/invoices/invoices/#delete-an-invoice).",
|
|
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
|
+
invoiceId: {
|
|
24
|
+
propDefinition: [
|
|
25
|
+
harvest,
|
|
26
|
+
"invoiceId",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ $ }) {
|
|
31
|
+
await this.harvest.deleteInvoice({
|
|
32
|
+
$,
|
|
33
|
+
invoiceId: this.invoiceId,
|
|
34
|
+
accountId: this.accountId,
|
|
35
|
+
});
|
|
36
|
+
$.export("$summary", `Successfully deleted invoice ${this.invoiceId}`);
|
|
37
|
+
},
|
|
38
|
+
};
|