diff --git a/README.md b/README.md index 878d501..79d3bb5 100644 --- a/README.md +++ b/README.md @@ -58,21 +58,27 @@ The configuration must be a `.yml` file (specified by the `--config` flag) with # PagerDuty auth token pdAuthToken: 12345 -# Rotation starting time -rotationStartHour: 08:00:00 - -# Currency to be shown when calculating the daily rates -currency: £ - -# Prices assigned to each day type -# Three types must be specified: weekday, weekend and bankholiday +# Rotation general information +rotationInfo: + dailyRotationStartsAt: 8 + checkRotationChangeEvery: 30 # minutes + +# Rotation excluded hours by day type +rotationExcludedHours: + - day: weekday + excludedStartsAt: 9 + excludedEndsAt: 17 + +# Rotation prices by day type rotationPrices: - - type: weekday - price: 1 - - type: weekend - price: 2 - - type: bankholiday - price: 2 + currency: £ + daysInfo: + - day: weekday + price: 1 + - day: weekend + price: 2 + - day: bankholiday + price: 2 # List of users to be considered for the rotation # Each one should be specifying a calendar for the bank holidays @@ -84,7 +90,7 @@ rotationUsers: - name: "User 2" holidaysCalendar: uk userId: P22A22B - - name: "Roger Solé Navarro" + - name: "Roger Solé" holidaysCalendar: sp_premia userId: P33A33B @@ -110,4 +116,4 @@ schedulesToIgnore: ## Roadmap - Add support for calendars loaded from outside the application -- Generate a summary for all the users involved in the rotations reported at the end +- Enable input to select month (concrete dates) to generate the report for diff --git a/cmd/generate_report.go b/cmd/generate_report.go index 43e80fb..37d0e51 100644 --- a/cmd/generate_report.go +++ b/cmd/generate_report.go @@ -55,6 +55,7 @@ func processArguments() InputData { lastMonth := now.AddDate(0, -1, 0) startDate := time.Date(lastMonth.Year(), lastMonth.Month(), 1, 0, 0, 0, 0, time.UTC) endDate := startDate.AddDate(0, 1, 0) + endDate = endDate.Add(time.Hour * time.Duration(Config.RotationInfo.DailyRotationStartsAt)) log.Printf("startDate: %s, endDate: %s", startDate, endDate) if len(schedules) == 1 && schedules[0] == "all" { @@ -89,13 +90,14 @@ func generateReport(cmd *cobra.Command, args []string) error { SchedulesData: make([]*report.ScheduleData, 0), } - weekDayHourlyPrice, weekendDayHourlyPrice, bhDayHourlyPrice, err := getPrices() + pricesInfo, err := generatePricesInfo() if err != nil { return err } - log.Println(fmt.Sprintf("Hourly prices - Week day: %f, Weekend day: %f, Bank holiday: %f", - weekDayHourlyPrice, weekendDayHourlyPrice, bhDayHourlyPrice)) + log.Println(fmt.Sprintf("Hourly prices (in %s) - Week day: %v (%vh), Weekend day: %v (%vh), Bank holiday: %v (%vh)", + Config.RotationPrices.Currency, pricesInfo.WeekDayHourlyPrice, pricesInfo.HoursWeekDay, pricesInfo.WeekendDayHourlyPrice, + pricesInfo.HoursWeekendDay, pricesInfo.BhDayHourlyPrice, pricesInfo.HoursBhDay)) for _, scheduleID := range input.schedules { log.Printf("Loading information for the schedule '%s'", scheduleID) @@ -109,8 +111,7 @@ func generateReport(cmd *cobra.Command, args []string) error { return err } - scheduleData, err := generateScheduleData(scheduleInfo, usersRotationData, - weekDayHourlyPrice, weekendDayHourlyPrice, bhDayHourlyPrice) + scheduleData, err := generateScheduleData(scheduleInfo, usersRotationData, pricesInfo) if err != nil { return err } @@ -118,14 +119,14 @@ func generateReport(cmd *cobra.Command, args []string) error { printableData.SchedulesData = append(printableData.SchedulesData, scheduleData) } - summaryPrintableData := calculateSummaryData(printableData.SchedulesData) + summaryPrintableData := calculateSummaryData(printableData.SchedulesData, pricesInfo) printableData.UsersSchedulesSummary = summaryPrintableData var reportWriter report.Writer if outputFormat == "pdf" { - reportWriter = report.NewPDFReport(Config.Currency) + reportWriter = report.NewPDFReport(Config.RotationPrices.Currency) } else { - reportWriter = report.NewConsoleReport(Config.Currency) + reportWriter = report.NewConsoleReport(Config.RotationPrices.Currency) } message, err := reportWriter.GenerateReport(printableData) if err != nil { @@ -138,7 +139,7 @@ func generateReport(cmd *cobra.Command, args []string) error { return nil } -func calculateSummaryData(data []*report.ScheduleData) []*report.UserSchedulesSummary { +func calculateSummaryData(data []*report.ScheduleData, pricesInfo *PricesInfo) []*report.UserSchedulesSummary { usersSummary := make(map[string]*report.UserSchedulesSummary) @@ -164,6 +165,9 @@ func calculateSummaryData(data []*report.ScheduleData) []*report.UserSchedulesSu result := make([]*report.UserSchedulesSummary, 0) for _, userSummary := range usersSummary { + userSummary.NumWorkDays = userSummary.NumWorkHours / float32(pricesInfo.HoursWeekDay) + userSummary.NumWeekendDays = userSummary.NumWeekendHours / float32(pricesInfo.HoursWeekendDay) + userSummary.NumBankHolidaysDays = userSummary.NumBankHolidaysHours / float32(pricesInfo.HoursBhDay) result = append(result, userSummary) } @@ -224,7 +228,7 @@ func getUsersRotationData(scheduleInfo *api.ScheduleInfo) (api.ScheduleUserRotat } func generateScheduleData(scheduleInfo *api.ScheduleInfo, usersRotationData api.ScheduleUserRotationData, - weekDayHourlyPrice, weekendDayHourlyPrice, bhDayHourlyPrice float32) (*report.ScheduleData, error) { + pricesInfo *PricesInfo) (*report.ScheduleData, error) { scheduleData := &report.ScheduleData{ ID: scheduleInfo.ID, @@ -235,7 +239,8 @@ func generateScheduleData(scheduleInfo *api.ScheduleInfo, usersRotationData api. for userID, userRotaInfo := range usersRotationData { rotationUserConfig, err := Config.FindRotationUserInfoByID(userID) if err != nil { - return nil, err + log.Println("Error:", err) + continue } calendarName := fmt.Sprintf("%s-%d", rotationUserConfig.HolidaysCalendar, scheduleInfo.Start.Year()) @@ -249,23 +254,20 @@ func generateScheduleData(scheduleInfo *api.ScheduleInfo, usersRotationData api. } for _, period := range userRotaInfo.Periods { + currentMonth := period.Start.Month() currentDate := period.Start for currentDate.Before(period.End) { - if userCalendar.IsDateBankHoliday(currentDate) { - scheduleUserData.NumBankHolidaysHours += 0.5 - } else if userCalendar.IsWeekend(currentDate) { - scheduleUserData.NumWeekendHours += 0.5 - } else { - scheduleUserData.NumWorkHours += 0.5 - } - - currentDate = currentDate.Add(time.Minute * 30) + updateDataForDate(&userCalendar, scheduleUserData, currentMonth, currentDate) + currentDate = currentDate.Add(time.Minute * time.Duration(Config.RotationInfo.CheckRotationChangeEvery)) } } - scheduleUserData.TotalAmountWorkHours = scheduleUserData.NumWorkHours * weekDayHourlyPrice - scheduleUserData.TotalAmountWeekendHours = scheduleUserData.NumWeekendHours * weekendDayHourlyPrice - scheduleUserData.TotalAmountBankHolidaysHours = scheduleUserData.NumBankHolidaysHours * bhDayHourlyPrice + scheduleUserData.NumWorkDays = scheduleUserData.NumWorkHours / float32(pricesInfo.HoursWeekDay) + scheduleUserData.NumWeekendDays = scheduleUserData.NumWeekendHours / float32(pricesInfo.HoursWeekendDay) + scheduleUserData.NumBankHolidaysDays = scheduleUserData.NumBankHolidaysHours / float32(pricesInfo.HoursBhDay) + scheduleUserData.TotalAmountWorkHours = scheduleUserData.NumWorkHours * pricesInfo.WeekDayHourlyPrice + scheduleUserData.TotalAmountWeekendHours = scheduleUserData.NumWeekendHours * pricesInfo.WeekendDayHourlyPrice + scheduleUserData.TotalAmountBankHolidaysHours = scheduleUserData.NumBankHolidaysHours * pricesInfo.BhDayHourlyPrice scheduleUserData.TotalAmount = scheduleUserData.TotalAmountWorkHours + scheduleUserData.TotalAmountWeekendHours + scheduleUserData.TotalAmountBankHolidaysHours @@ -275,20 +277,105 @@ func generateScheduleData(scheduleInfo *api.ScheduleInfo, usersRotationData api. return scheduleData, nil } -func getPrices() (float32, float32, float32, error) { +func updateDataForDate(calendar *configuration.BHCalendar, data *report.ScheduleUser, currentMonth time.Month, date time.Time) { + + if date.Hour() < Config.RotationInfo.DailyRotationStartsAt { + newDate := date.Add(time.Hour * time.Duration(-(date.Hour() + 1))) // move to yesterday night to determine which kind of day it was + // if yesterday night was last month, ignore the date + if newDate.Month() == currentMonth { + updateDataForDate(calendar, data, currentMonth, newDate) + } + } else { + if calendar.IsDateBankHoliday(date) { + excludedHours, _ := Config.FindRotationExcludedHoursByDay("bankholiday") + if excludedHours == nil { + //fmt.Printf("%s - Month: %d, time: %v -- bank holiday\n", data.Name, currentMonth, date) + data.NumBankHolidaysHours += 0.5 + return + } + + if date.Hour() < excludedHours.ExcludedEndsAt && date.Hour() >= excludedHours.ExcludedEndsAt { + //fmt.Printf("%s - Month: %d, time: %v -- bank holiday non excluded hours\n", data.Name, currentMonth, date) + data.NumBankHolidaysHours += 0.5 + } + } else if calendar.IsWeekend(date) { + excludedHours, _ := Config.FindRotationExcludedHoursByDay("weekend") + if excludedHours == nil { + //fmt.Printf("%s - Month: %d, time: %v -- weekend\n", data.Name, currentMonth, date) + data.NumWeekendHours += 0.5 + return + } + + if date.Hour() < excludedHours.ExcludedEndsAt && date.Hour() >= excludedHours.ExcludedEndsAt { + //fmt.Printf("%s - Month: %d, time: %v -- weekend non excluded hours\n", data.Name, currentMonth, date) + data.NumWeekendHours += 0.5 + } + } else { + excludedHours, _ := Config.FindRotationExcludedHoursByDay("weekday") + if excludedHours == nil { + //fmt.Printf("%s - Month: %d, time: %v -- weekday\n", data.Name, currentMonth, date) + data.NumWorkHours += 0.5 + return + } + + if date.Hour() < excludedHours.ExcludedStartsAt || date.Hour() >= excludedHours.ExcludedEndsAt { + //fmt.Printf("%s - Month: %d, time: %v -- weekday non excluded hours\n", data.Name, currentMonth, date) + data.NumWorkHours += 0.5 + } + } + } +} + +type PricesInfo struct { + WeekDayHourlyPrice float32 + HoursWeekDay int + WeekendDayHourlyPrice float32 + HoursWeekendDay int + BhDayHourlyPrice float32 + HoursBhDay int +} + +func generatePricesInfo() (*PricesInfo, error) { weekDayPrice, err := Config.FindPriceByDay("weekday") if err != nil { - return 0, 0, 0, err + return nil, err + } + excludedWeekDayHoursAmount := 0 + excludedHours, _ := Config.FindRotationExcludedHoursByDay("weekday") + if excludedHours != nil { + excludedWeekDayHoursAmount = excludedHours.ExcludedEndsAt - excludedHours.ExcludedStartsAt } + weekDayWorkingHours := 24 - excludedWeekDayHoursAmount + weekendDayPrice, err := Config.FindPriceByDay("weekend") if err != nil { - return 0, 0, 0, err + return nil, err } + excludedWeekendDayHoursAmount := 0 + excludedHours, _ = Config.FindRotationExcludedHoursByDay("weekend") + if excludedHours != nil { + excludedWeekendDayHoursAmount = excludedHours.ExcludedEndsAt - excludedHours.ExcludedStartsAt + } + weekendDayWorkingHours := 24 - excludedWeekendDayHoursAmount + bhDayPrice, err := Config.FindPriceByDay("bankholiday") if err != nil { - return 0, 0, 0, err + return nil, err } - - return float32(*weekDayPrice) / 24, float32(*weekendDayPrice) / 24, float32(*bhDayPrice) / 24, nil + excludedBhDayHoursAmount := 0 + excludedHours, _ = Config.FindRotationExcludedHoursByDay("bankholiday") + if excludedHours != nil { + excludedBhDayHoursAmount = excludedHours.ExcludedEndsAt - excludedHours.ExcludedStartsAt + } + bhWorkingHours := 24 - excludedBhDayHoursAmount + + return &PricesInfo{ + WeekDayHourlyPrice: float32(*weekDayPrice) / float32(weekDayWorkingHours), + HoursWeekDay: weekDayWorkingHours, + WeekendDayHourlyPrice: float32(*weekendDayPrice) / float32(weekendDayWorkingHours), + HoursWeekendDay: weekendDayWorkingHours, + BhDayHourlyPrice: float32(*bhDayPrice) / float32(bhWorkingHours), + HoursBhDay: bhWorkingHours, + }, nil } diff --git a/configuration/config.go b/configuration/config.go index 0d47e74..78bceb3 100644 --- a/configuration/config.go +++ b/configuration/config.go @@ -10,27 +10,45 @@ type RotationUser struct { HolidaysCalendar string } -type RotationPrice struct { - Type string +type RotationPriceDay struct { + Day string Price int } +type RotationPrices struct { + Currency string + DaysInfo []RotationPriceDay +} + +type RotationExcludedHoursDay struct { + Day string + ExcludedStartsAt int + ExcludedEndsAt int +} + +type RotationInfo struct { + DailyRotationStartsAt int + CheckRotationChangeEvery int +} + type Configuration struct { - PdAuthToken string - RotationStartHour string - RotationUsers []RotationUser - RotationPrices []RotationPrice - Currency string - SchedulesToIgnore []string + PdAuthToken string + RotationInfo RotationInfo + RotationExcludedHours []RotationExcludedHoursDay + RotationPrices RotationPrices + RotationUsers []RotationUser + SchedulesToIgnore []string cacheRotationUsers map[string]*RotationUser cacheRotationPrices map[string]int + cacheExcludedByDay map[string]*RotationExcludedHoursDay } func New() *Configuration { return &Configuration{ cacheRotationUsers: make(map[string]*RotationUser), cacheRotationPrices: make(map[string]int), + cacheExcludedByDay: make(map[string]*RotationExcludedHoursDay), } } @@ -39,9 +57,9 @@ func (c *Configuration) FindPriceByDay(dayType string) (*int, error) { return &price, nil } - for _, rotationPrice := range c.RotationPrices { - if rotationPrice.Type == dayType { - c.cacheRotationPrices[rotationPrice.Type] = rotationPrice.Price + for _, rotationPrice := range c.RotationPrices.DaysInfo { + if rotationPrice.Day == dayType { + c.cacheRotationPrices[rotationPrice.Day] = rotationPrice.Price return &rotationPrice.Price, nil } } @@ -49,6 +67,21 @@ func (c *Configuration) FindPriceByDay(dayType string) (*int, error) { return nil, fmt.Errorf("day type %s not found", dayType) } +func (c *Configuration) FindRotationExcludedHoursByDay(dayType string) (*RotationExcludedHoursDay, error) { + if excludedInfo, ok := c.cacheExcludedByDay[dayType]; ok { + return excludedInfo, nil + } + + for _, rotationExcludedHours := range c.RotationExcludedHours { + if rotationExcludedHours.Day == dayType { + c.cacheExcludedByDay[rotationExcludedHours.Day] = &rotationExcludedHours + return &rotationExcludedHours, nil + } + } + + return nil, fmt.Errorf("day type %s not found", dayType) +} + func (c *Configuration) FindRotationUserInfoByID(userID string) (*RotationUser, error) { if rotationUser, ok := c.cacheRotationUsers[userID]; ok { return rotationUser, nil diff --git a/report/console_report.go b/report/console_report.go index 1b9ae5a..b87f263 100644 --- a/report/console_report.go +++ b/report/console_report.go @@ -2,6 +2,8 @@ package report import ( "fmt" + "sort" + "strings" "time" ) @@ -34,15 +36,27 @@ func (r *consoleReport) GenerateReport(data *PrintableData) (string, error) { fmt.Println(separator) fmt.Println(fmt.Sprintf(rowFormat, "USER", "WEEKDAY", "WEEKEND", "BANK HOLIDAY", "TOTAL WEEKDAY", "TOTAL WEEKEND", "TOTAL BANK HOLIDAY", "TOTAL")) fmt.Println(fmt.Sprintf(rowFormat, "", "HOURS", "HOURS", "HOURS", "AMOUNT", "AMOUNT", "AMOUNT", "AMOUNT")) + fmt.Println(fmt.Sprintf(rowFormat, "", "DAYS", "DAYS", "DAYS", "", "", "", "")) fmt.Println(separator) + sort.Slice(scheduleData.RotaUsers, func(i, j int) bool { + return strings.Compare(scheduleData.RotaUsers[i].Name, scheduleData.RotaUsers[j].Name) < 1 + }) + for _, userData := range scheduleData.RotaUsers { fmt.Println(fmt.Sprintf(rowFormat, userData.Name, - userData.NumWorkHours, userData.NumWeekendHours, userData.NumBankHolidaysHours, + fmt.Sprintf("%v h", userData.NumWorkHours), + fmt.Sprintf("%v h", userData.NumWeekendHours), + fmt.Sprintf("%v h", userData.NumBankHolidaysHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWorkHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWeekendHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountBankHolidaysHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmount))) + fmt.Println(fmt.Sprintf(rowFormat, "_________________________", + fmt.Sprintf("%.1f d", userData.NumWorkDays), + fmt.Sprintf("%.1f d", userData.NumWeekendDays), + fmt.Sprintf("%.1f d", userData.NumBankHolidaysDays), + "_____________", "_____________", "__________________", "_________")) } fmt.Println(separator) } @@ -53,15 +67,27 @@ func (r *consoleReport) GenerateReport(data *PrintableData) (string, error) { fmt.Println(separator) fmt.Println(fmt.Sprintf(rowFormat, "USER", "WEEKDAY", "WEEKEND", "BANK HOLIDAY", "TOTAL WEEKDAY", "TOTAL WEEKEND", "TOTAL BANK HOLIDAY", "TOTAL")) fmt.Println(fmt.Sprintf(rowFormat, "", "HOURS", "HOURS", "HOURS", "AMOUNT", "AMOUNT", "AMOUNT", "AMOUNT")) + fmt.Println(fmt.Sprintf(rowFormat, "", "DAYS", "DAYS", "DAYS", "", "", "", "")) fmt.Println(separator) + sort.Slice(data.UsersSchedulesSummary, func(i, j int) bool { + return strings.Compare(data.UsersSchedulesSummary[i].Name, data.UsersSchedulesSummary[j].Name) < 1 + }) + for _, userData := range data.UsersSchedulesSummary { fmt.Println(fmt.Sprintf(rowFormat, userData.Name, - userData.NumWorkHours, userData.NumWeekendHours, userData.NumBankHolidaysHours, + fmt.Sprintf("%v h", userData.NumWorkHours), + fmt.Sprintf("%v h", userData.NumWeekendHours), + fmt.Sprintf("%v h", userData.NumBankHolidaysHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWorkHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWeekendHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmountBankHolidaysHours), fmt.Sprintf("%s%v", r.currency, userData.TotalAmount))) + fmt.Println(fmt.Sprintf(rowFormat, "_________________________", + fmt.Sprintf("%.1f d", userData.NumWorkDays), + fmt.Sprintf("%.1f d", userData.NumWeekendDays), + fmt.Sprintf("%.1f d", userData.NumBankHolidaysDays), + "_____________", "_____________", "__________________", "_________")) } fmt.Println(separator) diff --git a/report/pdf_report.go b/report/pdf_report.go index 9f17c14..99cf318 100644 --- a/report/pdf_report.go +++ b/report/pdf_report.go @@ -5,6 +5,10 @@ import ( "log" "time" + "sort" + + "strings" + "github.com/jung-kurt/gofpdf" "github.com/mitchellh/go-homedir" ) @@ -57,19 +61,38 @@ func (r *pdfReport) GenerateReport(data *PrintableData) (string, error) { pdf.Ln(3) pdf.CellFormat(0, 5, fmt.Sprintf(matrixRowFormat, "", "HOURS", "HOURS", "HOURS", "AMOUNT", "AMOUNT", "AMOUNT", "AMOUNT"), + "", 0, "L", false, 0, "") + pdf.Ln(3) + pdf.CellFormat(0, 5, + fmt.Sprintf(matrixRowFormat, "", "DAYS", "DAYS", "DAYS", "", "", "", ""), "B", 0, "L", false, 0, "") pdf.Ln(5) pdf.SetFont("Courier", "", 9) + + sort.Slice(scheduleData.RotaUsers, func(i, j int) bool { + return strings.Compare(scheduleData.RotaUsers[i].Name, scheduleData.RotaUsers[j].Name) < 1 + }) + for _, userData := range scheduleData.RotaUsers { pdf.CellFormat(0, 5, fmt.Sprintf(matrixRowFormat, tr(userData.Name), - userData.NumWorkHours, userData.NumWeekendHours, userData.NumBankHolidaysHours, + fmt.Sprintf("%v h", userData.NumWorkHours), + fmt.Sprintf("%v h", userData.NumWeekendHours), + fmt.Sprintf("%v h", userData.NumBankHolidaysHours), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWorkHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWeekendHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountBankHolidaysHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmount))), "", 0, "L", false, 0, "") + pdf.Ln(3) + pdf.CellFormat(0, 5, + fmt.Sprintf(matrixRowFormat, "_______________________", + fmt.Sprintf("%.1f d", userData.NumWorkDays), + fmt.Sprintf("%.1f d", userData.NumWeekendDays), + fmt.Sprintf("%.1f d", userData.NumBankHolidaysDays), + "__________", "__________", "_____________", "_________"), + "", 0, "L", false, 0, "") pdf.Ln(5) } @@ -90,19 +113,37 @@ func (r *pdfReport) GenerateReport(data *PrintableData) (string, error) { pdf.Ln(3) pdf.CellFormat(0, 5, fmt.Sprintf(matrixRowFormat, "", "HOURS", "HOURS", "HOURS", "AMOUNT", "AMOUNT", "AMOUNT", "AMOUNT"), + "", 0, "L", false, 0, "") + pdf.Ln(3) + pdf.CellFormat(0, 5, + fmt.Sprintf(matrixRowFormat, "", "DAYS", "DAYS", "DAYS", "", "", "", ""), "B", 0, "L", false, 0, "") pdf.Ln(5) + sort.Slice(data.UsersSchedulesSummary, func(i, j int) bool { + return strings.Compare(data.UsersSchedulesSummary[i].Name, data.UsersSchedulesSummary[j].Name) < 1 + }) + pdf.SetFont("Courier", "", 9) for _, userData := range data.UsersSchedulesSummary { pdf.CellFormat(0, 5, fmt.Sprintf(matrixRowFormat, tr(userData.Name), - userData.NumWorkHours, userData.NumWeekendHours, userData.NumBankHolidaysHours, + fmt.Sprintf("%v h", userData.NumWorkHours), + fmt.Sprintf("%v h", userData.NumWeekendHours), + fmt.Sprintf("%v h", userData.NumBankHolidaysHours), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWorkHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountWeekendHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmountBankHolidaysHours)), tr(fmt.Sprintf("%s%v", r.currency, userData.TotalAmount))), "", 0, "L", false, 0, "") + pdf.Ln(3) + pdf.CellFormat(0, 5, + fmt.Sprintf(matrixRowFormat, "_______________________", + fmt.Sprintf("%.1f d", userData.NumWorkDays), + fmt.Sprintf("%.1f d", userData.NumWeekendDays), + fmt.Sprintf("%.1f d", userData.NumBankHolidaysDays), + "__________", "__________", "_____________", "_________"), + "", 0, "L", false, 0, "") pdf.Ln(5) } diff --git a/report/writer.go b/report/writer.go index 9b89436..27e7785 100644 --- a/report/writer.go +++ b/report/writer.go @@ -1,6 +1,8 @@ package report -import "time" +import ( + "time" +) type PrintableData struct { Start time.Time @@ -18,10 +20,13 @@ type ScheduleData struct { type UserSchedulesSummary struct { Name string NumWorkHours float32 + NumWorkDays float32 TotalAmountWorkHours float32 NumWeekendHours float32 + NumWeekendDays float32 TotalAmountWeekendHours float32 NumBankHolidaysHours float32 + NumBankHolidaysDays float32 TotalAmountBankHolidaysHours float32 TotalAmount float32 } @@ -29,10 +34,13 @@ type UserSchedulesSummary struct { type ScheduleUser struct { Name string NumWorkHours float32 + NumWorkDays float32 TotalAmountWorkHours float32 NumWeekendHours float32 + NumWeekendDays float32 TotalAmountWeekendHours float32 NumBankHolidaysHours float32 + NumBankHolidaysDays float32 TotalAmountBankHolidaysHours float32 TotalAmount float32 }