fix: resolve go vet error and dayStart logic in ComputeDailyTotals
- Fix 'string(d)' int-to-rune conversion in rpg_test.go by using fmt.Sprintf - Fix ComputeDailyTotals dayStart logic: initial state should be StateWorking when dayStart > 0, correctly counting work from dayStart to first out event - Update README project structure to reflect new domain/handler/repo layout - Implement missing achievements: rpg_pioneer (on RPG enable) and salary_setter (on first rate set) - Add tryUnlockAchievement helper to Handler
This commit is contained in:
95
internal/handler/salary.go
Normal file
95
internal/handler/salary.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-telegram/bot/models"
|
||||
|
||||
"worktimeBot/internal/domain"
|
||||
)
|
||||
|
||||
// -- Command --
|
||||
|
||||
func (h *Handler) handleSalary(ctx context.Context, msg *models.Message, user *domain.User) {
|
||||
text, err := h.buildSalaryEstimate(user)
|
||||
if err != nil {
|
||||
h.sendText(ctx, msg.Chat.ID, err.Error())
|
||||
return
|
||||
}
|
||||
h.sendWithKB(ctx, msg.Chat.ID, text, backKeyboard())
|
||||
}
|
||||
|
||||
// -- Callback --
|
||||
|
||||
func (h *Handler) salaryCallback(ctx context.Context, chatID int64, msgID int, cbID string, user *domain.User) {
|
||||
defer h.answerCb(ctx, cbID)
|
||||
text, err := h.buildSalaryEstimate(user)
|
||||
if err != nil {
|
||||
text = err.Error()
|
||||
}
|
||||
kb := backKeyboard()
|
||||
h.editText(ctx, chatID, msgID, text, &kb)
|
||||
}
|
||||
|
||||
// -- Builders --
|
||||
|
||||
func (h *Handler) buildSalaryEstimate(user *domain.User) (string, error) {
|
||||
st, err := h.Repo.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if st.HourlyRate <= 0 {
|
||||
return "No hourly rate configured.\nUse /setrate <amount> to set your rate.", nil
|
||||
}
|
||||
loc := h.loadLocation(user.Timezone)
|
||||
now := time.Now().In(loc)
|
||||
calY, calM := now.Year(), int(now.Month())
|
||||
switch user.Calendar {
|
||||
case "jalali":
|
||||
calY, calM, _ = domain.GregorianToJalali(calY, calM, now.Day())
|
||||
case "hijri":
|
||||
calY, calM, _ = domain.GregorianToHijri(calY, calM, now.Day())
|
||||
}
|
||||
startStr, endStr := domain.MonthGregorianRange(user.Calendar, calY, calM)
|
||||
days, err := h.Repo.GetUserDaysInRange(user.ID, startStr, endStr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
est := h.computeMonthlySalary(days, user.ID, st.HourlyRate, loc)
|
||||
est.Currency = st.Currency
|
||||
est.HourlyRate = st.HourlyRate
|
||||
title := domain.FormatMonthTitle(user.Calendar, calY, calM)
|
||||
return fmt.Sprintf("Salary estimate for %s\n%s\nRate: %s%.2f/hr\nDays worked: %d\nHours: %.1f",
|
||||
title, est.FormatSalary(st.Currency), domain.CurrencySymbol(st.Currency), st.HourlyRate,
|
||||
est.WorkDays, est.WorkHours), nil
|
||||
}
|
||||
|
||||
func (h *Handler) computeMonthlySalary(days []domain.Day, userID int64, hourlyRate float64, loc *time.Location) domain.SalaryEstimate {
|
||||
var totalWork int64
|
||||
workDayCount := 0
|
||||
for _, day := range days {
|
||||
if day.IsDayOff {
|
||||
continue
|
||||
}
|
||||
events, err := h.Repo.EventsForDayByDayID(day.ID)
|
||||
if err != nil || len(events) == 0 {
|
||||
continue
|
||||
}
|
||||
y, m, d := domain.ParseGregorianDateKey(day.Date)
|
||||
dayStart := time.Date(y, time.Month(m), d, 0, 0, 0, 0, loc).Unix()
|
||||
dayEnd := time.Date(y, time.Month(m), d, 23, 59, 59, 0, loc).Unix()
|
||||
totals := domain.ComputeDailyTotals(events, day.MinBreakThreshold, dayStart, dayEnd)
|
||||
if totals.TotalSeconds > 0 {
|
||||
totalWork += totals.TotalSeconds
|
||||
workDayCount++
|
||||
}
|
||||
}
|
||||
hours := float64(totalWork) / domain.SecondsPerHour
|
||||
gross := domain.ComputeDailySalary(totalWork, hourlyRate)
|
||||
return domain.SalaryEstimate{
|
||||
WorkSeconds: totalWork, WorkHours: hours,
|
||||
GrossEarning: gross, WorkDays: workDayCount,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user