152 lines
4.7 KiB
Go
152 lines
4.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"wucher/internal/domain/base"
|
|
"wucher/internal/shared/pkg/appctx"
|
|
"wucher/internal/shared/pkg/sortkey"
|
|
)
|
|
|
|
type BaseService struct {
|
|
repo base.Repository
|
|
}
|
|
|
|
func NewBaseService(repo base.Repository) *BaseService {
|
|
return &BaseService{repo: repo}
|
|
}
|
|
|
|
var errInvalidBaseCategoryType = errors.New("invalid base category type")
|
|
|
|
func (s *BaseService) CreateBase(ctx context.Context, row *base.Base, categoryType string) error {
|
|
category, ok := base.NormalizeCategoryType(categoryType)
|
|
if !ok {
|
|
return errInvalidBaseCategoryType
|
|
}
|
|
if err := validateBaseCoordinates(row); err != nil {
|
|
return err
|
|
}
|
|
row.DefaultStartTimeType = normalizeBaseShiftTimeType(row.DefaultStartTimeType)
|
|
row.DefaultEndTimeType = normalizeBaseShiftTimeType(row.DefaultEndTimeType)
|
|
if row.DefaultStartTimeType == base.ShiftTimeTypeFixed && strings.TrimSpace(row.DefaultShiftStart) == "" {
|
|
return errors.New("default_shift_start is required")
|
|
}
|
|
if row.DefaultEndTimeType == base.ShiftTimeTypeFixed && strings.TrimSpace(row.DefaultShiftEnd) == "" {
|
|
return errors.New("default_shift_end is required")
|
|
}
|
|
return s.repo.CreateBase(ctx, row, category)
|
|
}
|
|
|
|
func (s *BaseService) UpdateBase(ctx context.Context, row *base.Base, categoryType string) error {
|
|
category, ok := base.NormalizeCategoryType(categoryType)
|
|
if !ok {
|
|
return errInvalidBaseCategoryType
|
|
}
|
|
if err := validateBaseCoordinates(row); err != nil {
|
|
return err
|
|
}
|
|
row.DefaultStartTimeType = normalizeBaseShiftTimeType(row.DefaultStartTimeType)
|
|
row.DefaultEndTimeType = normalizeBaseShiftTimeType(row.DefaultEndTimeType)
|
|
if row.DefaultStartTimeType == base.ShiftTimeTypeFixed && strings.TrimSpace(row.DefaultShiftStart) == "" {
|
|
return errors.New("default_shift_start is required")
|
|
}
|
|
if row.DefaultEndTimeType == base.ShiftTimeTypeFixed && strings.TrimSpace(row.DefaultShiftEnd) == "" {
|
|
return errors.New("default_shift_end is required")
|
|
}
|
|
return s.repo.UpdateBase(ctx, row, category)
|
|
}
|
|
|
|
func (s *BaseService) DeleteBase(ctx context.Context, id []byte, categoryType string) (*base.Base, error) {
|
|
category, ok := base.NormalizeCategoryType(categoryType)
|
|
if !ok {
|
|
return nil, errInvalidBaseCategoryType
|
|
}
|
|
|
|
// fetch existing row before deleting so we can return a copy
|
|
row, err := s.repo.GetBaseByID(ctx, id, category)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := s.repo.DeleteBase(ctx, id, category); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// if we had a row, populate DeletedAt/DeletedBy to reflect the repository update
|
|
if row != nil {
|
|
now := time.Now().UTC()
|
|
row.DeletedAt = &now
|
|
// try to pick actor from context if available
|
|
if actor := appctx.GetUserID(ctx); len(actor) > 0 {
|
|
row.DeletedBy = make([]byte, len(actor))
|
|
copy(row.DeletedBy, actor)
|
|
}
|
|
}
|
|
|
|
return row, nil
|
|
}
|
|
|
|
func (s *BaseService) GetBaseByID(ctx context.Context, id []byte, categoryType string) (*base.Base, error) {
|
|
category, ok := base.NormalizeCategoryType(categoryType)
|
|
if !ok {
|
|
return nil, errInvalidBaseCategoryType
|
|
}
|
|
return s.repo.GetBaseByID(ctx, id, category)
|
|
}
|
|
|
|
func (s *BaseService) ListBases(ctx context.Context, filter, sort string, limit, offset int, categoryType string, dul *bool) ([]base.Base, int64, error) {
|
|
if strings.TrimSpace(categoryType) == "" {
|
|
return s.repo.ListBases(ctx, filter, normalizeBaseSort(sort), limit, offset, "", dul)
|
|
}
|
|
category, ok := base.NormalizeCategoryType(categoryType)
|
|
if !ok {
|
|
return nil, 0, errInvalidBaseCategoryType
|
|
}
|
|
return s.repo.ListBases(ctx, filter, normalizeBaseSort(sort), limit, offset, category, dul)
|
|
}
|
|
|
|
func normalizeBaseSort(sort string) string {
|
|
return normalizeSortByRules(sort,
|
|
sortExpr(
|
|
joinSortClauses(sortkey.ActivePositiveSortClauses("", "is_active", "sortkey", "base", false)),
|
|
joinSortClauses(sortkey.ActivePositiveSortClauses("", "is_active", "sortkey", "base", true)),
|
|
"sortkey",
|
|
),
|
|
sortField("base"),
|
|
sortField("base_abbreviation"),
|
|
sortField("notes", "note", "notes"),
|
|
sortField("is_active"),
|
|
sortField("created_at"),
|
|
sortField("updated_at"),
|
|
)
|
|
}
|
|
|
|
func validateBaseCoordinates(row *base.Base) error {
|
|
if row == nil {
|
|
return nil
|
|
}
|
|
if row.Latitude < -90 || row.Latitude > 90 {
|
|
return errors.New("latitude must be between -90 and 90")
|
|
}
|
|
if row.Longitude < -180 || row.Longitude > 180 {
|
|
return errors.New("longitude must be between -180 and 180")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func normalizeBaseShiftTimeType(raw string) string {
|
|
switch strings.ToUpper(strings.TrimSpace(raw)) {
|
|
case "", base.ShiftTimeTypeFixed:
|
|
return base.ShiftTimeTypeFixed
|
|
case base.ShiftTimeTypeBMCT:
|
|
return base.ShiftTimeTypeBMCT
|
|
case base.ShiftTimeTypeECET:
|
|
return base.ShiftTimeTypeECET
|
|
default:
|
|
return strings.ToUpper(strings.TrimSpace(raw))
|
|
}
|
|
}
|