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  }