31, 2=>28+date('L'), 3=>31, 4=>30, 5=>31, 6=>30, 7=>31, 8=>31, 9=>30, 10=>31, 11=>30, 12=>31); $fin_mois = mktime(23, 59, 59, $num_mois, $dernier_jour[$num_mois], $annee); $bornes = array($debut_mois, $fin_mois); return $bornes; } //Return what A must pay to B function dettes($A, $B, $debut_mois, $fin_mois) { global $bdd; //When A paid and B was here $reqA_B = $bdd->prepare('SELECT id, date, montant, copains, invites FROM depenses WHERE date>'.$debut_mois.' AND date<'.$fin_mois.' AND de=:param1 AND (copains LIKE "%,'.(int) $B.',%" OR copains LIKE "%,'.(int)$B.'" OR copains LIKE "'.(int) $B.',%" OR copains LIKE "'.(int) $B.'")'); $reqA_B->bindvalue(':param1',$A); $reqA_B->execute(); //When B paid and A was here $reqB_A = $bdd->prepare('SELECT id, date, montant, copains, invites FROM depenses WHERE date>'.$debut_mois.' AND date<'.$fin_mois.' AND de=:param1 AND (copains LIKE "%,'.(int) $A.',%" OR copains LIKE "%,'.(int)$A.'" OR copains LIKE "'.(int) $A.',%" OR copains LIKE "'.(int) $A.'")'); $reqB_A->bindvalue(':param1',$B); $reqB_A->execute(); //What A already paid to B $reqPaiementsA_B = $bdd -> prepare('SELECT paiements.montant AS montant FROM paiements LEFT JOIN depenses ON paiements.id_depense=depenses.id WHERE depenses.date >'.$debut_mois.' AND depenses.date<'.$fin_mois.' AND paiements.de=:de AND paiements.a=:a'); $reqPaiementsA_B->bindvalue(':de',$A); $reqPaiementsA_B->bindvalue(':a',$B); $reqPaiementsA_B->execute(); //Same thing for B to A $reqPaiementsB_A = $bdd -> prepare('SELECT paiements.montant AS montant FROM paiements LEFT JOIN depenses ON paiements.id_depense=depenses.id WHERE depenses.date >'.$debut_mois.' AND depenses.date<'.$fin_mois.' AND paiements.de=:de AND paiements.a=:a'); $reqPaiementsB_A->bindvalue(':de',$B); $reqPaiementsB_A->bindvalue(':a',$A); $reqPaiementsB_A->execute(); //$deltaAB : What A must pay to B $deltaAB = 0; while($donneesA_B = $reqA_B->fetch()) { //We get the price of the meal, divided by the number of people who ate //nb of comma + 1 $deltaAB -= $donneesA_B['montant']/(substr_count($donneesA_B['copains'], ',') + 1 + $donneesA_B['invites']); } while($donneesB_A = $reqB_A->fetch()) //idem { $deltaAB += $donneesB_A['montant']/(substr_count($donneesB_A['copains'], ',') + 1 + $donneesB_A['invites']); } while($donneesPaiementsA_B = $reqPaiementsA_B->fetch()) //what has been already paid { $deltaAB -= $donneesPaiementsA_B['montant']; } while($donneesPaiementsB_A = $reqPaiementsB_A->fetch()) //idem { $deltaAB += $donneesPaiementsB_A['montant']; } return $deltaAB; } // Reduces the matrix in n steps function simplify ($copains){ // We work directly with $debts global $debts; global $matrix; $max = maximum($debts); // On cherche le plus proche en valeur absolue du maximum $near = nearest($debts, $max); // On en déduit l'écart entre leurs valeurs absolues $delta = $max["val"] + $near["val"]; // Case : //A : max 100 //B :near -90 // delta 10 // m[A][B] -90 // m[B][A] 90 if ($delta > 0){ $matrix[$max["id"]][$near["id"]] = -$debts[$near["id"]]; $matrix[$near["id"]][$max["id"]] = $debts[$near["id"]]; $debts[$max["id"]] = $delta; $debts[$near["id"]] = 0; } else { $matrix[$max["id"]][$near["id"]] = $debts[$max["id"]]; $matrix[$near["id"]][$max["id"]] = -$debts[$max["id"]]; $debts[$max["id"]] = 0; $debts[$near["id"]] = $delta; } return $matrix; } // Return the nearest value function nearest($debts, $max) { // Initialize with the maximum distance $d_min = max($debts) - min($debts); // Initialize the default id to one key in the array $debts_keys = array_keys($debts); $id_min = $debts_keys[1]; foreach($debts as $id => $val) { // Computes the absolute distance $d = abs($max["val"] + $val); // If it's a new minimum AND the value isn't positive if ($d <= $d_min && $val < 0) { $id_min = $id; $d_min = $d; } } return array("id"=>$id_min, "val"=>$debts[$id_min]); } function maximum($tableau) { $max["id"] = 0; $max["val"] = 0; foreach($tableau as $id=>$val) { if($val >= $max["val"]) { $max["val"] = $val; $max["id"] = $id; } } return $max; } // Function to insert a regulation between A and B for the simplification // system only. function inserer_paiement_rbmt($donnees_depense, $de_paiement, $a_paiement, $rbmt) { if ($de_paiement == $a_paiement) return 1; global $bdd; // We get all the payments between a and de (we just filter thanks to the // id which is linked to the a field) $paiement_existe_req = $bdd->prepare('SELECT montant, COUNT(*) AS nbre_paiement FROM paiements WHERE id_depense=:id_depense AND de=:de'); $paiement_existe_req->bindValue(':id_depense', $donnees_depense['id']); $paiement_existe_req->bindValue(':de', $de_paiement); $paiement_existe_req->execute(); $deja_paye = 0; while ($donnees = $paiement_existe_req->fetch()) { $deja_paye += $donnees['montant']; } $montant = $donnees_depense['montant']/(substr_count($donnees_depense['copains'], ',') + 1 + $donnees_depense['invites']) - $deja_paye; $req = $bdd->prepare('INSERT INTO paiements(id, de, a, id_depense, date, montant, rbmt) VALUES("", :de, :a, :id_depense, :date, :montant, :rbmt)'); $req->bindValue(':de', $de_paiement); $req->bindValue(':a', $a_paiement); $req->bindValue(':id_depense', $donnees_depense['id']); $req->bindValue(':date', time()); $req->bindValue(':rbmt', $rbmt); $req->bindValue(':montant', $montant); $req->execute(); return 1; } if(!(isset($_GET['confirm']) && isset($_POST['matrix']) && isset($_POST['copains']) && isset($_POST['date']))) { ?> Bouffe@Ulm : remboursements

