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  }