Import initail de calcul-astreintes v0.9.4 pour passage en paycheck 1.0

This commit is contained in:
2026-01-19 14:25:43 +01:00
commit cad0b2768a
44 changed files with 4183 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
package profiles
import (
"embed"
"encoding/json"
"fmt"
"sort"
"sync"
"git.dumerain.org/alban/calcul-astreintes/internal/models"
)
//go:embed profiles.json
var embeddedFS embed.FS
type profileJSON struct {
Label string `json:"label"`
Matricule string `json:"matricule,omitempty"` // ✅ pour auto-match avec l'agent importé
Rates map[string]float64 `json:"rates"`
ForfaitDimFerie float64 `json:"forfait_dim_ferie"`
}
type Repo struct {
mu sync.RWMutex
profiles map[string]models.Profile
rules models.GlobalRules
}
// NewEmbeddedRepo charge les profils depuis profiles.json (embarqué).
func NewEmbeddedRepo() (*Repo, *models.GlobalRules, error) {
b, err := embeddedFS.ReadFile("profiles.json")
if err != nil {
return nil, nil, err
}
var raw map[string]profileJSON
if err := json.Unmarshal(b, &raw); err != nil {
return nil, nil, fmt.Errorf("profiles.json invalide: %w", err)
}
repo := &Repo{profiles: map[string]models.Profile{}}
for id, p := range raw {
repo.profiles[id] = models.Profile{
ID: id,
Label: p.Label,
Matricule: p.Matricule,
T456: p.Rates["456"],
T458: p.Rates["458"],
T459: p.Rates["459"],
T471: p.Rates["471"],
}
if repo.rules.ForfaitDimFerie == 0 {
repo.rules.ForfaitDimFerie = p.ForfaitDimFerie
}
}
// Valeur par défaut de sécurité si le JSON n'a aucun profil
if repo.rules.ForfaitDimFerie == 0 {
repo.rules.ForfaitDimFerie = 120
}
return repo, &repo.rules, nil
}
// List renvoie les profils triés par label (dropdown stable).
func (r *Repo) List() ([]models.ProfileListItem, error) {
r.mu.RLock()
defer r.mu.RUnlock()
items := make([]models.ProfileListItem, 0, len(r.profiles))
for _, p := range r.profiles {
items = append(items, models.ProfileListItem{
ID: p.ID,
Label: p.Label,
Matricule: p.Matricule,
})
}
sort.Slice(items, func(i, j int) bool { return items[i].Label < items[j].Label })
return items, nil
}
func (r *Repo) Get(id string) (models.Profile, error) {
r.mu.RLock()
defer r.mu.RUnlock()
p, ok := r.profiles[id]
if !ok {
return models.Profile{}, fmt.Errorf("profil introuvable: %s", id)
}
return p, nil
}
func (r *Repo) Rules() models.GlobalRules {
r.mu.RLock()
defer r.mu.RUnlock()
return r.rules
}

View File

@@ -0,0 +1,46 @@
{
"test": {
"label": "TEST (fallback)",
"matricule": "",
"rates": {
"456": 1,
"458": 1,
"459": 1,
"471": 1
},
"forfait_dim_ferie": 120
},
"alban": {
"label": "DUMERAIN Alban (165004)",
"matricule": "165004",
"rates": {
"456": 18.03,
"458": 30.05,
"459": 36.06,
"471": 3.58
},
"forfait_dim_ferie": 120
},
"lydie": {
"label": "ROUQUIER Lydie (266340)",
"matricule": "266340",
"rates": {
"456": 15.24,
"458": 25.4,
"459": 30.48,
"471": 3.03
},
"forfait_dim_ferie": 120
},
"clement": {
"label": "DUFETELLE Clement (178549)",
"matricule": "178549",
"rates": {
"456": 19.05,
"458": 31.75,
"459": 38.1,
"471": 3.78
},
"forfait_dim_ferie": 120
}
}