Commit initial
[perso/Immae/Projets/Scripts/Public.git] / comptes
CommitLineData
5172ecf8
IB
1#!/usr/bin/en perl
2# The MIT License (MIT)
3#
4# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
5#
6# Permission is hereby granted, free of charge, to any person obtaining a copy
7# of this software and associated documentation files (the "Software"), to deal
8# in the Software without restriction, including without limitation the rights
9# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10# copies of the Software, and to permit persons to whom the Software is
11# furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice shall be included in
14# all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22# THE SOFTWARE.
23
24use Switch;
25use strict;
26
27my $file = "comptes.data";
28
29my @actions=('Ajouter un participant');
30my %participants = ();
31my @transactions = ();
32my @descriptions = ();
33my $evenement_def;
34my $remboursements = "";
35
36if($#ARGV==0) {
37 open FILE, $ARGV[0] || die "Impossible de lire le fichier";
38 $evenement_def = <FILE>;
39 chomp($evenement_def);
40 while(my $noms = <FILE>) {
41 if($noms eq "\n") { last; }
42 my ($numero,$nom) = split(/ /,$noms,2);
43 chomp($nom);
44 $participants{$nom} = $numero;
45 }
46 while(my $transaction = <FILE>) {
47 if($transaction eq "\n") { last; }
48 chomp($transaction);
49 push(@transactions,$transaction);
50 my $description = <FILE>;
51 chomp($description);
52 push(@descriptions,$description);
53 }
54 $file = $ARGV[0];
55}
56
57GLOBALE: while(1) {
58 if(keys(%participants)>0) {
59 $actions[1]="Ajouter une dépense";
60 $actions[2]="Enregistrer";
61 }
62 if(scalar(@transactions)>0) {
63 $actions[3]="Voir les dépenses de quelqu'un";
64 $actions[2]="Enregistrer";
65 $actions[4]="Equilibrage";
66 $actions[5]="Voir une transaction";
67 }
68
69 my $action;
70 while(1) {
71 my $i = 1;
72 my $var;
73 my @vart = ( @actions, 'Sortir' );
74 my $message = '';
75 foreach $var ( @vart ) {
76 $message .= $i++.') '.$var."\n";
77 }
78 print $message;
79 $var = <STDIN>;
80 chop($var);
81 if(/\D/ || $var < 1 || $var > $i) {
82 print "Mauvaise entrée\n";
83 next;
84 }
85 $action = $vart[$var-1];
86 last;
87 }
88 switch ($action) {
89 case "Ajouter un participant" {
90 print "Nom du participant\n";
91 my $participant = <STDIN>;
92 chomp($participant);
93 $participants{$participant} = keys(%participants)+1;
94 }
95 case "Ajouter une dépense" {
96 print "Qui a payé ?\n";
97 my $paye;
98 while(1) {
99 my $i = 1;
100 my $var;
101 my @vart = ( keys(%participants), "Annuler" );
102 foreach $var ( @vart ) {
103 print $i++.') '.$var."\n";
104 }
105 $var = <STDIN>;
106 chop($var);
107 if(/\D/ || $var < 1 || $var > $i) {
108 print "Mauvaise entrée\n";
109 next;
110 }
111 $paye = $vart[$var-1];
112 last;
113 }
114 if($paye eq "Annuler") {
115 next GLOBALE;
116 }
117 print "Quoi ?\n";
118 my $description = <STDIN>;
119 chomp($description);
120 print "Combien ?\n";
121 my $prix = <STDIN>;
122 chomp($prix);
123 print "Pour qui ?\n";
124 my $repartition = "";
125 my $total_parts = 0;
126 DESTS: while(1) {
127 my $dest;
128 while(1) {
129 my $i = 1;
130 my $var;
131 my @vart = ( keys(%participants), "Ajouter à tous", "Fini" );
132 foreach $var ( @vart ) {
133 print $i++.') '.$var."\n";
134 }
135 $var = <STDIN>;
136 chop($var);
137 if(/\D/ || $var < 1 || $var > $i) {
138 print "Mauvaise entrée\n";
139 next;
140 }
141 $dest = $vart[$var-1];
142 last;
143 }
144 switch($dest) {
145 case "Fini" {
146 if($repartition eq "") { print "Annulé\n"; }
147 elsif($total_parts == 0) {
148 print "Le nombre total de parts est nul, il faut en ajouter !\n";
149 next DESTS;
150 }
151 else {
152 push(@transactions, $participants{$paye}.' '.$prix.$repartition);
153 push(@descriptions, $description);
154 }
155 last DESTS;
156 }
157 case "Ajouter à tous" {
158 print "Nombre de parts ?\n";
159 my $parts = <STDIN>;
160 chomp($parts);
161 if(!($parts == 0)) {
162 foreach my $participant (keys(%participants)) {
163 $repartition .= ' '.$participants{$participant}.':'.scalar($parts);
164 $total_parts += scalar($parts);
165 }
166 }
167 }
168 else {
169 print "Nombre de parts ?\n";
170 my $parts = <STDIN>;
171 chomp($parts);
172 if(!($parts == 0)) {
173 $repartition .= ' '.$participants{$dest}.':'.scalar($parts);
174 $total_parts += scalar($parts);
175 }
176 }
177 }
178 }
179 }
180 case "Voir les dépenses de quelqu'un" {
181 my $personne;
182 while(1) {
183 my $i = 1;
184 my $var;
185 my @vart = ( keys(%participants), "Annuler" );
186 foreach $var ( @vart ) {
187 print $i++.') '.$var."\n";
188 }
189 $var = <STDIN>;
190 chop($var);
191 if(/\D/ || $var < 1 || $var > $i) {
192 print "Mauvaise entrée\n";
193 next;
194 }
195 $personne = $vart[$var-1];
196 last;
197 }
198 if($personne eq "Annuler") {
199 next GLOBALE;
200 }
201 my $depenses = 0;
202 my $frais = 0;
203 foreach my $transaction (@transactions) {
204 my @table_trans = split(/ /,$transaction);
205 my $payeur = shift(@table_trans);
206 my $prix = shift(@table_trans);
207 if($payeur == $participants{$personne}) {
208 $depenses += $prix;
209 }
210 my $parts = 0;
211 my $frac = 0;
212 my $repartition;
213 foreach $repartition (@table_trans) {
214 my ($pers,$part) = split(/:/,$repartition);
215 if($pers == $participants{$personne}) {
216 $frac += $part;
217 }
218 $parts += $part;
219 }
220 $frais += $prix*$frac/$parts;
221 }
222 print $personne." a payé ".$depenses." EUR\n";
223 print "et a pour ".sprintf("%.2f",$frais)." EUR de frais au total.\n";
224 print "Il a donc un solde de ".sprintf("%.2f",$depenses-$frais)." EUR\n";
225 my $pause = <STDIN>;
226 }
227 case "Voir une transaction" {
228 my $transaction;
229 while(1) {
230 my $i = 1;
231 my $var;
232 my @vart = ( @descriptions, "Annuler" );
233 foreach $var ( @vart ) {
234 print $i++.') '.$var."\n";
235 }
236 $var = <STDIN>;
237 chop($var);
238 if(/\D/ || $var < 1 || $var > $i) {
239 print "Mauvaise entrée\n";
240 next;
241 }
242 $transaction = $var-1;
243 last;
244 }
245 my @table_trans = split(/ /,$transactions[$transaction]);
246 my $payeur = shift(@table_trans);
247 my $prix = shift(@table_trans);
248 my $Tparts = 0;
249 my $repartition;
250 my %parts;
251 foreach my $pers (keys(%participants)) {
252 if($payeur == $participants{$pers}) {
253 print $descriptions[$transaction]." (payé par ".$pers."), ".$prix." EUR\n";
254 last
255 }
256 }
257 foreach $repartition (@table_trans) {
258 my ($pers,$part) = split(/:/,$repartition);
259 $Tparts += $part;
260 $parts{$pers} += $part;
261 }
262 foreach my $pers (keys(%participants)) {
263 if(!exists $parts{$participants{$pers}}) {
264 next;
265 }
266 print $pers.", ".$parts{$participants{$pers}}." part(s), soit ". $prix*$parts{$participants{$pers}}/$Tparts." EUR\n";
267 }
268 my $pause = <STDIN>;
269 }
270 case "Enregistrer" {
271 print "Nom de l'événement ?";
272 if(!($evenement_def eq "")) {
273 print " [".$evenement_def."]";
274 }
275 print "\n";
276 my $evenement = <STDIN>;
277 chomp($evenement);
278 if($evenement eq "") {
279 $evenement = $evenement_def;
280 }
281 open FILE, ">".$file;
282 print FILE $evenement."\n";
283 my $key;
284 foreach $key (keys(%participants)) {
285 print FILE $participants{$key}." ".$key."\n";
286 }
287 print FILE "\n";
288 for(my $i=0;$i<scalar(@transactions);$i++) {
289 print FILE $transactions[$i]."\n";
290 print FILE $descriptions[$i]."\n";
291 }
292 print FILE "\n";
293 print FILE $remboursements;
294 close FILE;
295 }
296 case "Equilibrage" {
297 my %Tdepenses = ();
298 my %Tfrais = ();
299 my %Tsolde = ();
300 $remboursements = "";
301 foreach my $Ttransaction (@transactions) {
302 my @Ttable_trans = split(/ /,$Ttransaction);
303 my $Tpayeur = shift(@Ttable_trans);
304 my $Tprix = shift(@Ttable_trans);
305 $Tdepenses{$Tpayeur} = $Tdepenses{$Tpayeur} + $Tprix;
306 my $Tparts = 0;
307 my $Tfrac = 0;
308 my $Trepartition;
309 foreach $Trepartition (@Ttable_trans) {
310 my ($Tpers,$Tpart) = split(/:/,$Trepartition);
311 $Tparts += $Tpart;
312 }
313 foreach $Trepartition (@Ttable_trans) {
314 my ($Tpers,$Tpart) = split(/:/,$Trepartition);
315 $Tfrais{$Tpers} = $Tfrais{$Tpers} + $Tprix*$Tpart/$Tparts;
316 }
317 }
318 foreach my $Tpersonne (keys(%participants)) {
319 my $numero = $participants{$Tpersonne};
320 $Tsolde{$Tpersonne} = sprintf("%.2f",$Tdepenses{$numero}-$Tfrais{$numero});
321 print $Tpersonne." a un solde de ".$Tsolde{$Tpersonne}." EUR\n";
322 }
323 my $pause = <STDIN>;
324 print "Y-a-t-il des remboursements plus aisés ?\n";
325 my $ouinon;
326 while(1) {
327 my $i = 1;
328 my $var;
329 my @vart = ( "Oui", "Non" );
330 foreach $var ( @vart ) {
331 print $i++.') '.$var."\n";
332 }
333 $var = <STDIN>;
334 chop($var);
335 if(/\D/ || $var < 1 || $var > $i) {
336 print "Mauvaise entrée\n";
337 next;
338 }
339 $ouinon = $vart[$var-1];
340 last;
341 }
342 AISE: while($ouinon eq "Oui") {
343 print "Qui ?\n";
344 my $personne;
345 while(1) {
346 my $i = 1;
347 my $var;
348 my @vart = ( keys(%participants), "Fini" );
349 foreach $var ( @vart ) {
350 print $i++.') '.$var."\n";
351 }
352 $var = <STDIN>;
353 chop($var);
354 if(/\D/ || $var < 1 || $var > $i) {
355 print "Mauvaise entrée\n";
356 next;
357 }
358 $personne = $vart[$var-1];
359 last;
360 }
361 if($personne eq "Fini") { last AISE; }
362 print "Avec qui ?\n";
363 my $personneb;
364 while(1) {
365 my $i = 1;
366 my $var;
367 my @vart = ( keys(%participants), "Annuler" );
368 foreach $var ( @vart ) {
369 print $i++.') '.$var."\n";
370 }
371 $var = <STDIN>;
372 chop($var);
373 if(/\D/ || $var < 1 || $var > $i) {
374 print "Mauvaise entrée\n";
375 next;
376 }
377 $personneb = $vart[$var-1];
378 last;
379 }
380 if($personneb eq "Annuler") { next AISE; }
381 if($Tsolde{$personne}*$Tsolde{$personneb}<0) {
382 my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
383 my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
384 my $inf = (abs($Tsolde{$personne})<abs($Tsolde{$personneb}))?abs($Tsolde{$personne}):abs($Tsolde{$personneb});
385 $remboursements .= $pers_inf." doit ".$inf." EUR à ".$pers_sup."\n";
386 $Tsolde{$pers_inf} += $inf;
387 $Tsolde{$pers_sup} -= $inf;
388 }
389 }
390 # Une boucle pour détecter si on a des couples qui s'annulent mutuellement
391 COUPLE: foreach my $personne (keys(%participants)) {
392 if($Tsolde{$personne} == 0) { next; }
393 foreach my $personneb (keys(%participants)) {
394 if($Tsolde{$personneb} + $Tsolde{$personne} != 0) { next; }
395 my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
396 my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
397 my $val = abs($Tsolde{$personne});
398 $remboursements .= $pers_inf." doit ".$val." EUR à ".$pers_sup."\n";
399 $Tsolde{$pers_inf} += $val;
400 $Tsolde{$pers_sup} -= $val;
401 next COUPLE;
402 }
403 }
404 REMB: while(1) {
405 # On supprime les 0, et on fait deux hashs
406 my %Tneg = ();
407 my %Tpos = ();
408 foreach my $personne (keys(%Tsolde)) {
409 if($Tsolde{$personne} == 0) { delete $Tsolde{$personne}; }
410 elsif($Tsolde{$personne} < 0) { $Tneg{$personne} = $Tsolde{$personne}; }
411 elsif($Tsolde{$personne} > 0) { $Tpos{$personne} = $Tsolde{$personne}; }
412 }
413 if(keys(%Tneg) == 0) {
414 last REMB;
415 }
416 foreach my $neg (sort { $Tneg{$a} cmp $Tneg{$b} } keys %Tneg) {
417 my $max = 0;
418 my $positif = 0;
419 foreach my $pos (sort { $Tpos{$a} cmp $Tpos{$b} } keys %Tpos) {
420 if($Tpos{$pos} + $Tneg{$neg}>0) {
421 $positif = $pos;
422 last;
423 }
424 $max = $pos;
425 }
426 if(!($max eq 0)) {
427 $remboursements .= $neg." doit ".$Tsolde{$max}." EUR à ".$max."\n";
428 $Tsolde{$neg} += $Tsolde{$max};
429 delete $Tsolde{$max};
430 }
431 else {
432 $remboursements .= $neg." doit ".-$Tsolde{$neg}." EUR à ".$positif."\n";
433 $Tsolde{$positif} += $Tsolde{$neg};
434 delete $Tsolde{$neg};
435 }
436 next REMB;
437 }
438 }
439 print $remboursements;
440 my $pause = <STDIN>;
441 }
442 case "Sortir" {
443 last GLOBALE;
444 }
445 }
446}