-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathassignment.go
More file actions
213 lines (194 loc) · 5.65 KB
/
assignment.go
File metadata and controls
213 lines (194 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package forecast
import (
"encoding/csv"
"io"
"net/url"
"strconv"
"strings"
"time"
)
type assignmentsContainer struct {
Assignments Assignments `json:"assignments"`
}
// Assignments is a list of assignments
type Assignments []Assignment
// Assignment is a Forecast assignment
type Assignment struct {
ID int `json:"id"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
Allocation int `json:"allocation"`
Notes string `json:"notes"`
HarvestProjectTaskID int `json:"harvest_project_task_id"`
UpdatedAt time.Time `json:"updated_at"`
UpdatedByID int `json:"updated_by_id"`
ProjectID int `json:"project_id"`
PersonID int `json:"person_id"`
PlaceholderID int `json:"placeholder_id"`
RepeatedAssignmentSetID int `json:"repeated_assignment_set_id"`
ActiveOnDaysOff bool `json:"active_on_days_off"`
}
// AssignmentFilter is used to filter assignments
type AssignmentFilter struct {
ProjectID int
PersonID int
StartDate string // Format: YYYY-MM-DD
EndDate string // Format: YYYY-MM-DD
RepeatedAssignmentSetID int
State string // active or archived
}
// Weekdays returns the number of working days between the start date and end date
// of the assignment
func (a *Assignment) Weekdays() int {
return a.WorkingDaysBetween("", "")
}
// WorkingDaysBetween calculates the number of assignment days between the given
// start date and end date
func (a *Assignment) WorkingDaysBetween(startDate string, endDate string) int {
var start *time.Time
if strings.TrimSpace(startDate) != "" {
parsedStart, err := time.Parse("2006-01-02", startDate)
if err == nil {
start = &parsedStart
}
}
var end *time.Time
if strings.TrimSpace(endDate) != "" {
parsedEnd, err := time.Parse("2006-01-02", endDate)
if err == nil {
end = &parsedEnd
}
}
assignmentStart, err := time.Parse("2006-01-02", a.StartDate)
if err != nil {
return 0
}
assignmentEnd, err := time.Parse("2006-01-02", a.EndDate)
if err != nil {
return 0
}
next := assignmentStart
result := 0
for {
if end != nil {
// Don't go past the requested end date
if end.AddDate(0, 0, 1).Before(next) {
break
}
}
// Assignment has not ended
if assignmentEnd.Sub(next).Seconds() < 0 {
break
}
if start != nil {
// Skip assignment dates that are prior to the requested start date
if start.After(next.AddDate(0, 0, -1)) {
next = next.Add(time.Hour * 24)
continue
}
}
switch next.Weekday() {
case time.Monday:
result = result + 1
case time.Tuesday:
result = result + 1
case time.Wednesday:
result = result + 1
case time.Thursday:
result = result + 1
case time.Friday:
result = result + 1
}
next = next.Add(time.Hour * 24)
}
return result
}
// Assignments retrieves all assignments for the Forecast account
func (api *API) Assignments() (Assignments, error) {
container, err := get[assignmentsContainer](api, "assignments")
if err != nil {
return nil, err
}
return container.Assignments, nil
}
// AssignmentsWithFilter retrieves all assignments for the Forecast account
func (api *API) AssignmentsWithFilter(filter AssignmentFilter) (Assignments, error) {
params := ToParams(filter.Values())
container, err := get[assignmentsContainer](api, "assignments"+params)
if err != nil {
return nil, err
}
return container.Assignments, nil
}
// ToParams formats url.Values as a string
func ToParams(values url.Values) string {
if len(values) == 0 {
return ""
}
return "?" + values.Encode()
}
// Values returns the AssignmentFilter as a url.Values result
func (filter *AssignmentFilter) Values() url.Values {
result := url.Values{}
if filter.ProjectID != 0 {
result.Set("project_id", strconv.Itoa(filter.ProjectID))
}
if filter.PersonID != 0 {
result.Set("person_id", strconv.Itoa(filter.PersonID))
}
if strings.TrimSpace(filter.StartDate) != "" {
result.Set("start_date", filter.StartDate)
}
if strings.TrimSpace(filter.EndDate) != "" {
result.Set("end_date", filter.EndDate)
}
if filter.RepeatedAssignmentSetID != 0 {
result.Set("repeated_assignment_set_id", strconv.Itoa(filter.RepeatedAssignmentSetID))
}
if strings.TrimSpace(filter.State) != "" {
result.Set("state", filter.State)
}
return result
}
// ToCSV writes the projects to the supplied writer in CSV
// format
func (assignments Assignments) ToCSV(w io.Writer) error {
writer := csv.NewWriter(w)
header := []string{
"id",
"start_date",
"end_date",
"allocation",
"notes",
"updated_at",
"updated_by_id",
"project_id",
"person_id",
"placeholder_id",
"repeated_assignment_set_id",
}
err := writer.Write(header)
if err != nil {
return err
}
for _, assignment := range assignments {
var record []string
record = append(record, strconv.Itoa(assignment.ID))
record = append(record, assignment.StartDate)
record = append(record, assignment.EndDate)
record = append(record, strconv.Itoa(assignment.Allocation))
record = append(record, assignment.Notes)
record = append(record, assignment.UpdatedAt.UTC().Format(time.RFC822Z))
record = append(record, strconv.Itoa(assignment.UpdatedByID))
record = append(record, strconv.Itoa(assignment.ProjectID))
record = append(record, strconv.Itoa(assignment.PersonID))
record = append(record, strconv.Itoa(assignment.PlaceholderID))
record = append(record, strconv.Itoa(assignment.RepeatedAssignmentSetID))
err := writer.Write(record)
if err != nil {
return err
}
}
writer.Flush()
return nil
}