-
Notifications
You must be signed in to change notification settings - Fork 0
/
yearly_report.go
116 lines (105 loc) · 3.13 KB
/
yearly_report.go
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
package timesheet
import (
"time"
"github.com/vshn/odootools/pkg/odoo"
"github.com/vshn/odootools/pkg/odoo/model"
)
type YearlyReport struct {
MonthlyReports []BalanceReport
Employee model.Employee
Year int
Summary YearlySummary
}
type YearlySummary struct {
TotalOvertime time.Duration
TotalExcused time.Duration
TotalWorked time.Duration
TotalLeaves float64
}
type YearlyReportBuilder struct {
year int
payslips model.PayslipList
attendances model.AttendanceList
leaves odoo.List[model.Leave]
employee model.Employee
contracts model.ContractList
clock func() time.Time
}
func NewYearlyReporter(attendances model.AttendanceList, leaves odoo.List[model.Leave], employee model.Employee, contracts model.ContractList, payslips model.PayslipList) *YearlyReportBuilder {
return &YearlyReportBuilder{
payslips: payslips,
attendances: attendances,
leaves: leaves,
employee: employee,
contracts: contracts,
clock: time.Now,
}
}
func (r *YearlyReportBuilder) CalculateYearlyReport() (YearlyReport, error) {
reports := make([]BalanceReport, 0)
now := r.clock()
max := 12
if r.year >= now.Year() {
max = int(now.Month())
}
min := 1
if startDate, found := r.getEarliestStartContractDate(); found && startDate.Year() == now.Year() && r.year == now.Year() {
min = int(startDate.Month())
}
for _, month := range makeRange(min, max) {
tz := DefaultTimeZone
payslip := r.payslips.FilterInMonth(time.Date(r.year, time.Month(month), 5, 0, 0, 0, 0, time.UTC))
if payslip != nil {
tz = payslip.TimeZone.LocationOrDefault(tz)
}
start := time.Date(r.year, time.Month(month), 1, 0, 0, 0, 0, tz)
end := start.AddDate(0, 1, 0)
monthlyReportBuilder := NewReporter(r.attendances, r.leaves, r.employee, r.contracts)
monthlyReportBuilder.clock = r.clock
monthlyReport, err := monthlyReportBuilder.CalculateReport(start, end)
if err != nil {
return YearlyReport{}, err
}
balanceReportBuilder := NewBalanceReportBuilder(monthlyReport, r.payslips)
balanceReport, err := balanceReportBuilder.CalculateBalanceReport()
if err != nil {
return YearlyReport{}, err
}
reports = append(reports, balanceReport)
}
yearlyReport := YearlyReport{
MonthlyReports: reports,
Year: r.year,
Employee: r.employee,
}
summary := YearlySummary{}
for _, month := range reports {
summary.TotalOvertime += month.Report.Summary.TotalOvertime
summary.TotalExcused += month.Report.Summary.TotalExcusedTime
summary.TotalWorked += month.Report.Summary.TotalWorkedTime
summary.TotalLeaves += month.Report.Summary.TotalLeave
}
yearlyReport.Summary = summary
return yearlyReport, nil
}
func makeRange(min, max int) []int {
a := make([]int, max-min+1)
for i := range a {
a[i] = min + i
}
return a
}
func (r *YearlyReportBuilder) getEarliestStartContractDate() (time.Time, bool) {
now := r.clock()
start := now
for _, contract := range r.contracts.Items {
if contract.Start.Before(start) {
start = contract.Start.Time
}
}
return start, start != now
}
func (r *YearlyReportBuilder) SetYear(year int) *YearlyReportBuilder {
r.year = year
return r
}