Remboursements simplifiés

query('SELECT id, nom FROM copains ORDER BY nom ASC'); while($copain = $req->fetch()) { $copains[$copain['id']] = $copain['nom']; //And put it in an array } ?>

Copains :
query('SELECT id, nom FROM copains ORDER BY nom ASC'); while($donnees2 = $req2->fetch()) { echo "
"; } ?>

ou retour à l'accueil

prepare('SELECT nom, id FROM copains ORDER BY nom ASC'); $req->execute(); // Fill an array only with friends who are participating while($copain = $req->fetch()) { // If the friend was selected if(isset($_POST['copain_'.$copain['id']])) $copains[$copain['id']] = $copain['nom']; } $n = count($copains); // Usefull for the size of the array // Create the temporal bounds for the requests $debut_mois = 0; $fin_mois = mktime($_POST['AM_PM'], 0, 0, $_POST['mois'], $_POST['jour'], $_POST['annee']); // We create an array containing the total debts and a matrix foreach($copains as $idA=>$nameA) { $debts[$idA] = 0; foreach($copains as $idB=>$nameB) { $matrix[$idA][$idB] = 0; } } // We initialize the debts array foreach($copains as $keyA=>$copainA) { foreach($copains as $keyB=>$copainB) { $dette = dettes($keyA,$keyB, $debut_mois, $fin_mois); $deltaAB = $dette; $debts[$keyA] += $deltaAB; } } // To avoid an infinite while loop, we have to round the value foreach($debts as &$val) $val = round($val, 2); // Should be zero, but with float error, it may be non null $error = array_sum($debts); // Do it in n steps for ($i=0; $i<$n; $i++) $matrix = simplify($copains); echo "

Récapitulatif

"; // Output the matrix foreach($copains as $keyA=>$copainA) { foreach($copains as $keyB=>$copainB) { if (isset($matrix[$keyA][$keyB]) && $matrix[$keyA][$keyB] > 0) echo '' . $copains[$keyA] . ' doit '. round($matrix[$keyA][$keyB], 2) . ' à ' . $copains[$keyB] .'
'; } } // Show a forme to confirm ?>

ou Retour à l'accueil
Attention, cette opération est irréversible et annulera tous les paiements jusqu'à la date choisie.

prepare('INSERT INTO remboursements(date, matrix, id, copains) VALUES(:date, :matrix, "", :copains)'); $req->bindValue(':date', $_POST['date']); $req->bindValue(':matrix', $_POST['matrix']); $req->bindValue(':copains', $_POST['copains']); // We insert the new matrix in the table if (!$req->execute()) echo "Une erreur est survenue"; else { // We get the biggest id (here, the one we just created) $req = $bdd->query('SELECT MAX(id) FROM remboursements'); $retour = $req->fetch(); $id = $retour["MAX(id)"]; // Now we can simplify the matrix by inserting as many regulation as // necessary $copains = unserialize($_POST['copains']); foreach($copains as $a=>$nomA) { foreach($copains as $de=>$nomB) { $req = $bdd->prepare('SELECT id, de, copains, montant, invites FROM depenses WHERE (copains LIKE "%,'.$de.',%" OR copains LIKE "%,'.$de.'" OR copains LIKE "'.$de.',%" OR copains LIKE "'.$de.'") AND de=:a AND date>:debut_mois AND date<:fin_mois'); $req->bindValue(':a', $a); // Bounds are 0 and the date given in the previous form $req->bindValue(':debut_mois', 0); $req->bindValue(':fin_mois', $_POST['date']); $req->execute(); // We've got a bunch of exchange to insert (with a flag to specify we // added it here) while($donnees = $req->fetch()) { if(!empty($de)) { inserer_paiement_rbmt($donnees, $de, $a, $id); } else { //For all the people who participate... $participants = explode(',', $donnees['copains']); foreach($participants as $participant) { // If we've got someone which participates to the // simplification if (in_array($participant, array_keys($copains))) inserer_paiement_rbmt($donnees, $participant, $a, $id); } } } } } // Everything went right header('location: message.php?id=14'); } } // If we want to delete one and have the id else if(isset($_GET['id']) && isset($_GET['action']) && $_GET['action'] == "del") { // If already confirmed if(isset($_POST['confirm'])) { // We delete the simplification AND the regulation it created if($bdd->query('DELETE FROM remboursements WHERE id='.$_GET['id']) && $bdd->query('DELETE FROM paiements WHERE rbmt='.$_GET['id'])) header('location: message.php?id=15'); else header('location: message.php?id=16'); } else { $req = $bdd->prepare('SELECT * FROM remboursements WHERE id='.$_GET['id']); ?>

ou Retour à l'accueil

Nouveau remboursement | Retour à l\'accueil'; echo '

Remboursements précédents

'; $req = $bdd->prepare('SELECT * FROM remboursements '); $req->execute(); $table = ''; $links = ''; while($data = $req->fetch()) { // Reset the list of friend to '' $liste = ''; // Extract info from $data // First the date $date = date('j/m', $data['date']); // List of friend $copains = unserialize($data['copains']); foreach($copains as $nom) $liste .= ', ' . $nom; // If we clicked on one particular remboursement if (isset($_GET['id']) && $_GET['id'] == $data['id'] && isset($_GET['action']) && $_GET['action'] == "show") { $table .= "
  • Le {$date}{$liste} - Supprimer"; $matrix = unserialize($data['matrix']); // We build an array containing the data we want to print // and a list containing the other remboursement $table.=' '; //Construct the header of the table and display it for the previous months foreach($copains as $key => $copain) { if($_SESSION['nom'] == $copain) $copain = ''.$copain.''; $table .= ''; } $table .= ''; foreach($copains as $keyA=>$copainA) { if($_SESSION['nom'] == $copainA) $copainA = ''.$copains[$keyA].''; $table .= ''; foreach($copains as $keyB=>$copainB) { if($matrix[$keyA][$keyB] <= 0) $table .= ''; else $table .= ''; } $table .= ''; } $table .= '
    Doit\À'.$copain.'
    '.$copainA.'-'.$matrix[$keyA][$keyB].'
  • '; } // Else, we print a link else $links .= "
  • Le {$date}{$liste} - Supprimer
  • "; } } echo '

    '; echo '

    '; echo 'Retour à l\'accueil'; echo '

    '; echo ''; ?>