github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/client/controllers/cont_inscriptions.go (about) 1 package controllers 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "strconv" 8 "strings" 9 10 "github.com/benoitkugler/goACVE/server/core/apiserver" 11 dm "github.com/benoitkugler/goACVE/server/core/datamodel" 12 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 13 "github.com/benoitkugler/goACVE/server/core/rawdata/matching" 14 ) 15 16 type ButtonsInscriptions struct { 17 Supprimer, Valider, LoadLog EtatSideButton 18 } 19 20 type ChoixEnvoi int 21 22 const ( 23 NoEnvoi ChoixEnvoi = iota 24 Envoi 25 EnvoiEtBascule 26 ) 27 28 type OngletInscriptions interface { 29 baseOnglet 30 31 ConfirmeSupprimeDossier(facture dm.AccesFacture) bool 32 ConfirmeValideMailInvalide(msg string) bool 33 DemandeEnvoiAccuseReception(respo rd.Personne) ChoixEnvoi 34 } 35 36 type EtatInscriptions struct { 37 InscriptionCurrent rd.IId 38 Recherche string 39 CritereIsFolded bool // si true InscriptionCurrent sera le responsable 40 CriteresTri dm.CriteresTri 41 } 42 43 // Inscriptions permet de valider les nouvelles inscriptions. 44 type Inscriptions struct { 45 Onglet OngletInscriptions 46 main *MainController 47 Liste []rd.ItemChilds 48 Header []rd.Header 49 Base *dm.BaseLocale 50 Etat EtatInscriptions 51 EditRight bool // Droit de modification et de validation, droit de "dé-validation" 52 } 53 54 func NewInscriptions(main *MainController, permission int) *Inscriptions { 55 insc := Inscriptions{main: main, Base: main.Base, EditRight: permission >= 2, 56 Header: []rd.Header{ 57 {Field: dm.PersonneIdentifie, Label: "Authentifié"}, 58 {Field: dm.PersonneNomPrenom, Label: "Personne"}, 59 {Field: dm.InscriptionDateHeure, Label: "Moment d'inscription"}, 60 {Field: dm.ParticipantCamp, Label: "Camp"}, 61 {Field: dm.PersonneDateNaissance, Label: "Date de naissance"}, 62 {Field: dm.PersonneSexe, Label: "Sexe"}, 63 }, 64 } 65 insc.resetData() 66 return &insc 67 } 68 69 func (c *Inscriptions) resetData() { 70 c.Liste = nil 71 72 cache, cache4 := c.Base.ResoudParticipants() 73 cache2 := c.Base.ResoudMessages() 74 cache3 := c.Base.ResoudPaiements() 75 // les "inscriptions" sont les facture non validées... 76 for _, insc := range c.Base.Factures { 77 if !insc.IsValidated { 78 c.Liste = append(c.Liste, c.Base.NewFacture(insc.Id).AsItemChilds(cache, cache2, cache3, cache4)) 79 } 80 } 81 // ... et les participants simples temporaires 82 for id := range c.Base.Participantsimples { 83 if ac := c.Base.NewParticipantsimple(id); ac.GetPersonne().RawData().IsTemporaire { 84 c.Liste = append(c.Liste, ac.AsItemChilds()) 85 } 86 } 87 88 if strings.TrimSpace(c.Etat.Recherche) != "" { 89 c.Liste = dm.RechercheDetailleeChilds(c.Liste, c.Etat.Recherche, c.Header) 90 } 91 92 dm.SortCriteresChilds(c.Liste, c.Etat.CriteresTri) 93 94 if c.Etat.InscriptionCurrent == nil { // fastpath 95 return 96 } 97 98 // on vérifie que l'inscription courante est dans la liste à afficher 99 // (en prenant en compte l'affichage ou non des "enfants") 100 var found bool 101 for _, insc := range c.Liste { 102 if insc.Id == c.Etat.InscriptionCurrent { 103 found = true 104 break 105 } 106 if c.Etat.CritereIsFolded { 107 continue 108 } 109 110 // on regarde dans les enfants 111 for _, part := range insc.Childs { 112 if part.Id == c.Etat.InscriptionCurrent { 113 found = true 114 break 115 } 116 } 117 } 118 if !found { 119 c.Etat.InscriptionCurrent = nil 120 } 121 } 122 123 func (c *Inscriptions) SideButtons() ButtonsInscriptions { 124 var bs ButtonsInscriptions 125 if c.EditRight { 126 bs.Supprimer = ButtonPresent 127 if c.Etat.InscriptionCurrent != nil { 128 bs.Supprimer = ButtonActivated 129 } 130 131 bs.Valider = ButtonPresent 132 if c.isInscriptionValidable() { 133 bs.Valider = ButtonActivated 134 } 135 } 136 bs.LoadLog = ButtonActivated 137 return bs 138 } 139 140 // AsAcces construit un accès à partir de `id` (participant, participantsimple ou facture) 141 func (c *Inscriptions) AsAcces(id rd.IId) dm.Personne { 142 switch id := id.(type) { 143 case rd.IdParticipantsimple: 144 return c.Base.NewParticipantsimple(id.Int64()) 145 case rd.IdParticipant: 146 return c.Base.NewParticipant(id.Int64()) 147 case rd.IdFacture: 148 return c.Base.NewFacture(id.Int64()) 149 default: 150 return nil 151 } 152 } 153 154 func (c *Inscriptions) isInscriptionValidable() bool { 155 facture, has := c.Base.IdAsFacture(c.Etat.InscriptionCurrent) 156 if !has { 157 return false 158 } 159 if facture.RawData().IsValidated { // déjà validé, ne devrait pas arriver 160 return false 161 } 162 if facture.GetPersonne().RawData().IsTemporaire { 163 return false 164 } 165 166 parts := facture.GetDossiers(nil) 167 if len(parts) == 0 { // aucune inscription, autant ne pas la valider 168 return false 169 } 170 for _, part := range parts { 171 if part.GetPersonne().RawData().IsTemporaire { 172 return false 173 } 174 } 175 return true 176 } 177 178 // CurrentInfo renvoie le message (éventuel) de l'inscription courante 179 func (c *Inscriptions) CurrentInfo() string { 180 switch id := c.Etat.InscriptionCurrent.(type) { 181 case rd.IdParticipantsimple: 182 return c.Base.NewParticipantsimple(id.Int64()).RawData().Info.TrimSpace().String() 183 case rd.IdFacture: 184 // on rassemble les messages (probablement 1 ou 0, mais l'espace perso a pu déjà être utilisé) 185 return c.Base.NewFacture(id.Int64()).GetEtat(nil, nil).Info() 186 case rd.IdParticipant: 187 // on se ramène au dossier 188 fac, ok := c.Base.NewParticipant(id.Int64()).GetFacture() 189 if !ok { 190 return "" 191 } 192 return fac.GetEtat(nil, nil).Info() 193 default: 194 return "" 195 } 196 } 197 198 // GetStats renvoi les statistiques courantes 199 func (c *Inscriptions) GetStats() []Stat { 200 nbCurrent := 0 201 for _, insc := range c.Base.Factures { 202 if !insc.IsValidated { 203 nbCurrent += 1 204 } 205 } 206 return []Stat{ 207 {Label: "Nombre d'inscriptions en cours", Value: strconv.Itoa(nbCurrent)}, 208 } 209 } 210 211 // SupprimeInscription supprime le groupe d'inscription courante 212 // après confirmation 213 func (c *Inscriptions) SupprimeInscription() { 214 if c.Etat.InscriptionCurrent == nil { 215 return 216 } 217 if idSimple, ok := c.Etat.InscriptionCurrent.(rd.IdParticipantsimple); ok { 218 // on supprime le participant et la personne temporaire 219 c.main.Controllers.Camps.supprimeParticipantsimple(c.Base.NewParticipantsimple(idSimple.Int64())) 220 return 221 } 222 223 facture, ok := c.Base.IdAsFacture(c.Etat.InscriptionCurrent) 224 if !ok { 225 return 226 } 227 228 if keep := c.Onglet.ConfirmeSupprimeDossier(facture); !keep { 229 c.main.ShowStandard("Suppression annulée", false) 230 return 231 } 232 233 job := func() (interface{}, error) { 234 var out apiserver.DeleteInscriptionOut 235 err := requete(apiserver.UrlInscriptions, http.MethodDelete, IdAsParams(facture.Id), &out) 236 return out, err 237 } 238 onSuccess := func(_out interface{}) { 239 out := _out.(apiserver.DeleteInscriptionOut) 240 c.Etat.InscriptionCurrent = nil 241 c.Base.DeleteFacture(facture.Id) 242 if out.IdResponsable >= 0 { 243 delete(c.Base.Personnes, out.IdResponsable) 244 } 245 for _, idPaiement := range out.IdsPaiements { 246 delete(c.Base.Paiements, idPaiement) 247 } 248 c.Base.CleanupDocuments(out.IdsDocuments) 249 for _, part := range out.Participants { 250 c.Base.CleanupParticipant(part) 251 } 252 253 c.main.ShowStandard("Inscription supprimée avec succès.", false) 254 c.Reset() 255 } 256 257 c.main.ShowStandard("Suppression de l'inscription en cours...", true) 258 c.main.Background.Run(job, onSuccess) 259 } 260 261 type jwc struct { 262 job func() (interface{}, error) 263 onSuccess func(_out interface{}) 264 } 265 266 func (c *Inscriptions) setupJobIdentResponsable(argsPers apiserver.IdentifiePersonneIn, id rd.IdFacture) jwc { 267 argsPers.IdPersonneTmp = c.Base.NewFacture(id.Int64()).GetPersonne().Id 268 params := apiserver.IdentifieResponsableIn{ 269 IdFacture: id.Int64(), 270 IdentifiePersonneIn: argsPers, 271 } 272 273 job := func() (interface{}, error) { 274 var out apiserver.IdentifieResponsableOut 275 err := requete(apiserver.UrlIdentifieResponsable, http.MethodPut, params, &out) 276 return out, err 277 } 278 onSuccess := func(_out interface{}) { 279 out := _out.(apiserver.IdentifieResponsableOut) 280 c.Base.Factures[out.Facture.Id] = out.Facture 281 c.Base.ApplyIdentifie(out.IdentifiePersonneOut) 282 c.main.ShowStandard("Identification effectuée.", false) 283 c.main.ResetAllControllers() 284 } 285 return jwc{job: job, onSuccess: onSuccess} 286 } 287 288 func (c *Inscriptions) setupJobIdentParticipant(argsPers apiserver.IdentifiePersonneIn, id rd.IdParticipant) (jwc, bool) { 289 part := c.Base.NewParticipant(id.Int64()) 290 argsPers.IdPersonneTmp = part.GetPersonne().Id 291 params := apiserver.IdentifieParticipantIn{ 292 IdParticipant: id.Int64(), 293 IdentifiePersonneIn: argsPers, 294 } 295 296 if argsPers.Rattache { // on vérifie que la personne target n'est pas déjà dans le séjour 297 if camp := part.GetCamp(); c.Base.IsParticipantAlreadyHere(argsPers.IdPersonneTarget, camp.Id) { 298 c.main.ShowError(fmt.Errorf("%s est déjà sur le séjour %s", argsPers.Modifications.NomPrenom(), camp.RawData().Label())) 299 return jwc{}, false 300 } 301 } 302 303 job := func() (interface{}, error) { 304 var out apiserver.IdentifieParticipantOut 305 err := requete(apiserver.UrlIdentifieParticipant, http.MethodPut, params, &out) 306 return out, err 307 } 308 onSuccess := func(_out interface{}) { 309 out := _out.(apiserver.IdentifieParticipantOut) 310 c.Base.Participants[out.Participant.Id] = out.Participant 311 c.Base.ApplyIdentifie(out.IdentifiePersonneOut) 312 c.main.ShowStandard("Identification effectuée.", false) 313 c.main.ResetAllControllers() 314 } 315 return jwc{job: job, onSuccess: onSuccess}, true 316 } 317 318 func (c *Inscriptions) setupJobIdentParticipantsimple(argsPers apiserver.IdentifiePersonneIn, id rd.IdParticipantsimple) (jwc, bool) { 319 part := c.Base.NewParticipantsimple(id.Int64()) 320 argsPers.IdPersonneTmp = part.GetPersonne().Id 321 params := apiserver.IdentifieParticipantsimpleIn{ 322 IdParticipantsimple: id.Int64(), 323 IdentifiePersonneIn: argsPers, 324 } 325 326 if argsPers.Rattache { // on vérifie que la personne target n'est pas déjà dans le séjour 327 if camp := part.GetCamp(); c.Base.IsParticipantsimpleAlreadyHere(argsPers.IdPersonneTarget, camp.Id) { 328 c.main.ShowError(fmt.Errorf("%s est déjà sur le séjour %s", argsPers.Modifications.NomPrenom(), camp.RawData().Label())) 329 return jwc{}, false 330 } 331 } 332 333 job := func() (interface{}, error) { 334 var out apiserver.IdentifieParticipantsimpleOut 335 err := requete(apiserver.UrlIdentifieParticipantsimple, http.MethodPut, params, &out) 336 return out, err 337 } 338 onSuccess := func(_out interface{}) { 339 out := _out.(apiserver.IdentifieParticipantsimpleOut) 340 c.Base.Participantsimples[out.Participantsimple.Id] = out.Participantsimple 341 c.Base.ApplyIdentifie(out.IdentifiePersonneOut) 342 c.main.ShowStandard("Identification effectuée et mail de confirmation envoyé.", false) 343 c.main.ResetAllControllers() 344 } 345 return jwc{job: job, onSuccess: onSuccess}, true 346 } 347 348 // Identifie identifie l'inscription courante contre la personne donnée. 349 func (c *Inscriptions) Identifie(target matching.IdentifieTarget) { 350 // IdPersonneTmp est complété plus tard 351 var argsPers apiserver.IdentifiePersonneIn 352 switch target := target.(type) { 353 case matching.NouveauProfil: 354 // rien à transmettre 355 case matching.Rattache: 356 argsPers.Rattache = true 357 argsPers.IdPersonneTarget = target.IdTarget 358 argsPers.Modifications = target.Modifications 359 } 360 // normalement aucun acteur d'une inscription n'upload de documents 361 // donc il n'y a pas besoin de check les doublons 362 363 var ( 364 js jwc 365 ok bool 366 ) 367 368 switch id := c.Etat.InscriptionCurrent.(type) { 369 case rd.IdParticipantsimple: 370 js, ok = c.setupJobIdentParticipantsimple(argsPers, id) 371 case rd.IdFacture: 372 js, ok = c.setupJobIdentResponsable(argsPers, id), true 373 case rd.IdParticipant: 374 js, ok = c.setupJobIdentParticipant(argsPers, id) 375 default: 376 c.main.ShowError(errors.New("Veuillez sélectionner une inscription !")) 377 } 378 if !ok { 379 return 380 } 381 382 message := "Validation en tant que nouveau profil ..." 383 if argsPers.Rattache { 384 message = fmt.Sprintf("Identification à %s en cours...", argsPers.Modifications.NomPrenom()) 385 } 386 c.main.ShowStandard(message, true) 387 c.main.Background.Run(js.job, js.onSuccess) 388 } 389 390 // Valide valide le groupe d'inscription courant, de manière synchrone, 391 // puis propose l'envoi d'un accusé de réception. 392 func (c *Inscriptions) Valide() { 393 facture, ok := c.Base.IdAsFacture(c.Etat.InscriptionCurrent) 394 if !ok { 395 c.main.ShowError(errors.New("Veuillez sélectionnez une inscription !")) 396 return 397 } 398 399 if !facture.RawData().IsConfirmed { 400 pers := facture.GetPersonne().RawData() 401 msg := fmt.Sprintf("Attention, l'adresse <b>mail</b> de l'inscription n'a <b>pas été validée</b> par le responsable. <br/>"+ 402 "<i>A moins d'être sur que l'adresse <b>%s</b> soit valide, il est déconseillé de valider cette inscription.</i>", pers.Mail) 403 keep := c.Onglet.ConfirmeValideMailInvalide(msg) 404 if !keep { 405 return 406 } 407 } 408 409 c.main.ShowStandard("Validation de l'inscription en cours...", true) 410 var out rd.Facture 411 err := requete(apiserver.UrlValideInscriptions, http.MethodPost, IdAsParams(facture.Id), &out) 412 if err != nil { 413 c.main.ShowError(err) 414 return 415 } 416 c.Base.Factures[out.Id] = out 417 c.main.ShowStandard("Inscription validée", false) 418 c.main.ResetAllControllers() 419 envoiAR := c.Onglet.DemandeEnvoiAccuseReception(facture.GetPersonne().RawData()) 420 if envoiAR == NoEnvoi { 421 return 422 } 423 c.main.Controllers.SuiviDossiers.EnvoiAccuseReception(facture) 424 if envoiAR == EnvoiEtBascule { 425 c.main.Controllers.SuiviDossiers.SelectFacture(facture) 426 } 427 } 428 429 func (c *Inscriptions) LoadLogInscriptions() rd.Inscriptions { 430 var out rd.Inscriptions 431 err := requete(apiserver.UrlInscriptions, http.MethodGet, nil, &out) 432 if err != nil { 433 c.main.ShowError(err) 434 return nil 435 } 436 return out 437 } 438 439 // RejouerInscription envoie une requête sur l'url d'inscription publique 440 // La base locale doit être raffraichie pour prendre en compte le résultat 441 func (c *Inscriptions) RejouerInscription(insc rd.Inscription) bool { 442 c.main.ShowStandard("Envoi de l'inscription...", true) 443 444 err := requete(urlRejoueInscription, http.MethodPost, insc, new(string)) // dismiss the body 445 if err != nil { 446 c.main.ShowError(err) 447 return false 448 } 449 c.main.ShowStandard("Inscription déclenchée.", false) 450 return true 451 }