github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/rawdata/composites/finances.go (about) 1 package composites 2 3 import ( 4 "fmt" 5 6 rd "github.com/benoitkugler/goACVE/server/core/rawdata" 7 ) 8 9 // ValeurEffective renvoie : 10 // - le montant dans le cas d'une aide absolue 11 // - le montant fois le nombre de jours (en prenant en compte une éventuelle limite) sinon 12 // Si `withRemise` vaut true les remises (%) sont appliquées. 13 func (a AideParticipantCamp) ValeurEffective(withRemise bool) rd.Euros { 14 val := a.Aide.Valeur 15 nbJours := a.ParticipantCamp.AsOptionParticipantCamp().NbJours() 16 if a.Aide.ParJour { 17 limite := a.Aide.NbJoursMax 18 if limite > 0 && limite < nbJours { 19 nbJours = limite 20 } 21 val = val * rd.Euros(nbJours) 22 } 23 if withRemise { 24 val = val.Remise(a.Participant.Remises.Pourcent()) 25 } 26 return val 27 } 28 29 type AideComplet struct { 30 AideStructureaide 31 ParticipantCamp 32 } 33 34 func (a AideComplet) Description() string { 35 aide := a.ParticipantCamp.WithAide(a.Aide) 36 return fmt.Sprintf("%s : %s", a.Structureaide.Nom, aide.ValeurEffective(false)) 37 } 38 39 // c'est celui du participant, ou sinon celui du responsable 40 func (p ParticipantFacturePersonne) getQuotientFamilial() rd.Int { 41 qfPart := p.Participant.OptionPrix.QuotientFamilial 42 if qfPart != 0 { 43 return qfPart 44 } 45 if p.Participant.IdFacture.IsNil() { 46 return 0 47 } 48 return p.FacturePersonne.Personne.QuotientFamilial 49 } 50 51 // StatutPrix renvoi la catégorie de prix du participant 52 // Une catégorie avec un Id vide équivaut à l'absence de catégorie 53 func (p OptionParticipantCamp) StatutPrix() rd.PrixParStatut { 54 s := p.OptionPrix.Statut 55 if s == 0 { 56 return rd.PrixParStatut{} 57 } 58 campOption := p.Camp.OptionPrix 59 if campOption.Active != rd.OptionsPrix.STATUT { 60 return rd.PrixParStatut{} 61 } 62 for _, info := range campOption.Statut { 63 if info.Id == s { 64 return info 65 } 66 } 67 return rd.PrixParStatut{} 68 } 69 70 type ParticipantComplet struct { 71 ParticipantCamp 72 FacturePersonne 73 } 74 75 func (p ParticipantComplet) AsFacture() ParticipantFacturePersonne { 76 return ParticipantFacturePersonne{Participant: p.Participant, FacturePersonne: p.FacturePersonne} 77 } 78 79 func (p ParticipantCamp) WithAide(aide rd.Aide) AideParticipantCamp { 80 return AideParticipantCamp{Aide: aide, ParticipantCamp: p} 81 } 82 83 func getIndexQF(qf rd.Int) int { 84 n := len(rd.QuotientFamilial) 85 for i := 0; i < n-1; i++ { 86 q1, q2 := rd.QuotientFamilial[i], rd.QuotientFamilial[i+1] 87 if q1 < qf && qf <= q2 { 88 return i 89 } 90 } 91 return n - 1 92 } 93 94 // Renvoie le prix du camp, en prenant en compte une éventuelle option. 95 // Renvoi aussi une description de l'éventuelle option. 96 func (p ParticipantComplet) prixCampBase() (rd.Euros, string) { 97 desc := p.AsOptionParticipantCamp().Description().String() 98 99 quotientFamilial := p.AsFacture().getQuotientFamilial() 100 optionPrixParticipant := p.Participant.OptionPrix 101 optionPrixCamp := p.Camp.OptionPrix 102 optionActive := optionPrixCamp.Active 103 var prix rd.Euros = -1 104 switch optionActive { 105 case rd.OptionsPrix.SEMAINE: 106 semaine := optionPrixParticipant.Semaine 107 prixSem := optionPrixCamp.Semaine 108 if semaine == rd.SSe1 { 109 prix = prixSem.Prix1 110 } else if semaine == rd.SSe2 { 111 prix = prixSem.Prix2 112 } 113 case rd.OptionsPrix.STATUT: 114 statutInfo := p.AsOptionParticipantCamp().StatutPrix() 115 if statutInfo.Id != 0 { 116 prix = statutInfo.Prix 117 } 118 case rd.OptionsPrix.QUOTIENT_FAMILIAL: 119 qf := optionPrixParticipant.QuotientFamilial 120 if qf == 0 { 121 qf = quotientFamilial 122 } 123 if qf > 0 { 124 qfCamp := optionPrixCamp.QuotientFamilial 125 prix = qfCamp[getIndexQF(qf)] 126 } 127 case rd.OptionsPrix.JOUR: 128 nbJours := p.ParticipantCamp.AsOptionParticipantCamp().NbJours() 129 prixJours := optionPrixCamp.Jour 130 if nbJours == 0 { // invalide -> camp entier 131 break 132 } 133 if int(nbJours) <= len(prixJours) { 134 prix = prixJours[nbJours-1] 135 } 136 } 137 if prix == -1 { 138 prix = p.Camp.Prix 139 } 140 return prix, desc 141 } 142 143 type resolvedAide struct { 144 Description string 145 Montant rd.Euros 146 Valide bool 147 } 148 149 // BilanPrixCamp regroupe les infos relative 150 // au coût d'un séjour pour un participant. 151 type BilanPrixCamp struct { 152 Aides []resolvedAide 153 Remises rd.Remises 154 155 // prix du camp (option comprise) 156 PrixBase rd.Euros 157 DescriptionPrix string 158 } 159 160 // PrixSansRemises renvoie le prix du séjour si on applique les aides (extérieures) 161 // mais pas les remises. 162 func (b BilanPrixCamp) PrixSansRemises() rd.Euros { 163 p := b.PrixBase - b.TotalAides() 164 if p < 0 { 165 p = 0 166 } 167 return p 168 } 169 170 // PrixSansAide renvoie le prix du séjour en appliquant les remises, 171 // mais pas les aides. 172 func (b BilanPrixCamp) PrixSansAide() rd.Euros { 173 return b.PrixBase.Remise(b.Remises.ReducEquipiers+b.Remises.ReducEnfants) - b.Remises.ReducSpeciale 174 } 175 176 func (b BilanPrixCamp) TotalAides() rd.Euros { 177 var out rd.Euros 178 for _, aide := range b.Aides { 179 if aide.Valide { 180 out += aide.Montant 181 } 182 } 183 return out 184 } 185 186 func (b BilanPrixCamp) PrixNet() rd.Euros { 187 p := b.PrixSansRemises().Remise(b.Remises.Pourcent()) - b.Remises.ReducSpeciale 188 if p < 0 { 189 p = 0 190 } 191 return p 192 } 193 194 // EtatFinancier calcule le prix du sejour pour le participant, 195 // en prenant en compte les options, les remises et les aides. 196 // Si `withAidesInvalides` vaut `false`, les aides non validées ne sont pas renvoyées. 197 // `aides` n'est pas filtrée 198 func (p ParticipantComplet) EtatFinancier(aides []AideStructureaide, withAidesInvalides bool) BilanPrixCamp { 199 var out BilanPrixCamp 200 out.PrixBase, out.DescriptionPrix = p.prixCampBase() 201 out.Remises = p.Participant.Remises 202 for _, aide := range aides { 203 va := p.WithAide(aide.Aide).ValeurEffective(false) 204 dumped := resolvedAide{ 205 Description: AideComplet{AideStructureaide: aide, ParticipantCamp: p.ParticipantCamp}.Description(), 206 Montant: va, 207 Valide: bool(aide.Aide.Valide), 208 } 209 if withAidesInvalides || dumped.Valide { 210 out.Aides = append(out.Aides, dumped) 211 } 212 } 213 return out 214 } 215 216 // ByFacture associe à chaque facture ses paiements (cout linéaire) 217 func (ps PaiementFactures) ByFacture() map[int64]PaiementFactures { 218 out := map[int64]PaiementFactures{} 219 for _, pf := range ps { 220 out[pf.IdFacture] = append(out[pf.IdFacture], pf) 221 } 222 return out 223 }