From 2134a2c28425c0f31658e79e621a79b8e8700c53 Mon Sep 17 00:00:00 2001 From: Phyks Date: Mon, 23 Sep 2013 23:08:01 +0200 Subject: [PATCH] First version of global payback --- inc/GlobalPaybacks.class.php | 108 +++++++++++++++++++++++ inc/UsersIn.class.php | 2 +- inc/UsersInGlobalPayback.class.php | 132 ++++++++++++++++++++++++++++ index.php | 132 +++++++++++++++++++++++++--- tpl/default_en/css/style.css | 4 + tpl/default_fr/css/style.css | 23 ++++- tpl/default_fr/manage_paybacks.html | 43 +++++++++ 7 files changed, 429 insertions(+), 15 deletions(-) create mode 100644 inc/GlobalPaybacks.class.php create mode 100644 inc/UsersInGlobalPayback.class.php create mode 100644 tpl/default_fr/manage_paybacks.html diff --git a/inc/GlobalPaybacks.class.php b/inc/GlobalPaybacks.class.php new file mode 100644 index 0000000..00d05aa --- /dev/null +++ b/inc/GlobalPaybacks.class.php @@ -0,0 +1,108 @@ +'key', + 'date'=>'date', + ); + + public function __construct() { + parent::__construct(); + $this->users_in = new UsersInGlobalPayback(); + } + + // Getters + // ======= + public function getId() { + return $this->id; + } + + public function getDate($format = "d-m-Y H:i") { + if(!empty($this->date)) + return $this->date->format($format); + else + return false; + } + + public function getUsersIn() { + return $this->users_in; + } + + // Setters + // ======= + public function setId($id) { + $this->users_in->setInvoiceId($id); + $this->id = (int) $id; + } + + public function setDate($minute, $hour, $day, $month, $year) { + if((int) $minute < 10) $minute = '0'.$minute; + + $this->date = DateTime::createFromFormat('Y-n-j G:i', $year.'-'.(int) $month.'-'.(int) $day.' '.(int) $hour.':'.$minute); + } + + public function setUsersIn($users_in) { + // Note : users_in in param is an array with users in listed and guests for each user + $this->users_in->set($users_in); + } + + // Maps htmlspecialchars on the class before display + // ================================================= + public function secureDisplay() { + $this->id = (int) $this->id; + + return $this; + } + + // Restores object from array + // ========================== + public function sessionRestore($data, $serialized = false) { + if($serialized) { + $data = unserialize($data); + } + + $this->setId($data['id']); + $this->date = DateTime::createFromFormat('Y-m-d H:i:s', $data['date']); + } + + // Override parent load() method + // ============================= + public function load($fields = NULL, $first_only = false) { + $return = parent::load($fields, $first_only); // Execute parent load + + if(is_array($return)) { + foreach(array_keys($return) as $key) { + $return[$key]->users_in->load(); // Load users in for each global paybacks + } + } + elseif(is_a($return, 'GlobalPayback')) { + $return->users_in->load(); + } + + return $return; // Return the loaded elements + } + + // Override parent save() method + // ============================ + public function save() { + parent::save(); // Save invoice element + + $this->users_in->save(); // Save users in + } + + // Override parent delete() method + // =============================== + public function delete() { + parent::delete(); // Delete invoice element + + $this->users_in->delete(); // Also delete users in + } + } diff --git a/inc/UsersIn.class.php b/inc/UsersIn.class.php index e449f46..f740b1f 100644 --- a/inc/UsersIn.class.php +++ b/inc/UsersIn.class.php @@ -58,7 +58,7 @@ foreach($this->users_list as $user=>$guests) { $temp_array[(int) $user] = (int) $guests; } - $this->users_in = $temp_array; + $this->users_list = $temp_array; return $this; } diff --git a/inc/UsersInGlobalPayback.class.php b/inc/UsersInGlobalPayback.class.php new file mode 100644 index 0000000..9c35374 --- /dev/null +++ b/inc/UsersInGlobalPayback.class.php @@ -0,0 +1,132 @@ +'int', + 'user1_id'=>'int', + 'user2_id'=>'int', + 'amount'=>'float' + ); + + public function __construct() { + parent::__construct(); + $users_list = array(); + } + + // Getters + // ======= + public function getPaybackId() { + return $this->payback_id; + } + + public function get() { + return $this->users_list; + } + + // Setters + // ======= + public function setPaybackId($id) { + $this->payback_id = (int) $id; + } + + public function set($users_in) { + $this->users_list = $users_in; + } + + // Maps htmlspecialchars on the class before display + // ================================================= + public function secureDisplay() { + $this->payback_id = (int) $this->payback_id; + + $temp_array = array(); + foreach($this->users_list as $user1=>$temp) { + foreach($temp as $user2=>$amount) { + $temp_array[(int) $user1][(int) [$user2]] = (float) $amount; + } + } + $this->users_list = $temp_array; + + return $this; + } + + // Override load() method + // ====================== + public function load() { + $query = 'SELECT '; + + $i = false; + foreach($this->fields as $field=>$type) { + if($i) { $query .= ','; } else { $i = true; } + + $query .= $field; + } + + $query .= ' FROM '.MYSQL_PREFIX.$this->TABLE_NAME.' WHERE payback_id=:payback_id'; + + $query = $this->getConnection()->prepare($query); + $query->bindParam(':payback_id', $this->payback_id); + $query->execute(); + + $results = $query->fetchAll(); + $this->users_list = array(); + foreach($results as $result) { + $this->users_list[(int) $result['user1_id']][(int) $result['user2_id']] = (float) $result['amount']; + } + } + + // Override save() method + // ====================== + public function save() { + // TODO : Optimize ? + + $query = 'SELECT COUNT(payback_id) FROM '.MYSQL_PREFIX.$this->TABLE_NAME.' WHERE payback_id=:payback_id'; + $query = $this->getConnection()->prepare($query); + $query->bindParam(':payback_id', $this->payback_id); + $query->execute(); + + $count = $query->fetchColumn(0); + + if($count != 0) { + // If there are already some records, delete them first + $query = $this->getConnection()->prepare('DELETE FROM '.MYSQL_PREFIX.$this->TABLE_NAME.' WHERE payback_id=:payback_id'); + $query->bindParam(':payback_id', $this->payback_id); + $query->execute(); + } + + $query = 'INSERT INTO '.MYSQL_PREFIX.$this->TABLE_NAME.'('; + $i = false; + foreach($this->fields as $field=>$type) { + if($i) { $query .= ','; } else { $i = true;} + $query .= $field; + } + + $query .= ') VALUES(:payback_id, :user1_id, :user2_id, :amount)'; + + $query = $this->getConnection()->prepare($query); + + $query->bindParam(':payback_id', $this->payback_id); + + foreach($this->users_list as $user1=>$temp) { + foreach($temp as $user2=>$amount) { + $query->bindParam(':user1_id', intval($user1)); + $query->bindParam(':user2_id', intval($user2)); + $query->bindParam(':amount', floatval($amount)); + $query->execute(); + } + } + } + + // Override delete() method + // ======================== + public function delete() { + $query = $this->getConnection()->prepare('DELETE FROM '.MYSQL_PREFIX.$this->TABLE_NAME.' WHERE payback_id=:payback_id'); + $query->bindParam(':payback_id', $this->payback_id); + $query->execute(); + } + } diff --git a/index.php b/index.php index 8e406b4..23e6ff1 100644 --- a/index.php +++ b/index.php @@ -23,6 +23,7 @@ require_once('inc/User.class.php'); require_once('inc/Invoices.class.php'); require_once('inc/Paybacks.class.php'); + require_once('inc/GlobalPaybacks.class.php'); require_once('inc/rain.tpl.class.php'); require_once('inc/functions.php'); require_once('inc/Ban.inc.php'); @@ -353,29 +354,29 @@ foreach($config as $line_number=>$line) { if(strpos(trim($line), "MYSQL_HOST") !== false) - $config[$line_number] = "\tdefine('MYSQL_HOST', '".$_POST['mysql_host']."');\n"; + $config[$line_number] = "\tdefine('MYSQL_HOST', '".$_POST['mysql_host']."');"; elseif(strpos(trim($line), "MYSQL_LOGIN") !== false) - $config[$line_number] = "\tdefine('MYSQL_LOGIN', '".$_POST['mysql_login']."');\n"; + $config[$line_number] = "\tdefine('MYSQL_LOGIN', '".$_POST['mysql_login']."');"; elseif(strpos(trim($line), "MYSQL_PASSWORD") !== false && !empty($_POST['mysql_password'])) - $config[$line_number] = "\tdefine('MYSQL_PASSWORD', '".$_POST['mysql_password']."');\n"; + $config[$line_number] = "\tdefine('MYSQL_PASSWORD', '".$_POST['mysql_password']."');"; elseif(strpos(trim($line), "MYSQL_DB") !== false) - $config[$line_number] = "\tdefine('MYSQL_DB', '".$_POST['mysql_db']."');\n"; + $config[$line_number] = "\tdefine('MYSQL_DB', '".$_POST['mysql_db']."');"; elseif(strpos(trim($line), "MYSQL_PREFIX") !== false && !empty($_POST['mysql_prefix'])) - $config[$line_number] = "\tdefine('MYSQL_PREFIX', '".$_POST['mysql_prefix']."');\n"; + $config[$line_number] = "\tdefine('MYSQL_PREFIX', '".$_POST['mysql_prefix']."');"; elseif(strpos(trim($line), "INSTANCE_TITLE") !== false) - $config[$line_number] = "\tdefine('INSTANCE_TITLE', '".$_POST['instance_title']."');\n"; + $config[$line_number] = "\tdefine('INSTANCE_TITLE', '".$_POST['instance_title']."');"; elseif(strpos(trim($line), "BASE_URL") !== false) - $config[$line_number] = "\tdefine('BASE_URL', '".$_POST['base_url']."');\n"; + $config[$line_number] = "\tdefine('BASE_URL', '".$_POST['base_url']."');"; elseif(strpos(trim($line), "CURRENCY") !== false) - $config[$line_number] = "\tdefine('CURRENCY', '".$_POST['currency']."');\n"; + $config[$line_number] = "\tdefine('CURRENCY', '".$_POST['currency']."');"; elseif(strpos(trim($line), "EMAIL_WEBMASTER") !== false) - $config[$line_number] = "\tdefine('EMAIL_WEBMASTER', '".$_POST['email_webmaster']."');\n"; + $config[$line_number] = "\tdefine('EMAIL_WEBMASTER', '".$_POST['email_webmaster']."');"; elseif(strpos(trim($line), "TEMPLATE_DIR") !== false) - $config[$line_number] = "\tdefine('TEMPLATE_DIR', 'tpl/".$_POST['template']."/');\n"; + $config[$line_number] = "\tdefine('TEMPLATE_DIR', 'tpl/".$_POST['template']."/');"; elseif(strpos(trim($line), "LANG") !== false) - $config[$line_number] = "\tdefine('LANG', '".substr($_POST['template'], -2)."');\n"; + $config[$line_number] = "\tdefine('LANG', '".substr($_POST['template'], -2)."');"; elseif(strpos(trim($line), 'date_default_timezone_set') !== false) - $config[$line_number] = "\tdate_default_timezone_set('".$_POST['timezone']."');\n"; + $config[$line_number] = "\tdate_default_timezone_set('".$_POST['timezone']."');"; } if(file_put_contents("data/config.php", $config)) { @@ -675,6 +676,113 @@ } break; + case "manage_paybacks": + if(empty($_GET['new'])) { + $tpl->assign('list', true); + $tpl->assign('global_paybacks', array(array("id"=>1, "date"=>"now"))); + } + else { + if(!empty($_POST['users_in'])) { + $global_payback = new GlobalPayback(); + + // Backup database + if(!is_dir('db_backup')) { + mkdir('db_backup'); + } + system("mysqldump -h ".MYSQL_HOST." -u ".MYSQL_LOGIN." -p ".MYSQL_PASSWORD." ".MYSQL_DB." > db_backup/".date('d-m-Y_H:i')); + + $users_in = array(); + foreach($_POST['users_in'] as $user1_id) { + $user1_id = intval($user1_id); + foreach($_POST['users_in'] as $user2_id) { + $user2_id = intval($user2_id); + if($user1_id == $user2_id) { + $users_in[$user1_id][$user2_id] = 0; + } + elseif(!empty($users_in[$user2_id][$user1_id])) { + if($users_in[$user2_id][$user1_id] > 0) { + $users_in[$user1_id][$user2_id] = 0; + } + else { + $users_in[$user1_id][$user2_id] = -$users_in[$user1_id][$user2_id]; + $users_in[$user2_id][$user1_id] = 0; + } + } + else { + // Get the amount user1 owes to user2 + $users_in[$user1_id][$user2_id] = 0; + + // Confirm all paybacks when user2 is buyer + $invoices = new Invoice(); + $invoices = $invoices->load(array('buyer'=>$user2_id)); + + if($invoices !== false) { + foreach($invoices as $invoice) { + $paybacks = new Payback(); + $paybacks = $paybacks->load(array('invoice_id'=>$invoice->getId(), 'to_user'=>$user2_id, 'from_user'=>$user1_id)); + + if($paybacks === false) { + $payback = new Payback(); + $payback->setTo($user2_id); + $payback->setFrom($user1_id); + $payback->setAmount($invoice->getAmountPerPerson($user1_id)); + $payback->setInvoice($invoice->getId()); + $payback->setDate(date('i'), date('G'), date('j'), date('n'), date('Y')); + $payback->save(); + + // Add the amount to what user1 owes to user2 + $users_in[$user1_id][$user2_id] += $payback->getAmount(); + } + } + } + + // Confirm all paybacks when from is buyer + $invoices = new Invoice(); + $invoices = $invoices->load(array('buyer'=>$user1_id)); + + if($invoices !== false) { + foreach($invoices as $invoice) { + $paybacks = new Payback(); + $paybacks = $paybacks->load(array('invoice_id'=>$invoice->getId(), 'to_user'=>$user1_id, 'from_user'=>$user2_id)); + + if($paybacks === false) { + $payback = new Payback(); + $payback->setTo($user1_id); + $payback->setFrom($user2_id); + $payback->setAmount($invoice->getAmountPerPerson($user2_id)); + $payback->setInvoice($invoice->getId()); + $payback->setDate(date('i'), date('G'), date('j'), date('n'), date('Y')); + $payback->save(); + + // Substract the amount to what user1 owes to user2 + $users_in[$user1_id][$user2_id] -= $payback->getAmount(); + } + } + } + } + } + } + + $global_payback->setUsersIn($users_in); + $global_payback->setDate(date('i'), date('G'), date('j'), date('n'), date('Y')); + $global_payback->save(); + + // Clear the cache + ($cached_files = glob(raintpl::$cache_dir."*.rtpl.php")) or ($cached_files = array()); + array_map("unlink", $cached_files); + + header('location: index.php?do=edit_users&'.$get_redir); + exit(); + } + + $users_list = new User(); + $users_list = $users_list->load(); + + $tpl->assign('users', $users_list); + } + $tpl->draw('manage_paybacks'); + break; + default: if(empty($_GET['all'])) diff --git a/tpl/default_en/css/style.css b/tpl/default_en/css/style.css index 06ebd14..1b4c4b8 100644 --- a/tpl/default_en/css/style.css +++ b/tpl/default_en/css/style.css @@ -63,6 +63,10 @@ input[type="checkbox"] { text-align: center; } +.red { + color: red; +} + .label-block { display: inline-block; text-align: right; diff --git a/tpl/default_fr/css/style.css b/tpl/default_fr/css/style.css index 06ebd14..45d6680 100644 --- a/tpl/default_fr/css/style.css +++ b/tpl/default_fr/css/style.css @@ -10,6 +10,11 @@ body { margin: 0; } +body>p, body>ul, body>dl { + margin-left: 1em; + margin-right: 1em; +} + fieldset { border: 1px solid #999; margin-bottom: 1em; @@ -55,10 +60,20 @@ h2 { border-left: none; } +hr { + width: 33%; + margin-top: 2em; + margin-bottom: 2em; +} + input[type="checkbox"] { margin-left: 2em; } +.red { + color: red; +} + .center { text-align: center; } @@ -120,12 +135,16 @@ input[type=submit] { text-align: center } -#edit_password_form, #edit_user_form, #invoice_form, #notice_form { +#edit_password_form, #edit_user_form, #invoice_form, #notice_form, #global_payback_form { width: 67%; margin: auto; } -#edit_password_form p, #edit_user_form p, #notice_form p { +#global_payback_form fieldset { + margin-top: 2em; +} + +#edit_password_form p, #edit_user_form p, #notice_form p, #global_payback_form p { text-align: center; } diff --git a/tpl/default_fr/manage_paybacks.html b/tpl/default_fr/manage_paybacks.html new file mode 100644 index 0000000..c8ca15e --- /dev/null +++ b/tpl/default_fr/manage_paybacks.html @@ -0,0 +1,43 @@ +{include="header"} + +{if condition="!empty($list)"} +

