github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/client/GUI/onglets/dons.go (about)

     1  package onglets
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/benoitkugler/goACVE/server/core/apiserver"
     8  	dm "github.com/benoitkugler/goACVE/server/core/datamodel"
     9  	rd "github.com/benoitkugler/goACVE/server/core/rawdata"
    10  	"github.com/benoitkugler/goACVE/server/core/rawdata/matching"
    11  
    12  	"github.com/benoitkugler/goACVE/client/GUI/basic"
    13  	"github.com/benoitkugler/goACVE/client/GUI/common"
    14  	"github.com/benoitkugler/goACVE/client/GUI/fields"
    15  	"github.com/benoitkugler/goACVE/client/GUI/lists"
    16  	"github.com/benoitkugler/goACVE/client/controllers"
    17  	"github.com/therecipe/qt/core"
    18  	"github.com/therecipe/qt/widgets"
    19  )
    20  
    21  func (d *Dons) Render() {
    22  	d.liste.Model().SetData(d.controller.Liste)
    23  	if d.controller.Etat.DonCurrent != nil {
    24  		d.liste.SelectRow(d.controller.Etat.DonCurrent)
    25  	}
    26  	d.stats.SetData(d.controller.GetStats())
    27  	d.liste.SetSearch(d.controller.Etat.Recherche)
    28  	d.annee.SetYears(d.controller.PossibleYears())
    29  	d.annee.SetData(d.controller.Etat.CritereAnnee)
    30  	d.emis.SetData(d.controller.Etat.CritereEmis)
    31  	d.showOrga.SetData(d.controller.Etat.CritereOrganismes)
    32  }
    33  
    34  func (d *Dons) ConfirmeForceRecuFiscal(don dm.AccesDon) bool {
    35  	dona := don.GetDonateur()
    36  	if _, isOrga := dona.(dm.AccesOrganisme); isOrga {
    37  		return true
    38  	}
    39  	label := "annonyme"
    40  	if dona, ok := dona.(dm.AccesPersonne); ok {
    41  		label = "de " + dona.RawData().NomPrenom().String()
    42  	}
    43  	msg := fmt.Sprintf("Le don <i>%s</i>, d'un montant de %s et reçu le %s, <br/>a déjà été émis dans un reçu fiscal. <br/>"+
    44  		"Etes-vous sur de vouloir de <b>ré-éditer</b> un reçu le contenant ?",
    45  		label, don.RawData().Valeur, don.RawData().DateReception)
    46  	return basic.Confirmation(msg, "Editer le reçu fiscal", basic.ONAction)
    47  }
    48  
    49  type Dons struct {
    50  	*widgets.QFrame
    51  	controller *controllers.Dons
    52  	parent     *widgets.QTabWidget
    53  	toolbar    *widgets.QToolBar
    54  
    55  	liste lists.Table
    56  	stats common.Statistics
    57  
    58  	annee    fields.Year
    59  	showOrga fields.OptionnalBool
    60  	emis     fields.OptionnalBool
    61  }
    62  
    63  func newDons(ct *controllers.Dons) *Dons {
    64  	p := Dons{QFrame: basic.Frame(), controller: ct}
    65  
    66  	p.liste = lists.Table{
    67  		Liste: lists.Liste{
    68  			Headers: ct.Header,
    69  			Title:   "Dons",
    70  			OnDoubleClick: func(acces rd.Item, _ int) {
    71  				p.editeDon(acces.Id.Int64())
    72  			},
    73  			OnClick: func(acces rd.Item, _ int) {
    74  				ct.Etat.DonCurrent = acces.Id
    75  				p.UpdateToolbar()
    76  			},
    77  			OnSearch: func(pattern string) {
    78  				ct.Etat.Recherche = pattern
    79  				ct.Reset()
    80  			},
    81  			OnRightClick: func(acces rd.Item, pos *core.QPoint) {
    82  				don := ct.Base.NewDon(acces.Id.Int64())
    83  				menu := widgets.NewQMenu(p)
    84  				if donateur := don.GetDonateur(); donateur != nil {
    85  					menu.AddAction("Aller au donateur").ConnectTriggered(func(bool) {
    86  						ct.Main().Controllers.Personnes.SelectPersonne(donateur)
    87  					})
    88  				}
    89  				if don.RawData().ModePaiement == rd.MPHelloasso {
    90  					menu.AddAction("Modifier l'ID HelloAsso").ConnectTriggered(func(bool) {
    91  						p.setIDHelloasso(don.RawData())
    92  					})
    93  				}
    94  				if len(menu.Actions()) > 0 {
    95  					p.liste.ShowContextMenu(menu, pos)
    96  				}
    97  			},
    98  			OnSort: func(field rd.Field, reverse bool) {
    99  				lists.DefaultSort(p.liste, field, reverse)
   100  			},
   101  		},
   102  	}
   103  
   104  	p.emis = fields.NewOptionnalBool(true, "Edité", "Non édité")
   105  	p.emis.ConnectCurrentIndexChanged(func(_ int) {
   106  		ct.Etat.CritereEmis = p.emis.GetData()
   107  		ct.Reset()
   108  	})
   109  	p.annee = fields.NewYear()
   110  	p.annee.ConnectActivated(func(int) {
   111  		ct.Etat.CritereAnnee = p.annee.GetData()
   112  		ct.Reset()
   113  	})
   114  	p.showOrga = fields.NewOptionnalBool(true, "Organismes", "Personnes")
   115  	p.showOrga.ConnectCurrentIndexChanged(func(_ int) {
   116  		ct.Etat.CritereOrganismes = p.showOrga.GetData()
   117  		ct.Reset()
   118  	})
   119  
   120  	rightHeader := widgets.NewQHBoxLayout()
   121  	rightHeader.AddWidget(basic.Label("Donateur :"), 1, 0)
   122  	rightHeader.AddWidget(p.showOrga, 1, core.Qt__AlignLeft)
   123  	rightHeader.AddWidget(basic.Label("Année :"), 1, 0)
   124  	rightHeader.AddWidget(p.annee, 1, core.Qt__AlignLeft)
   125  	rightHeader.AddWidget(basic.Label("Reçu fiscal :"), 1, 0)
   126  	rightHeader.AddWidget(p.emis, 1, core.Qt__AlignRight)
   127  
   128  	p.liste.RightHeader = rightHeader
   129  	p.liste.Init()
   130  	p.liste.View.(*widgets.QTableView).HorizontalHeader().SetMinimumSectionSize(200)
   131  
   132  	p.stats = common.NewStatistics(true)
   133  
   134  	lay := widgets.NewQVBoxLayout2(p)
   135  	lay.AddWidget(p.stats, 0, 0)
   136  	lay.AddWidget(p.liste, 1, 0)
   137  	return &p
   138  }
   139  
   140  func (d *Dons) creer() {
   141  	f := common.NewFicheDon(d.controller.Base, true)
   142  	det := common.NewDetails(&f, true)
   143  	newDon := rd.Don{DateReception: rd.Date(time.Now())}
   144  	f.SetData(newDon, rd.DonDonateur{}) // date par défaut à aujourdhui
   145  	if det.Exec() == 0 {
   146  		return
   147  	}
   148  	don, donateur := f.GetData()
   149  	params := apiserver.CreateDonIn{Don: don, Donateur: donateur}
   150  
   151  	// notification optionnelle
   152  	if donateur.IId() != nil {
   153  		dial := basic.Dialog2("Notifier par mail")
   154  
   155  		b1 := basic.Button("Enregistrer et notifier")
   156  		b1.SetObjectName(basic.ONAdd)
   157  		b1.ConnectClicked(func(bool) {
   158  			params.Notifie = true
   159  			dial.Accept()
   160  		})
   161  
   162  		b2 := basic.Button("Ne pas notifier")
   163  		b2.SetObjectName(basic.ONAction)
   164  		b2.ConnectClicked(func(bool) {
   165  			params.Notifie = false
   166  			dial.Accept()
   167  		})
   168  
   169  		h := widgets.NewQHBoxLayout()
   170  		h.AddWidget(b2, 1, 0)
   171  		h.AddStretch(3)
   172  		h.AddWidget(b1, 1, 0)
   173  
   174  		lay := widgets.NewQVBoxLayout2(dial)
   175  		lay.AddWidget(basic.Label("Souhaitez-vous notifier le donateur par mail ?"), 2, 0)
   176  		lay.AddLayout(h, 1)
   177  
   178  		if dial.Exec() == 0 {
   179  			return // annulation
   180  		}
   181  	}
   182  
   183  	d.controller.CreeDon(params)
   184  }
   185  
   186  func (d *Dons) editeDon(id int64) {
   187  	f := common.NewFicheDon(d.controller.Base, d.controller.EditRight)
   188  	f.SetData(d.controller.Base.Dons[id], d.controller.Base.DonDonateurs[id])
   189  	det := common.NewDetails(&f, d.controller.EditRight)
   190  	if det.Exec() == 0 {
   191  		return
   192  	}
   193  	don, donateur := f.GetData()
   194  	d.controller.UpdateDon(apiserver.CreateDonIn{Don: don, Donateur: donateur})
   195  }
   196  
   197  func (d *Dons) supprimer() {
   198  	keep := basic.Confirmation("Etes-vous sur de vouloir <b>supprimer</b> ce don ?",
   199  		"Supprimer", basic.ONDelete)
   200  	if keep {
   201  		d.controller.SupprimeDon()
   202  	}
   203  }
   204  
   205  func (d *Dons) setIDHelloasso(don rd.Don) {
   206  	dial := basic.Dialog("ID HelloAsso")
   207  
   208  	e := fields.NewString(true)
   209  	e.SetData(rd.String(don.Infos.IdPaiementHelloAsso)) // valeur initiale
   210  	valid := basic.Button("Modifier l'ID")
   211  	valid.SetObjectName(basic.ONAction)
   212  	valid.ConnectClicked(func(bool) {
   213  		don.Infos.IdPaiementHelloAsso = e.GetData().String()
   214  		d.controller.UpdateDon(apiserver.CreateDonIn{
   215  			Don:      don,
   216  			Donateur: d.controller.Base.DonDonateurs[don.Id],
   217  		})
   218  		dial.Accept()
   219  	})
   220  
   221  	dial.Layout().AddWidget(basic.Label(`Définir un ID HelloAsso permet de rattacher
   222  	ce don à un don HelloAsso. <br/> Le don HelloAsso n'apparaitra alors plus lors de la procédure d'import.`))
   223  	dial.Layout().AddWidget(e)
   224  	dial.Layout().AddWidget(valid)
   225  	dial.Exec()
   226  }
   227  
   228  func (d *Dons) exporterListe() {
   229  	dial := basic.Dialog2("Export des dons courants")
   230  
   231  	avecCoord := fields.NewBool(true)
   232  	valid := basic.Button("Exporter")
   233  	valid.SetObjectName(basic.ONAction)
   234  
   235  	valid.ConnectClicked(func(_ bool) {
   236  		dial.Close()
   237  		path := d.controller.ExporteListe(bool(avecCoord.GetData()))
   238  		if path != "" {
   239  			basic.ShowFile(path)
   240  		}
   241  	})
   242  
   243  	lay := widgets.NewQVBoxLayout2(dial)
   244  	lay.AddWidget(basic.Label("Veuillez choisir les options d'export :"), 1, 0)
   245  	form := widgets.NewQFormLayout(nil)
   246  	form.AddRow3("Afficher les coordonnées des donateurs", avecCoord)
   247  	lay.AddLayout(form, 2)
   248  	lay.AddWidget(valid, 1, core.Qt__AlignCenter)
   249  	dial.Exec()
   250  }
   251  
   252  func (d *Dons) editerRecu() {
   253  	dial := basic.Dialog2("Edition de reçus fiscaux")
   254  	num := fields.NewInt(true)
   255  	reEdit := fields.NewBool(true)
   256  	preview := basic.Label("")
   257  	preview.SetMaximumWidth(500)
   258  	preview.SetWordWrap(true)
   259  	valid := basic.Button("Editer les reçus")
   260  	valid.SetObjectName(basic.ONAction)
   261  	var params dm.OptionsRecuFiscal
   262  
   263  	valid.ConnectClicked(func(_ bool) {
   264  		valid.SetText("Edition en cours...")
   265  		valid.SetEnabled(false)
   266  		basic.Delay(func() {
   267  			path := d.controller.EditeRecusFiscaux(params)
   268  			dial.Accept()
   269  			if path != "" {
   270  				basic.ShowFile(path)
   271  			}
   272  		})
   273  	})
   274  
   275  	onChanged := func() {
   276  		params = dm.OptionsRecuFiscal{
   277  			Annee:  int(num.GetData()),
   278  			ReEmet: bool(reEdit.GetData()),
   279  		}
   280  		rfs := params.Select(d.controller.Base.Dons, d.controller.Base.DonDonateurs)
   281  		text := fmt.Sprintf(`<br/>
   282  			Reçus fiscaux à émettre : <b>%d</b><br/>
   283  			Dons concernés : <i>%d</i><br/>
   284  			Dons annonymes ignorés : <i>%d</i><br/>`,
   285  			len(rfs.Recus), len(rfs.IdsDons), rfs.NbAnnonyme)
   286  		preview.SetText(text)
   287  		valid.SetEnabled(len(rfs.Recus) != 0)
   288  	}
   289  
   290  	num.ConnectValueChanged(func(_ int) { onChanged() })
   291  	reEdit.ConnectClicked(func(_ bool) { onChanged() })
   292  
   293  	now := time.Now()
   294  	year := now.Year()
   295  	if now.Month() < time.April {
   296  		year = now.Year() - 1
   297  	}
   298  	num.SetData(rd.Int(year)) // valeur par défaut
   299  
   300  	lay := widgets.NewQFormLayout(dial)
   301  	lay.AddRow3("Année", num)
   302  	lay.AddRow3("Ré-emettre les dons déjà traités", reEdit)
   303  	lay.AddRow5(preview)
   304  	lay.AddRow5(valid)
   305  	dial.Exec()
   306  }
   307  
   308  func (d *Dons) importHelloasso() {
   309  	dial := basic.Dialog2("Import des dons HelloAsso")
   310  
   311  	var (
   312  		liste       lists.Table
   313  		dons        controllers.DonsImported
   314  		curentIndex = -1 // pour pouvoir enlever le don après identification
   315  		comp        *common.Similaires
   316  	)
   317  	comp = common.NewSimilaires(d.controller.Base, func(target matching.IdentifieTarget) {
   318  		d.controller.IdentifieDonHelloasso(dons[curentIndex], target)
   319  		// comme la mise à jour est asynchrone, on espère ne pas
   320  		// avoir d'erreur et on enlève directement le don de la liste
   321  		// Au pire, l'utilisateur relancera l'import
   322  		dons = append(dons[:curentIndex], dons[curentIndex+1:]...)
   323  		liste.Model().SetData(dons.Table())
   324  		comp.SetData(rd.BasePersonne{}, false) // désactive
   325  	})
   326  
   327  	liste = lists.Table{
   328  		Liste: lists.Liste{
   329  			Placeholder: "Chargement des dons HelloAsso...",
   330  			Headers:     controllers.HeaderDonImported,
   331  			OnClick: func(acces rd.Item, _ int) {
   332  				index := int(acces.Id.Int64())
   333  				curentIndex = index
   334  				if index >= len(dons) { // ne devrait jamais arriver
   335  					return
   336  				}
   337  				comp.SetData(dons[index].Donateur, true)
   338  			},
   339  			OnRightClick: func(acces rd.Item, pos *core.QPoint) {},
   340  			OnSort: func(field rd.Field, reverse bool) {
   341  				lists.DefaultSort(liste, field, reverse)
   342  			},
   343  			Title: "Dons présents sur le serveur HelloAsso",
   344  		},
   345  	}
   346  	liste.Init()
   347  	liste.View.(*widgets.QTableView).HorizontalHeader().SetMinimumSectionSize(200)
   348  	lay := widgets.NewQVBoxLayout2(dial)
   349  	lay.SetSpacing(1)
   350  	lay.AddWidget(liste, 4, 0)
   351  	lay.AddWidget(basic.Label("<b>Identifier</b> le donateur :"), 1, 0)
   352  	lay.AddWidget(comp, 3, 0)
   353  	dial.SetMinimumHeight(500)
   354  	dial.Show()
   355  
   356  	basic.Delay(func() {
   357  		dons = d.controller.ChargeDonsHelloasso()
   358  		if len(dons) == 0 {
   359  			dial.Reject()
   360  			return
   361  		}
   362  		liste.Model().SetData(dons.Table())
   363  	})
   364  
   365  }