summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2015-08-31 19:39:25 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2015-08-31 19:39:25 +0200
commitc2590696efd0b91972c238ab892555f739751bc9 (patch)
tree6d5deb55dee05b863bffd05f29a952154d450ea9
parentdf1c9d58185639bc3c413175b8fadd2545ae1e4b (diff)
downloadPublic-c2590696efd0b91972c238ab892555f739751bc9.tar.gz
Public-c2590696efd0b91972c238ab892555f739751bc9.tar.zst
Public-c2590696efd0b91972c238ab892555f739751bc9.zip
Amélioration script comptes
-rwxr-xr-xcomptes895
1 files changed, 492 insertions, 403 deletions
diff --git a/comptes b/comptes
index 0fbacf2..853615a 100755
--- a/comptes
+++ b/comptes
@@ -1,4 +1,4 @@
1#!/usr/bin/en perl 1#!/usr/bin/env perl
2# The MIT License (MIT) 2# The MIT License (MIT)
3# 3#
4# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/ 4# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
@@ -31,416 +31,505 @@ my %participants = ();
31my @transactions = (); 31my @transactions = ();
32my @descriptions = (); 32my @descriptions = ();
33my $evenement_def; 33my $evenement_def;
34my $remboursements = ""; 34my @remboursements = ();
35 35my %initiales = ();
36if($#ARGV==0) { 36
37 open FILE, $ARGV[0] || die "Impossible de lire le fichier"; 37if($#ARGV == 0) {
38 $evenement_def = <FILE>; 38 open FILE, $ARGV[0] || die "Impossible de lire le fichier";
39 chomp($evenement_def); 39 $evenement_def = <FILE>;
40 while(my $noms = <FILE>) { 40 chomp($evenement_def);
41 if($noms eq "\n") { last; } 41 while(my $noms = <FILE>) {
42 my ($numero,$nom) = split(/ /,$noms,2); 42 if($noms eq "\n") { last; }
43 chomp($nom); 43 my ($numero,$nom) = split(/ /,$noms,2);
44 $participants{$nom} = $numero; 44 chomp($nom);
45 $participants{$nom} = $numero;
46 }
47 while(my $transaction = <FILE>) {
48 if($transaction eq "\n") { last; }
49 chomp($transaction);
50 push(@transactions,$transaction);
51 my $description = <FILE>;
52 chomp($description);
53 push(@descriptions,$description);
54 }
55 while(my $remboursement = <FILE>) {
56 if($remboursement eq "\n") { last; }
57 chomp($remboursement);
58 my @remb = split(/ /, $remboursement);
59 push(@remboursements,\@remb);
60 }
61 $file = $ARGV[0];
62}
63
64sub choose_action {
65 my @actions = ('Ajouter un participant');
66 my $action;
67
68 if (keys(%participants) > 0) {
69 $actions[1] = "Ajouter une dépense";
70 $actions[2] = "Enregistrer";
71 }
72 if(scalar(@transactions) > 0) {
73 $actions[2] = "Enregistrer";
74 $actions[3] = "Voir les frais de quelqu'un (dépenses - dettes)";
75 $actions[4] = "Voir les frais de tout le monde";
76 $actions[5] = "Equilibrage";
77 $actions[6] = "Voir une transaction";
78 }
79 if(scalar(@remboursements) > 0) {
80 $actions[7] = "Afficher les remboursements";
81 }
82
83 while(1) {
84 my $i = 1;
85 my $var;
86 my @vart = ( @actions, 'Sortir' );
87 my $message = '';
88 foreach $var ( @vart ) {
89 $message .= $i++.') '.$var."\n";
90 }
91 print $message;
92 $var = <STDIN>;
93 chop($var);
94 if(/\D/ || $var < 1 || $var > $i) {
95 print "Mauvaise entrée\n";
96 next;
97 }
98 $action = $vart[$var-1];
99 last;
100 }
101
102 return $action;
103}
104
105sub pp {
106 my ($price, $noteur) = @_;
107
108 if (!$noteur) {
109 return sprintf("%.2f", $price)." EUR";
110 } else {
111 return sprintf("%.2f", $price);
112 }
113}
114
115sub compute_initiales {
116 %initiales = ();
117}
118
119sub add_participant {
120 print "Nom du participant ?\n";
121 my $participant = <STDIN>;
122 chomp($participant);
123 $participant =~ s/\s/_/g;
124 $participants{$participant} = keys(%participants)+1;
125 compute_initiales();
126}
127
128sub select_menu {
129 my (@vart) = @_;
130 while(1) {
131 my $i = 1;
132 my $var;
133 foreach $var ( @vart ) {
134 print $i++.') '.$var."\n";
135 }
136 $var = <STDIN>;
137 chop($var);
138 if(/\D/ || $var < 1 || $var > scalar @vart) {
139 print "Mauvaise entrée\n";
140 next;
45 } 141 }
46 while(my $transaction = <FILE>) { 142 return $vart[$var-1];
47 if($transaction eq "\n") { last; } 143 }
48 chomp($transaction); 144}
49 push(@transactions,$transaction); 145
50 my $description = <FILE>; 146sub select_participant {
51 chomp($description); 147 my ($annuler, @supplementaires) = @_;
52 push(@descriptions,$description); 148 while(1) {
149 my $i = 1;
150 my $var;
151 my @vart = ( keys(%participants), @supplementaires, ($annuler) );
152 foreach $var ( @vart ) {
153 print $i++.') '.$var."\n";
53 } 154 }
54 $file = $ARGV[0]; 155 $var = <STDIN>;
156 chop($var);
157 if(/\D/ || $var < 1 || $var > scalar @vart) {
158 print "Mauvaise entrée\n";
159 next;
160 }
161 if ($var != scalar @vart) {
162 return $vart[$var-1];
163 } else {
164 return;
165 }
166 }
167}
168
169sub select_transaction {
170 my $transaction;
171 while(1) {
172 my $i = 1;
173 my $var;
174 my @vart = ( @descriptions, "Annuler" );
175 foreach $var ( @vart ) {
176 print $i++.') '.$var."\n";
177 }
178 $var = <STDIN>;
179 chop($var);
180 if(/\D/ || $var < 1 || $var > $i) {
181 print "Mauvaise entrée\n";
182 next;
183 }
184 $transaction = $var-1;
185 last;
186 }
187
188 my ($payeur, $prix, $total_parts, $split, $parts) = &parse_transaction($transactions[$transaction]);
189 return ($descriptions[$transaction], $payeur, $prix, $total_parts, $split, $parts);
190}
191
192sub add_transaction {
193 print "Qui a payé ?\n";
194 my $paye = select_participant("Annuler");
195 if(!$paye) {
196 print "Annulé";
197 return;
198 }
199 print "Quoi ?\n";
200 my $description = <STDIN>;
201 chomp($description);
202 print "Combien ?\n";
203 my $prix = <STDIN>;
204 chomp($prix);
205 print "Pour qui ?\n";
206 my $repartition = "";
207 my $total_parts = 0;
208 DESTS: while(1) {
209 my $dest = select_participant("Fini", "Ajouter à tous");
210 switch($dest) {
211 case undef {
212 if($repartition eq "") {
213 print "Annulé\n";
214 return;
215 }
216 elsif($total_parts == 0) {
217 print "Le nombre total de parts est nul, il faut en ajouter !\n";
218 next DESTS;
219 }
220 else {
221 push(@transactions, $participants{$paye}.' '.$prix.$repartition);
222 push(@descriptions, $description);
223 return;
224 }
225 }
226 case "Ajouter à tous" {
227 print "Nombre de parts ?\n";
228 my $parts = <STDIN>;
229 chomp($parts);
230 if(!($parts == 0)) {
231 foreach my $participant (keys(%participants)) {
232 $repartition .= ' '.$participants{$participant}.':'.scalar($parts);
233 $total_parts += scalar($parts);
234 }
235 }
236 }
237 else {
238 print "Nombre de parts ?\n";
239 my $parts = <STDIN>;
240 chomp($parts);
241 if(!($parts == 0)) {
242 $repartition .= ' '.$participants{$dest}.':'.scalar($parts);
243 $total_parts += scalar($parts);
244 }
245 }
246 }
247 }
248}
249
250sub find_participant {
251 my ($participant_number) = @_;
252
253 foreach my $name (keys(%participants)) {
254 if ($participant_number == $participants{$name}) {
255 return $name;
256 }
257 }
258}
259
260sub parse_transaction {
261 my ($transaction) = @_;
262 my @table_trans = split(/ /,$transaction);
263
264 my $payeur = shift(@table_trans);
265 $payeur = find_participant($payeur);
266 my $prix = shift(@table_trans);
267 my %parts;
268 my %split;
269 my $total_parts = 0;
270 foreach my $repartition (@table_trans) {
271 my ($participant, $part) = split(/:/, $repartition);
272 $participant = find_participant($participant);
273 $parts{$participant} ||= 0;
274 $parts{$participant} += $part;
275 $total_parts += $part;
276 }
277 if (!$parts{$payeur}) {
278 $parts{$payeur} = 0;
279 }
280 foreach my $participant (keys(%parts)) {
281 $split{$participant} = - ($parts{$participant} * $prix) / $total_parts;
282 if ($participant eq $payeur) {
283 $split{$participant} += $prix;
284 }
285 }
286
287 return ($payeur, $prix, $total_parts, \%split, \%parts);
288}
289
290sub max_length {
291 my (@strings) = @_;
292 my @string_lengths = sort { length($a) <=> length($b) } @strings;
293 return length($string_lengths[-1]);
294}
295
296sub list_transactions_for_participants {
297 my (@participants) = @_;
298 my $one_participant = 0;
299 if (scalar @participants == 0) {
300 @participants = keys(%participants);
301 }
302 if (scalar @participants == 1) {
303 $one_participant = 1;
304 }
305
306 my %depenses;
307 my %solde;
308
309 my @zipped = map {($transactions[$_], $descriptions[$_])} (0 .. $#descriptions);
310 while (scalar(@zipped) > 0) {
311 my $transaction = shift @zipped;
312 my $description = shift @zipped;
313 my ($payeur, $prix, $total_parts, $parsed_transaction, $parts) = &parse_transaction($transaction);
314 $depenses{$payeur} ||= 0;
315 $depenses{$payeur} += $prix;
316
317 my @intersection = grep( $parsed_transaction->{$_}, @participants);
318 if (scalar @intersection) {
319 my $phantom = " " x length($description.":");
320 my $max_participant_length = max_length(@intersection);
321
322 print $description.":";
323 foreach my $participant (@intersection) {
324 $solde{$participant} ||= 0;
325 $solde{$participant} += $parsed_transaction->{$participant};
326
327 if ($one_participant) {
328 print " ".pp($parsed_transaction->{$participant});
329 if ($payeur eq $participant) {
330 print " (a payé, ".pp($prix).")";
331 }
332 print "\n";
333 } else {
334 my $participant_padding = " " x ($max_participant_length - length($participant));
335 print " ".$participant.$participant_padding." ".pp($parsed_transaction->{$participant});
336 if ($payeur eq $participant) {
337 print " (a payé, ".pp($prix).")";
338 }
339 print "\n".$phantom;
340 }
341 }
342 if (!$one_participant) {
343 print "\n";
344 }
345 }
346 }
347
348 foreach my $personne (@participants) {
349 my $d = $depenses{$personne} || 0;
350 my $s = $solde{$personne} || 0;
351 if ($d) {
352 print $personne." a payé ".pp($d);
353 } else {
354 print $personne." n'a rien payé";
355 }
356 if ($s) {
357 print " et a pour ".pp($d - $s)." de frais au total.\n";
358 } else {
359 print " et n'a pas eu de frais.\n";
360 }
361 print $personne." a donc un solde de ".pp($s)."\n";
362 }
363}
364
365sub compute_equity {
366 my %depenses;
367 my %frais;
368 my %soldes;
369 foreach my $transaction (@transactions) {
370 my ($payeur, $prix, $total_parts, $split, $parts) = &parse_transaction($transaction);
371 $depenses{$payeur} += $prix;
372
373 foreach my $personne (keys(%{$split})) {
374 $soldes{$personne} += $split->{$personne};
375 }
376 }
377 foreach my $personne (keys(%soldes)) {
378 $frais{$personne} = $depenses{$personne} - $soldes{$personne};
379 }
380
381 return (\%depenses, \%frais, \%soldes);
382}
383
384sub delete_zeros {
385 my ($soldes, @participants) = @_;
386
387 foreach my $participant (@participants) {
388 delete $soldes->{$participant} if pp($soldes->{$participant}, 1) == 0;
389 }
390}
391
392sub compute_reimbursment {
393 my ($a, $b, $soldes) = @_;
394 my $s_a = $soldes->{$a};
395 my $s_b = $soldes->{$b};
396
397 return if (pp($s_a, 1) * pp($s_b, 1) >= 0);
398 my $debtor = pp($s_a, 1) < 0 ? $a : $b;
399 my $creditor = pp($s_a, 1) > 0 ? $a : $b;
400 my $exchange = (abs($s_a) < abs($s_b)) ? abs($s_a) : abs($s_b);
401
402 my @remboursement = ($debtor, $creditor, $exchange);
403 push @remboursements, \@remboursement;
404 $soldes->{$creditor} -= $exchange;
405 $soldes->{$debtor} += $exchange;
406 delete_zeros($soldes, $a, $b);
407}
408
409sub select_exchange_couple {
410 my ($soldes) = @_;
411 my $bd; # biggest debtor
412 my $sc; # smallest creditor
413
414 foreach my $p (keys(%{$soldes})) {
415 $bd = $p if $soldes->{$p} < 0 && (!$bd || $soldes->{$p} < $soldes->{$bd});
416 $sc = $p if $soldes->{$p} > 0 && (!$sc || $soldes->{$p} < $soldes->{$sc});
417 }
418
419 return ($bd, $sc);
420}
421
422sub print_remboursements {
423 foreach my $remboursement (@remboursements) {
424 my ($debtor, $creditor, $exchange) = (@{$remboursement});
425 print $debtor." doit ".pp($exchange)." à ".$creditor."\n";
426 }
427 my $pause = <STDIN>;
55} 428}
56 429
57GLOBALE: while(1) { 430GLOBALE: while(1) {
58 if(keys(%participants)>0) { 431 my $action = choose_action();
59 $actions[1]="Ajouter une dépense"; 432 switch ($action) {
60 $actions[2]="Enregistrer"; 433 case "Ajouter un participant" {
434 add_participant();
435 }
436 case "Ajouter une dépense" {
437 add_transaction();
438 }
439 case "Voir les frais de quelqu'un (dépenses - dettes)" {
440 my $personne = select_participant("Annuler");
441 if(!$personne) {
442 next GLOBALE;
443 }
444 list_transactions_for_participants(($personne));
445 my $pause = <STDIN>;
446 }
447 case "Voir les frais de tout le monde" {
448 list_transactions_for_participants(keys(%participants));
449 my $pause = <STDIN>;
61 } 450 }
62 if(scalar(@transactions)>0) { 451 case "Voir une transaction" {
63 $actions[3]="Voir les dépenses de quelqu'un"; 452 my ($description, $payeur, $prix, $total_parts, $split, $parts) = select_transaction();
64 $actions[2]="Enregistrer"; 453 print $description." (payé par ".$payeur."), ".pp($prix)."\n";
65 $actions[4]="Equilibrage"; 454 foreach my $pers (keys(%{$split})) {
66 $actions[5]="Voir une transaction"; 455 print $pers.", ".$parts->{$pers}." part(s), soit ". pp($split->{$pers});
456 if ($pers eq $payeur) {
457 print " (".pp($prix)." - ".pp($prix - $split->{$pers}).")";
458 }
459 print "\n";
460 }
67 } 461 }
462 case "Enregistrer" {
463 print "Nom de l'événement ?";
464 if(!($evenement_def eq "")) {
465 print " [".$evenement_def."]";
466 }
467 print "\n";
468 my $evenement = <STDIN>;
469 chomp($evenement);
470 if($evenement eq "") {
471 $evenement = $evenement_def;
472 }
473 open FILE, ">".$file;
474 print FILE $evenement."\n";
475 my $key;
476 foreach $key (keys(%participants)) {
477 print FILE $participants{$key}." ".$key."\n";
478 }
479 print FILE "\n";
480 for(my $i=0;$i<scalar(@transactions);$i++) {
481 print FILE $transactions[$i]."\n";
482 print FILE $descriptions[$i]."\n";
483 }
484 print FILE "\n";
485 foreach my $remboursement (@remboursements) {
486 print FILE join(" ", @{$remboursement})."\n";
487 }
488 close FILE;
489 }
490 case "Equilibrage" {
491 my ($depenses, $frais, $soldes) = compute_equity();
492 @remboursements = ();
493
494 foreach my $personne (keys(%participants)) {
495 print $personne." a un solde de ".pp($soldes->{$personne})." (+" . pp($depenses->{$personne}). " / -". pp($frais->{$personne}) . ")\n";
496 }
497 my $pause = <STDIN>;
498 print "Y-a-t-il des remboursements plus aisés ?\n";
499 my $ouinon = select_menu("Oui", "Non");
68 500
69 my $action; 501 AISE: while($ouinon eq "Oui") {
70 while(1) { 502 print "Qui ?\n";
71 my $i = 1; 503 my $personnea = select_participant("Fini");
72 my $var; 504 if(!$personnea) { last AISE; }
73 my @vart = ( @actions, 'Sortir' ); 505 print "Avec qui ?\n";
74 my $message = ''; 506 my $personneb = select_participant("Annuler");
75 foreach $var ( @vart ) { 507 if(!$personneb) { next AISE; }
76 $message .= $i++.') '.$var."\n"; 508 compute_reimbursment($personnea, $personneb, $soldes);
77 } 509 }
78 print $message; 510 # Une boucle pour détecter si on a des couples qui s'annulent mutuellement
79 $var = <STDIN>; 511 delete_zeros($soldes, keys(%{$soldes}));
80 chop($var); 512 COUPLE: foreach my $personnea (keys(%participants)) {
81 if(/\D/ || $var < 1 || $var > $i) { 513 next if(pp($soldes->{$personnea}, 1) == 0);
82 print "Mauvaise entrée\n"; 514 foreach my $personneb (keys(%participants)) {
83 next; 515 next if (pp($soldes->{$personneb} + $soldes->{$personnea}, 1) != 0);
84 } 516 compute_reimbursment($personnea, $personneb, $soldes);
85 $action = $vart[$var-1]; 517 next COUPLE;
86 last; 518 }
519 }
520 REMB: while(1) {
521 last REMB if(keys(%{$soldes}) == 0);
522
523 my ($biggest_debtor, $smallest_creditor) = select_exchange_couple($soldes);
524 compute_reimbursment($biggest_debtor, $smallest_creditor, $soldes);
525 }
526 print_remboursements();
527 }
528 case "Afficher les remboursements" {
529 print_remboursements();
87 } 530 }
88 switch ($action) { 531 case "Sortir" {
89 case "Ajouter un participant" { 532 last GLOBALE;
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 } 533 }
534 }
446} 535}