github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/client/controllers/cont_equipiers.go (about) 1 package controllers 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "path/filepath" 9 "sort" 10 "strconv" 11 "strings" 12 13 "github.com/benoitkugler/goACVE/server/core/rawdata/matching" 14 "github.com/benoitkugler/goACVE/server/core/utils/table" 15 16 "github.com/benoitkugler/goACVE/server/core/apiserver" 17 dm "github.com/benoitkugler/goACVE/server/core/datamodel" 18 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 19 ) 20 21 type ButtonsEquipiers struct { 22 Creer, Supprimer, Exporter EtatSideButton 23 } 24 25 type OngletEquipiers interface { 26 baseOnglet 27 28 ChoixEviteDoublonsDocuments(docs []dm.AccesDocumentPersonne) (toSupp rd.Ids) 29 ConfirmeSupprimeEquipier(part rd.Personne) bool 30 } 31 32 type EtatEquipiers struct { 33 EquipierCurrent rd.IId 34 CritereCamp *dm.AccesCamp 35 // 0 pour tous, 1 pour temporaire, -1 pour référencés 36 CritereTemporaire rd.OptionnalBool 37 Recherche string 38 } 39 40 // Equipiers permet de valider les équipiers temporaires, 41 // et d'accéder aux renseignements administratifs. 42 // Les documents sont accessibles via l'Onglet Personnes. 43 // Les documents temporaires ne sont pas accessibles directement. 44 type Equipiers struct { 45 Onglet OngletEquipiers 46 main *MainController 47 Liste rd.Table 48 Header []rd.Header 49 Base *dm.BaseLocale 50 Etat EtatEquipiers 51 EditRight bool // Droit de modification et de validation 52 } 53 54 func NewEquipiers(main *MainController, permission int) *Equipiers { 55 eq := Equipiers{main: main, Base: main.Base, EditRight: permission >= 2, 56 Header: []rd.Header{ 57 {Field: dm.EquipierCamp, Label: "Camp"}, 58 {Field: dm.PersonneNom, Label: "Nom"}, 59 {Field: dm.PersonnePrenom, Label: "Prénom"}, 60 {Field: dm.EquipierRoles, Label: "Rôle"}, 61 {Field: dm.PersonneSexe, Label: "Sexe"}, 62 {Field: dm.PersonneNomJeuneFille, Label: "Nom de jeune fille"}, 63 {Field: dm.PersonneDateNaissance, Label: "Date de naissance"}, 64 {Field: dm.PersonneVilleNaissance, Label: "Ville de naissance"}, 65 {Field: dm.PersonneDepartementNaissance, Label: "Département de naissance"}, 66 {Field: dm.EquipierDiplome, Label: "Diplôme"}, 67 {Field: dm.EquipierAppro, Label: "Approfondissement"}, 68 {Field: dm.PersonneSecuriteSociale, Label: "Sécurité sociale"}, 69 {Field: dm.PersonneProfession, Label: "Profession"}, 70 {Field: dm.PersonneEtudiant, Label: "Etudiant"}, 71 {Field: dm.PersonneFonctionnaire, Label: "Fonctionnaire"}, 72 {Field: dm.EquipierPresence, Label: "Présence"}, 73 }} 74 eq.resetData() 75 return &eq 76 } 77 78 func (c *Equipiers) resetData() { 79 c.Liste = nil 80 var equipiers []dm.AccesEquipier 81 if c.Etat.CritereCamp != nil { 82 equipiers = c.Etat.CritereCamp.GetEquipe(nil) 83 } else { 84 equipiers = make([]dm.AccesEquipier, 0, len(c.Base.Equipiers)) 85 for id := range c.Base.Equipiers { 86 equipiers = append(equipiers, c.Base.NewEquipier(id)) 87 } 88 } 89 90 ct := c.Etat.CritereTemporaire 91 for _, part := range equipiers { 92 isTmp := bool(part.GetPersonne().RawData().IsTemporaire) 93 if ct == 0 || (ct.Bool() && isTmp) || (!ct.Bool() && !isTmp) { 94 c.Liste = append(c.Liste, part.AsItem()) 95 } 96 } 97 if strings.TrimSpace(c.Etat.Recherche) != "" { 98 c.Liste = dm.RechercheDetaillee(c.Liste, c.Etat.Recherche, c.Header) 99 } 100 101 dm.SortBy(c.Liste, dm.PersonnePrenom, false) 102 dm.SortStableBy(c.Liste, dm.PersonneNom, false) 103 dm.SortStableBy(c.Liste, dm.EquipierCamp, false) 104 105 hasEquipier := c.Etat.EquipierCurrent != nil 106 // besoin de déselectionner si absent 107 if hasEquipier && !HasId(c.Liste, c.Etat.EquipierCurrent) { 108 c.Etat.EquipierCurrent = nil 109 } 110 } 111 112 func (c *Equipiers) SideButtons() ButtonsEquipiers { 113 var bs ButtonsEquipiers 114 Etat := ButtonPresent 115 if c.Etat.EquipierCurrent != nil { 116 Etat = ButtonActivated 117 } 118 if c.EditRight { 119 bs.Creer = ButtonActivated 120 bs.Supprimer = Etat 121 } 122 bs.Exporter = ButtonPresent 123 if len(c.Liste) > 0 { 124 bs.Exporter = ButtonActivated 125 } 126 return bs 127 } 128 129 // GetStats renvoi les statistiques courantes 130 func (c *Equipiers) GetStats() []Stat { 131 nbCampsCourants, nbPartTmps := len(c.Base.GetCamps(false, -1)), 0 132 pers := rd.NewSet() 133 nbEquipiers := len(c.Base.Equipiers) 134 for _, p := range c.Base.Equipiers { 135 pers.Add(p.IdPersonne) 136 if c.Base.Personnes[p.IdPersonne].IsTemporaire { 137 nbPartTmps += 1 138 } 139 } 140 nbPersonnes := len(pers) 141 return []Stat{ 142 {Label: "Nombre de camps en cours", Value: strconv.Itoa(nbCampsCourants)}, 143 {Label: "Nombre d'équipiers non référencés", Value: strconv.Itoa(nbPartTmps)}, 144 {Label: "Nombre total d'équipiers", Value: fmt.Sprintf("%d (%d participations)", nbPersonnes, nbEquipiers)}, 145 } 146 } 147 148 // UpdateEquipier met à jour le profil transmis sur le serveur. 149 // La modification des champs de la personne se fait via l'onglet "Personnes" 150 func (c *Equipiers) UpdateEquipier(equipier rd.Equipier) { 151 // on empêche l'ajout d'un directeur 152 if dir, has := c.Base.NewEquipier(equipier.Id).GetCamp().GetDirecteurEquipier(); has && 153 dir.Id != equipier.Id && equipier.Roles.Is(rd.RDirecteur) { 154 c.main.ShowError(fmt.Errorf("Le séjour a déjà un directeur <i>%s</i>", dir.GetPersonne().RawData().NomPrenom())) 155 return 156 } 157 158 c.main.ShowStandard("Mise à jour de l'équipier...", true) 159 var out rd.Equipier 160 if err := requete(apiserver.UrlEquipiers, http.MethodPost, equipier, &out); err != nil { 161 c.main.ShowError(err) 162 return 163 } 164 165 c.Base.Equipiers[out.Id] = out 166 c.main.ShowStandard("Equipier mis à jour avec succès.", false) 167 c.main.ResetAllControllers() 168 } 169 170 // CreateEquipier crée un nouvel `equipier`, 171 // ayant des champs idPersonne et idCamp valides 172 // Renvoie `true` si la modification a été lancée 173 func (c *Equipiers) CreateEquipier(equipier rd.Equipier) bool { 174 personne := c.Base.Personnes[equipier.IdPersonne] 175 camp := c.Base.Camps[equipier.IdCamp] 176 if c.Base.IsEquipierAlreadyHere(equipier) { 177 c.main.ShowError(fmt.Errorf("%s est déjà présent(e) au camp %s", personne.NomPrenom(), 178 camp.Label())) 179 return false 180 } 181 182 if dir, has := c.Base.NewCamp(camp.Id).GetDirecteurEquipier(); has && equipier.Roles.Is(rd.RDirecteur) { 183 c.main.ShowError(fmt.Errorf("Le séjour a déjà un directeur <i>%s</i>", dir.GetPersonne().RawData().NomPrenom())) 184 return false 185 } 186 187 job := func() (interface{}, error) { 188 var out apiserver.CreateEquipierOut 189 err := requete(apiserver.UrlEquipiers, http.MethodPut, equipier, &out) 190 return out, err 191 } 192 onSuccess := func(_out interface{}) { 193 out := _out.(apiserver.CreateEquipierOut) 194 c.Base.Equipiers[out.Equipier.Id] = out.Equipier 195 c.Base.EquipierContraintes[out.Equipier.Id] = out.Contraintes 196 c.main.ShowStandard("Equipier ajouté avec succès.", false) 197 c.main.ResetAllControllers() 198 } 199 200 c.main.ShowStandard("Ajout de l'équipier en cours...", true) 201 c.main.Background.Run(job, onSuccess) 202 return true 203 } 204 205 // SupprimePersonne supprime l'équipier courant. 206 // S'il est temporaire, la personne et les documents liés sont aussi supprimés. 207 func (c *Equipiers) SupprimeEquipier() { 208 if c.Etat.EquipierCurrent == nil { 209 return 210 } 211 part := c.Base.NewEquipier(c.Etat.EquipierCurrent.Int64()) 212 acPers := part.GetPersonne() 213 pers := acPers.RawData() 214 215 if !c.Onglet.ConfirmeSupprimeEquipier(pers) { 216 return 217 } 218 219 job := func() (interface{}, error) { 220 var out apiserver.DeleteEquipierOut 221 err := requete(apiserver.UrlEquipiers, http.MethodDelete, IdAsParams(part.Id), &out) 222 return out, err 223 } 224 onSuccess := func(_out interface{}) { 225 out := _out.(apiserver.DeleteEquipierOut) 226 c.Etat.EquipierCurrent = nil 227 for _, idDoc := range out.IdsDocuments { 228 delete(c.Base.Documents, idDoc) 229 } 230 delete(c.Base.Equipiers, part.Id) 231 delete(c.Base.Personnes, out.IdPersonne) 232 c.main.ShowStandard(fmt.Sprintf("Equipier bien supprimé (ainsi que %d document(s) associé(s))", len(out.IdsDocuments)), false) 233 c.main.ResetAllControllers() 234 235 } 236 237 c.main.ShowStandard("Suppression de l'équipier en cours...", true) 238 c.main.Background.Run(job, onSuccess) 239 } 240 241 // IdentifieTmp identifie l'équipier courant avec la personne fournie. 242 // Si `cree` vaut `true`, la personne est créée. 243 func (c *Equipiers) IdentifieTmp(target matching.IdentifieTarget) { 244 if c.Etat.EquipierCurrent == nil { 245 return 246 } 247 equipier := c.Base.NewEquipier(c.Etat.EquipierCurrent.Int64()) 248 persTmp := equipier.GetPersonne() 249 if !persTmp.RawData().IsTemporaire { 250 c.main.ShowError(errors.New("Veuillez sélectionner un équipier temporaire !")) 251 return 252 } 253 254 params := apiserver.IdentifiePersonneIn{IdPersonneTmp: persTmp.Id} 255 switch target := target.(type) { 256 case matching.NouveauProfil: // rien à transmettre 257 case matching.Rattache: 258 params.Rattache = true 259 params.IdPersonneTarget = target.IdTarget 260 params.Modifications = target.Modifications 261 } 262 263 if params.Rattache { 264 // on vérifie que la personne target n'est pas déjà dans le séjour 265 if camp := equipier.GetCamp(); c.Base.IsEquipierAlreadyHere(rd.Equipier{IdPersonne: params.IdPersonneTarget, IdCamp: camp.Id}) { 266 c.main.ShowError(fmt.Errorf("%s est déjà sur le séjour %s", params.Modifications.NomPrenom(), camp.RawData().Label())) 267 return 268 } 269 } 270 271 // alerte pour les catégories de docs en double 272 if params.Rattache { 273 cache := c.Base.ResoudDocumentsPersonnes() 274 275 // on calcule les catégories nouvelles 276 idsContraintes := rd.NewSet() 277 for _, doc := range persTmp.GetDocuments(cache) { 278 idsContraintes.Add(doc.GetContrainte().Id) 279 } 280 281 // parmi les documents existants, on sélectionne ceux qui vont produire un doublon 282 var filteredDocs []dm.AccesDocumentPersonne 283 for _, doc := range c.Base.NewPersonne(params.IdPersonneTarget).GetDocuments(cache) { 284 if idsContraintes.Has(doc.GetContrainte().Id) { 285 filteredDocs = append(filteredDocs, doc) 286 } 287 } 288 sort.Slice(filteredDocs, func(i, j int) bool { 289 return filteredDocs[i].GetContrainte().Id < filteredDocs[j].GetContrainte().Id 290 }) 291 292 if len(filteredDocs) > 0 { 293 docsToSupp := c.Onglet.ChoixEviteDoublonsDocuments(filteredDocs) 294 if docsToSupp == nil { 295 c.main.ShowStandard("Identification annulée.", false) 296 return 297 } 298 params.SupprimeDocuments = docsToSupp 299 } 300 } 301 paramsFull := apiserver.IdentifieEquipierIn{ 302 IdEquipier: equipier.Id, 303 IdentifiePersonneIn: params, 304 } 305 job := func() (interface{}, error) { 306 var out apiserver.IdentifieEquipierOut 307 err := requete(apiserver.UrlIdentifieEquipier, http.MethodPut, paramsFull, &out) 308 return out, err 309 } 310 onSuccess := func(_out interface{}) { 311 out := _out.(apiserver.IdentifieEquipierOut) 312 c.Base.Equipiers[out.Equipier.Id] = out.Equipier 313 c.Base.ApplyIdentifie(out.IdentifiePersonneOut) 314 c.main.ShowStandard(fmt.Sprintf("Equipier identifié en %s", out.Personne.NomPrenom()), false) 315 c.main.ResetAllControllers() 316 } 317 318 c.main.ShowStandard("Identification de l'équipier en cours...", true) 319 c.main.Background.Run(job, onSuccess) 320 } 321 322 // ExportEquipiers génère la liste des équpiers courant au format excel 323 // et renvoi le chemin du fichier créé. 324 func (c *Equipiers) ExportEquipiers() string { 325 additionnalHeaders := []rd.Header{ 326 {Field: dm.PersonneMail, Label: "Adresse mail"}, 327 {Field: dm.PersonneTels, Label: "Téléphones"}, 328 {Field: dm.PersonneAdresse, Label: "Adresse"}, 329 {Field: dm.PersonneCodePostal, Label: "Code postal"}, 330 {Field: dm.PersonneVille, Label: "Ville"}, 331 } 332 headers := append(c.Header, additionnalHeaders...) 333 buf, err := table.GenereListeEquipe(headers, c.Liste, false) 334 if err != nil { 335 c.main.ShowError(err) 336 return "" 337 } 338 path, err := filepath.Abs(filepath.Join(LocalFolder, "equipiers.xlsx")) 339 if err != nil { 340 c.main.ShowError(err) 341 return "" 342 } 343 if err = ioutil.WriteFile(path, buf.Bytes(), 0666); err != nil { 344 c.main.ShowError(fmt.Errorf("Impossible d'enregistrer le fichier : %s", err)) 345 return "" 346 } 347 c.main.ShowStandard(fmt.Sprintf("Equipier exportés dans %s", path), false) 348 return path 349 }