-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from vshn/contracts
Query the workload percentage from Odoo
- Loading branch information
Showing
14 changed files
with
398 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package odoo | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
) | ||
|
||
type ContractList []Contract | ||
|
||
type Contract struct { | ||
ID float64 `json:"id"` | ||
Start *Date `json:"date_start"` | ||
End *Date `json:"date_end"` | ||
WorkingSchedule *WorkingSchedule `json:"working_hours"` | ||
} | ||
|
||
func (l ContractList) GetFTERatioForDay(day Date) (float64, error) { | ||
date := day.ToTime() | ||
for _, contract := range l { | ||
start := contract.Start.ToTime().Add(-1 * time.Second) | ||
if contract.End.IsZero() { | ||
// current contract | ||
if start.Before(date) { | ||
return contract.WorkingSchedule.GetFTERatio() | ||
} | ||
continue | ||
} | ||
end := contract.End.ToTime().Add(1 * time.Second) | ||
if start.Before(date) && end.After(date) { | ||
return contract.WorkingSchedule.GetFTERatio() | ||
} | ||
} | ||
return 0, fmt.Errorf("no contract found that covers date: %s", day.String()) | ||
} | ||
|
||
func (c Client) FetchAllContracts(sid string, employeeID int) (ContractList, error) { | ||
return c.readContracts(sid, []Filter{ | ||
[]interface{}{"employee_id", "=", employeeID}, | ||
}) | ||
} | ||
|
||
func (c Client) readContracts(sid string, domainFilters []Filter) (ContractList, error) { | ||
// Prepare "search contract" request | ||
body, err := NewJsonRpcRequest(&ReadModelRequest{ | ||
Model: "hr.contract", | ||
Domain: domainFilters, | ||
Fields: []string{"date_start", "date_end", "working_hours"}, | ||
}).Encode() | ||
if err != nil { | ||
return nil, fmt.Errorf("encoding request: %w", err) | ||
} | ||
|
||
res, err := c.makeRequest(sid, body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
type readResult struct { | ||
Length int `json:"length,omitempty"` | ||
Records []Contract `json:"records,omitempty"` | ||
} | ||
result := &readResult{} | ||
if err := c.unmarshalResponse(res.Body, result); err != nil { | ||
return nil, err | ||
} | ||
return result.Records, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package odoo | ||
|
||
import ( | ||
"strconv" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func newFTESchedule(ratioPercentage int) *WorkingSchedule { | ||
return &WorkingSchedule{ | ||
ID: 0, | ||
Name: strconv.Itoa(ratioPercentage) + "%", | ||
} | ||
} | ||
|
||
func TestContractList_GetFTERatioForDay(t *testing.T) { | ||
tests := map[string]struct { | ||
givenList ContractList | ||
givenDay Date | ||
expectedRatio float64 | ||
expectErr bool | ||
}{ | ||
"GivenEmptyList_WhenNil_ThenReturnErr": { | ||
givenList: nil, | ||
expectErr: true, | ||
}, | ||
"GivenEmptyList_WhenNoContracts_ThenReturnErr": { | ||
givenList: []Contract{}, | ||
expectErr: true, | ||
}, | ||
"GivenListWith1Contract_WhenOpenEnd_ThenReturnRatio": { | ||
givenDay: *newDate(t, "2021-12-04"), | ||
givenList: []Contract{ | ||
{Start: newDate(t, "2021-02-01"), WorkingSchedule: newFTESchedule(100)}, | ||
}, | ||
expectedRatio: 1, | ||
}, | ||
"GivenListWith1Contract_WhenDayBeforeStart_ThenReturnErr": { | ||
givenDay: *newDate(t, "2021-02-01"), | ||
givenList: []Contract{ | ||
{Start: newDate(t, "2021-02-02"), WorkingSchedule: newFTESchedule(100)}, | ||
}, | ||
expectErr: true, | ||
}, | ||
"GivenListWith2Contract_WhenDayBetweenContract_ThenReturnRatioFromTerminatedContract": { | ||
givenDay: *newDate(t, "2021-03-31"), | ||
givenList: []Contract{ | ||
{Start: newDate(t, "2021-02-02"), End: newDate(t, "2021-03-31"), WorkingSchedule: newFTESchedule(90)}, | ||
{Start: newDate(t, "2021-04-01"), WorkingSchedule: newFTESchedule(80)}, | ||
}, | ||
expectedRatio: 0.9, | ||
}, | ||
"GivenListWith2Contract_WhenDayInOpenContract_ThenReturnRatioFromOpenContract": { | ||
givenDay: *newDate(t, "2021-04-01"), | ||
givenList: []Contract{ | ||
{Start: newDate(t, "2021-02-02"), End: newDate(t, "2021-03-31"), WorkingSchedule: newFTESchedule(90)}, | ||
{Start: newDate(t, "2021-04-01"), WorkingSchedule: newFTESchedule(80)}, | ||
}, | ||
expectedRatio: 0.8, | ||
}, | ||
} | ||
for name, tt := range tests { | ||
t.Run(name, func(t *testing.T) { | ||
result, err := tt.givenList.GetFTERatioForDay(tt.givenDay) | ||
if tt.expectErr { | ||
require.Error(t, err) | ||
return | ||
} | ||
require.NoError(t, err) | ||
assert.Equal(t, tt.expectedRatio, result) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package odoo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
var workingScheduleRegex = regexp.MustCompile("(?P<ratio>[0-9]+\\s*%)") | ||
|
||
type WorkingSchedule struct { | ||
ID float64 | ||
Name string | ||
} | ||
|
||
func (s *WorkingSchedule) String() string { | ||
if s == nil { | ||
return "" | ||
} | ||
return s.Name | ||
} | ||
|
||
func (s WorkingSchedule) MarshalJSON() ([]byte, error) { | ||
if s.Name == "" { | ||
return []byte("false"), nil | ||
} | ||
arr := []interface{}{s.ID, s.Name} | ||
return json.Marshal(arr) | ||
} | ||
func (s *WorkingSchedule) UnmarshalJSON(b []byte) error { | ||
var f bool | ||
if err := json.Unmarshal(b, &f); err == nil || string(b) == "false" { | ||
return nil | ||
} | ||
var arr []interface{} | ||
if err := json.Unmarshal(b, &arr); err != nil { | ||
return err | ||
} | ||
if len(arr) >= 2 { | ||
if v, ok := arr[1].(string); ok { | ||
*s = WorkingSchedule{ | ||
ID: arr[0].(float64), | ||
Name: v, | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// GetFTERatio tries to extract the FTE ratio from the name of the schedule. | ||
// It returns an error if it could not find a match | ||
func (s *WorkingSchedule) GetFTERatio() (float64, error) { | ||
match := workingScheduleRegex.FindStringSubmatch(s.Name) | ||
if len(match) > 0 { | ||
v := match[0] | ||
v = strings.TrimSpace(v) | ||
v = strings.ReplaceAll(v, " ", "") // there might be spaces in between | ||
v = strings.ReplaceAll(v, "%", "") | ||
ratio, err := strconv.Atoi(v) | ||
return float64(ratio) / 100, err | ||
} | ||
return 0, fmt.Errorf("could not find FTE ratio in name: '%s'", s.Name) | ||
} |
Oops, something went wrong.