#!/usr/bin/en perl
# The MIT License (MIT)
#
# Copyright (c) 2011-2015 Ismaël Bouya http://www.normalesup.org/~bouya/
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
use Switch;
use strict;
my $file = "comptes.data";
my @actions=('Ajouter un participant');
my %participants = ();
my @transactions = ();
my @descriptions = ();
my $evenement_def;
my $remboursements = "";
if($#ARGV==0) {
open FILE, $ARGV[0] || die "Impossible de lire le fichier";
$evenement_def = <FILE>;
chomp($evenement_def);
while(my $noms = <FILE>) {
if($noms eq "\n") { last; }
my ($numero,$nom) = split(/ /,$noms,2);
chomp($nom);
$participants{$nom} = $numero;
}
while(my $transaction = <FILE>) {
if($transaction eq "\n") { last; }
chomp($transaction);
push(@transactions,$transaction);
my $description = <FILE>;
chomp($description);
push(@descriptions,$description);
}
$file = $ARGV[0];
}
GLOBALE: while(1) {
if(keys(%participants)>0) {
$actions[1]="Ajouter une dépense";
$actions[2]="Enregistrer";
}
if(scalar(@transactions)>0) {
$actions[3]="Voir les dépenses de quelqu'un";
$actions[2]="Enregistrer";
$actions[4]="Equilibrage";
$actions[5]="Voir une transaction";
}
my $action;
while(1) {
my $i = 1;
my $var;
my @vart = ( @actions, 'Sortir' );
my $message = '';
foreach $var ( @vart ) {
$message .= $i++.') '.$var."\n";
}
print $message;
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$action = $vart[$var-1];
last;
}
switch ($action) {
case "Ajouter un participant" {
print "Nom du participant\n";
my $participant = <STDIN>;
chomp($participant);
$participants{$participant} = keys(%participants)+1;
}
case "Ajouter une dépense" {
print "Qui a payé ?\n";
my $paye;
while(1) {
my $i = 1;
my $var;
my @vart = ( keys(%participants), "Annuler" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$paye = $vart[$var-1];
last;
}
if($paye eq "Annuler") {
next GLOBALE;
}
print "Quoi ?\n";
my $description = <STDIN>;
chomp($description);
print "Combien ?\n";
my $prix = <STDIN>;
chomp($prix);
print "Pour qui ?\n";
my $repartition = "";
my $total_parts = 0;
DESTS: while(1) {
my $dest;
while(1) {
my $i = 1;
my $var;
my @vart = ( keys(%participants), "Ajouter à tous", "Fini" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$dest = $vart[$var-1];
last;
}
switch($dest) {
case "Fini" {
if($repartition eq "") { print "Annulé\n"; }
elsif($total_parts == 0) {
print "Le nombre total de parts est nul, il faut en ajouter !\n";
next DESTS;
}
else {
push(@transactions, $participants{$paye}.' '.$prix.$repartition);
push(@descriptions, $description);
}
last DESTS;
}
case "Ajouter à tous" {
print "Nombre de parts ?\n";
my $parts = <STDIN>;
chomp($parts);
if(!($parts == 0)) {
foreach my $participant (keys(%participants)) {
$repartition .= ' '.$participants{$participant}.':'.scalar($parts);
$total_parts += scalar($parts);
}
}
}
else {
print "Nombre de parts ?\n";
my $parts = <STDIN>;
chomp($parts);
if(!($parts == 0)) {
$repartition .= ' '.$participants{$dest}.':'.scalar($parts);
$total_parts += scalar($parts);
}
}
}
}
}
case "Voir les dépenses de quelqu'un" {
my $personne;
while(1) {
my $i = 1;
my $var;
my @vart = ( keys(%participants), "Annuler" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$personne = $vart[$var-1];
last;
}
if($personne eq "Annuler") {
next GLOBALE;
}
my $depenses = 0;
my $frais = 0;
foreach my $transaction (@transactions) {
my @table_trans = split(/ /,$transaction);
my $payeur = shift(@table_trans);
my $prix = shift(@table_trans);
if($payeur == $participants{$personne}) {
$depenses += $prix;
}
my $parts = 0;
my $frac = 0;
my $repartition;
foreach $repartition (@table_trans) {
my ($pers,$part) = split(/:/,$repartition);
if($pers == $participants{$personne}) {
$frac += $part;
}
$parts += $part;
}
$frais += $prix*$frac/$parts;
}
print $personne." a payé ".$depenses." EUR\n";
print "et a pour ".sprintf("%.2f",$frais)." EUR de frais au total.\n";
print "Il a donc un solde de ".sprintf("%.2f",$depenses-$frais)." EUR\n";
my $pause = <STDIN>;
}
case "Voir une transaction" {
my $transaction;
while(1) {
my $i = 1;
my $var;
my @vart = ( @descriptions, "Annuler" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$transaction = $var-1;
last;
}
my @table_trans = split(/ /,$transactions[$transaction]);
my $payeur = shift(@table_trans);
my $prix = shift(@table_trans);
my $Tparts = 0;
my $repartition;
my %parts;
foreach my $pers (keys(%participants)) {
if($payeur == $participants{$pers}) {
print $descriptions[$transaction]." (payé par ".$pers."), ".$prix." EUR\n";
last
}
}
foreach $repartition (@table_trans) {
my ($pers,$part) = split(/:/,$repartition);
$Tparts += $part;
$parts{$pers} += $part;
}
foreach my $pers (keys(%participants)) {
if(!exists $parts{$participants{$pers}}) {
next;
}
print $pers.", ".$parts{$participants{$pers}}." part(s), soit ". $prix*$parts{$participants{$pers}}/$Tparts." EUR\n";
}
my $pause = <STDIN>;
}
case "Enregistrer" {
print "Nom de l'événement ?";
if(!($evenement_def eq "")) {
print " [".$evenement_def."]";
}
print "\n";
my $evenement = <STDIN>;
chomp($evenement);
if($evenement eq "") {
$evenement = $evenement_def;
}
open FILE, ">".$file;
print FILE $evenement."\n";
my $key;
foreach $key (keys(%participants)) {
print FILE $participants{$key}." ".$key."\n";
}
print FILE "\n";
for(my $i=0;$i<scalar(@transactions);$i++) {
print FILE $transactions[$i]."\n";
print FILE $descriptions[$i]."\n";
}
print FILE "\n";
print FILE $remboursements;
close FILE;
}
case "Equilibrage" {
my %Tdepenses = ();
my %Tfrais = ();
my %Tsolde = ();
$remboursements = "";
foreach my $Ttransaction (@transactions) {
my @Ttable_trans = split(/ /,$Ttransaction);
my $Tpayeur = shift(@Ttable_trans);
my $Tprix = shift(@Ttable_trans);
$Tdepenses{$Tpayeur} = $Tdepenses{$Tpayeur} + $Tprix;
my $Tparts = 0;
my $Tfrac = 0;
my $Trepartition;
foreach $Trepartition (@Ttable_trans) {
my ($Tpers,$Tpart) = split(/:/,$Trepartition);
$Tparts += $Tpart;
}
foreach $Trepartition (@Ttable_trans) {
my ($Tpers,$Tpart) = split(/:/,$Trepartition);
$Tfrais{$Tpers} = $Tfrais{$Tpers} + $Tprix*$Tpart/$Tparts;
}
}
foreach my $Tpersonne (keys(%participants)) {
my $numero = $participants{$Tpersonne};
$Tsolde{$Tpersonne} = sprintf("%.2f",$Tdepenses{$numero}-$Tfrais{$numero});
print $Tpersonne." a un solde de ".$Tsolde{$Tpersonne}." EUR\n";
}
my $pause = <STDIN>;
print "Y-a-t-il des remboursements plus aisés ?\n";
my $ouinon;
while(1) {
my $i = 1;
my $var;
my @vart = ( "Oui", "Non" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$ouinon = $vart[$var-1];
last;
}
AISE: while($ouinon eq "Oui") {
print "Qui ?\n";
my $personne;
while(1) {
my $i = 1;
my $var;
my @vart = ( keys(%participants), "Fini" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$personne = $vart[$var-1];
last;
}
if($personne eq "Fini") { last AISE; }
print "Avec qui ?\n";
my $personneb;
while(1) {
my $i = 1;
my $var;
my @vart = ( keys(%participants), "Annuler" );
foreach $var ( @vart ) {
print $i++.') '.$var."\n";
}
$var = <STDIN>;
chop($var);
if(/\D/ || $var < 1 || $var > $i) {
print "Mauvaise entrée\n";
next;
}
$personneb = $vart[$var-1];
last;
}
if($personneb eq "Annuler") { next AISE; }
if($Tsolde{$personne}*$Tsolde{$personneb}<0) {
my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
my $inf = (abs($Tsolde{$personne})<abs($Tsolde{$personneb}))?abs($Tsolde{$personne}):abs($Tsolde{$personneb});
$remboursements .= $pers_inf." doit ".$inf." EUR à ".$pers_sup."\n";
$Tsolde{$pers_inf} += $inf;
$Tsolde{$pers_sup} -= $inf;
}
}
# Une boucle pour détecter si on a des couples qui s'annulent mutuellement
COUPLE: foreach my $personne (keys(%participants)) {
if($Tsolde{$personne} == 0) { next; }
foreach my $personneb (keys(%participants)) {
if($Tsolde{$personneb} + $Tsolde{$personne} != 0) { next; }
my $pers_inf = ($Tsolde{$personne}<0)?$personne:$personneb;
my $pers_sup = ($Tsolde{$personne}>0)?$personne:$personneb;
my $val = abs($Tsolde{$personne});
$remboursements .= $pers_inf." doit ".$val." EUR à ".$pers_sup."\n";
$Tsolde{$pers_inf} += $val;
$Tsolde{$pers_sup} -= $val;
next COUPLE;
}
}
REMB: while(1) {
# On supprime les 0, et on fait deux hashs
my %Tneg = ();
my %Tpos = ();
foreach my $personne (keys(%Tsolde)) {
if($Tsolde{$personne} == 0) { delete $Tsolde{$personne}; }
elsif($Tsolde{$personne} < 0) { $Tneg{$personne} = $Tsolde{$personne}; }
elsif($Tsolde{$personne} > 0) { $Tpos{$personne} = $Tsolde{$personne}; }
}
if(keys(%Tneg) == 0) {
last REMB;
}
foreach my $neg (sort { $Tneg{$a} cmp $Tneg{$b} } keys %Tneg) {
my $max = 0;
my $positif = 0;
foreach my $pos (sort { $Tpos{$a} cmp $Tpos{$b} } keys %Tpos) {
if($Tpos{$pos} + $Tneg{$neg}>0) {
$positif = $pos;
last;
}
$max = $pos;
}
if(!($max eq 0)) {
$remboursements .= $neg." doit ".$Tsolde{$max}." EUR à ".$max."\n";
$Tsolde{$neg} += $Tsolde{$max};
delete $Tsolde{$max};
}
else {
$remboursements .= $neg." doit ".-$Tsolde{$neg}." EUR à ".$positif."\n";
$Tsolde{$positif} += $Tsolde{$neg};
delete $Tsolde{$neg};
}
next REMB;
}
}
print $remboursements;
my $pause = <STDIN>;
}
case "Sortir" {
last GLOBALE;
}
}
}