Gérer les remboursements globaux

+

Ajouter un remboursement global

+ + {if condition="count($global_paybacks) > 0"} +

Liste des remboursements globaux précédents :

+
+ {loop="$global_paybacks"} +
{$value['date']}
+
Remboursement n°{$value['id']}
+ {/loop} +
+ {/if} +{else} +

Ajouter un remboursement global

+

Cette page vous permet d'ajouter un remboursement global. Un tel remboursement permet de simplifier au maximum les remboursements. Ainsi, le tableau de la page d'accueil sera remis à zéro et un nouveau tableau sera créé, tableau qui simplifiera les échanges.

+ +

Par exemple, si A doit 5{$currency} à B et B doit 5{$currency} à C, après remboursement global, ces remboursements se simplifieront en A doit 5{$currency} à C.

+ +

Note : Cette opération est irréversible sans mettre les mains dans la base de données.

+ +

Note : Un backup de votre base de données à l'heure actuelle sera effectué et stocké dans le répertoire backups à la racine de l'instance. Vous pourrez ainsi restaurer la base de données en cas d'erreur de votre part.

+ +
+ +

Si vous confirmez la création d'un remboursement global, veuillez sélectionner ci-dessous les utilisateurs que vous souhaitez inclure dans le remboursement.

+ +
+
+ Utilisateurs à inclure + {loop="$users"} + +
+ {/loop} +
+

+ +

+
+{/if} +{include="footer"}