diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index c89fc5937454e99385edaf59b0c77b3aaad9e1b2..bd1daca8886a7d042dde3dc556060d87dd865851 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1681,7 +1681,7 @@ class ExtraFields // Clean parameters $value_key=dol_mktime($_POST[$keysuffix."options_".$key.$keyprefix."hour"], $_POST[$keysuffix."options_".$key.$keyprefix."min"], 0, $_POST[$keysuffix."options_".$key.$keyprefix."month"], $_POST[$keysuffix."options_".$key.$keyprefix."day"], $_POST[$keysuffix."options_".$key.$keyprefix."year"]); } - else if (in_array($key_type,array('checkbox'))) + else if (in_array($key_type,array('checkbox', 'chkbxlst'))) { $value_arr=GETPOST($keysuffix."options_".$key.$keyprefix); // Make sure we get an array even if there's only one checkbox diff --git a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql index 11a86724cf0a8f86bf354f589826673bc6af7216..d7e683465110ee9b809d992735ea47ba1d00d8f6 100644 --- a/htdocs/install/mysql/migration/5.0.0-6.0.0.sql +++ b/htdocs/install/mysql/migration/5.0.0-6.0.0.sql @@ -159,6 +159,9 @@ CREATE TABLE llx_product_attribute_combination ALTER TABLE llx_bank_account drop foreign key bank_fk_accountancy_journal; +-- Fix missing entity column after init demo +ALTER TABLE llx_accounting_journal ADD COLUMN entity integer DEFAULT 1; + -- Add journal entries INSERT INTO llx_accounting_journal (rowid, code, label, nature, active) VALUES (1,'VT', 'Sale journal', 2, 1); INSERT INTO llx_accounting_journal (rowid, code, label, nature, active) VALUES (2,'AC', 'Purchase journal', 3, 1); @@ -355,4 +358,24 @@ delete from llx_categorie_member where fk_categorie not in (select rowid from ll delete from llx_categorie_contact where fk_categorie not in (select rowid from llx_categorie where type = 4); delete from llx_categorie_project where fk_categorie not in (select rowid from llx_categorie where type = 5); -ALTER TABLE llx_inventory ADD COLUMN ref varchar(48); \ No newline at end of file +ALTER TABLE llx_inventory ADD COLUMN ref varchar(48); + +create table llx_loan_schedule +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_loan integer, + datec datetime, + tms timestamp, + datep datetime, + amount_capital real DEFAULT 0, + amount_insurance real DEFAULT 0, + amount_interest real DEFAULT 0, + fk_typepayment integer NOT NULL, + num_payment varchar(50), + note_private text, + note_public text, + fk_bank integer NOT NULL, + fk_user_creat integer, + fk_user_modif integer +)ENGINE=innodb; + diff --git a/htdocs/install/mysql/tables/llx_loan_schedule.sql b/htdocs/install/mysql/tables/llx_loan_schedule.sql new file mode 100644 index 0000000000000000000000000000000000000000..c682b22f276150f132f13275976e0f11bd397d45 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_loan_schedule.sql @@ -0,0 +1,37 @@ +-- =================================================================== +-- Copyright (C) 2014 Alexandre Spangaro <aspangaro.dolibarr@gmail.com> +-- Copyright (C) 2015 Frederic France <frederic.france@free.fr> +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- =================================================================== + +create table llx_loan_schedule +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_loan integer, + datec datetime, -- creation date + tms timestamp, + datep datetime, -- payment date + amount_capital real DEFAULT 0, + amount_insurance real DEFAULT 0, + amount_interest real DEFAULT 0, + fk_typepayment integer NOT NULL, + num_payment varchar(50), + note_private text, + note_public text, + fk_bank integer NOT NULL, + fk_user_creat integer, -- creation user + fk_user_modif integer -- last modification user +)ENGINE=innodb; diff --git a/htdocs/langs/en_US/loan.lang b/htdocs/langs/en_US/loan.lang index 927aab2abf4a86ad3a97b04ed4c65202d99277f6..d00b11738be75484b24da384c4695e3211f8064c 100644 --- a/htdocs/langs/en_US/loan.lang +++ b/htdocs/langs/en_US/loan.lang @@ -50,3 +50,4 @@ ConfigLoan=Configuration of the module loan LOAN_ACCOUNTING_ACCOUNT_CAPITAL=Accounting account capital by default LOAN_ACCOUNTING_ACCOUNT_INTEREST=Accounting account interest by default LOAN_ACCOUNTING_ACCOUNT_INSURANCE=Accounting account insurance by default +CreateCalcSchedule=Créer / Modifier échéancier de pret diff --git a/htdocs/loan/calcmens.php b/htdocs/loan/calcmens.php new file mode 100644 index 0000000000000000000000000000000000000000..3778f455b041af7afa3e36188a56327d65386831 --- /dev/null +++ b/htdocs/loan/calcmens.php @@ -0,0 +1,72 @@ +<?php +/* TVI + * Copyright (C) 2015 Florian HENRY <florian.henry@open-concept.pro> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * \file tvi/ajax/list.php + * \brief File to return datables output + */ +if (! defined('NOTOKENRENEWAL')) + define('NOTOKENRENEWAL', '1'); // Disables token renewal +if (! defined('NOREQUIREMENU')) + define('NOREQUIREMENU', '1'); + // if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); +if (! defined('NOREQUIREAJAX')) + define('NOREQUIREAJAX', '1'); + // if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); + // if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); + + +require '../main.inc.php'; +require DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php'; + +$mens=GETPOST('mens'); +$capital=GETPOST('capital'); +$rate=GETPOST('rate'); +$echance=GETPOST('echeance'); +$nbterm=GETPOST('nbterm'); + +top_httphead(); + +$output=array(); + +$object = new LoanSchedule($db); + +$int = ($capital*($rate/12)); +$int = round($int ,2,PHP_ROUND_HALF_UP); +$cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); +$output[$echance]=array('cap_rest'=>$cap_rest,'cap_rest_str'=>price($cap_rest),'interet'=>$int,'interet_str'=>price($int,0,'',1),'mens'=>$mens); + +$echance++; +$capital=$cap_rest; +while ($echance<=$nbterm) { + + $mens = round($object->calc_mens($capital,$rate,$nbterm-$echance+1),2,PHP_ROUND_HALF_UP); + + $int = ($capital*($rate/12)); + $int = round($int ,2,PHP_ROUND_HALF_UP); + $cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); + + $output[$echance]=array('cap_rest'=>$cap_rest,'cap_rest_str'=>price($cap_rest),'interet'=>$int,'interet_str'=>price($int,0,'',1),'mens'=>$mens); + + $capital=$cap_rest; + $echance++; +} + +echo json_encode($output); + diff --git a/htdocs/loan/card.php b/htdocs/loan/card.php index 81d43e46ab0bcd0d78b0d42ac8ce92131ba72151..557d48be6802a2e1622ce7debd6eff2ca7f4881b 100644 --- a/htdocs/loan/card.php +++ b/htdocs/loan/card.php @@ -72,7 +72,7 @@ if (empty($reshook)) setEventMessages($loan->error, null, 'errors'); } } - + // Delete loan if ($action == 'confirm_delete' && $confirm == 'yes') { @@ -89,7 +89,7 @@ if (empty($reshook)) setEventMessages($loan->error, null, 'errors'); } } - + // Add loan if ($action == 'add' && $user->rights->loan->write) { @@ -99,7 +99,7 @@ if (empty($reshook)) $dateend = dol_mktime(12, 0, 0, GETPOST('endmonth','int'), GETPOST('endday','int'), GETPOST('endyear','int')); $capital = price2num(GETPOST('capital')); $rate = GETPOST('rate'); - + if (! $capital) { $error++; $action = 'create'; @@ -120,7 +120,7 @@ if (empty($reshook)) $error++; $action = 'create'; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rate")), null, 'errors'); } - + if (! $error) { $object->label = GETPOST('label'); @@ -133,15 +133,15 @@ if (empty($reshook)) $object->note_private = GETPOST('note_private'); $object->note_public = GETPOST('note_public'); $object->fk_project = GETPOST('fk_project'); - + $accountancy_account_capital = GETPOST('accountancy_account_capital'); $accountancy_account_insurance = GETPOST('accountancy_account_insurance'); $accountancy_account_interest = GETPOST('accountancy_account_interest'); - + if ($accountancy_account_capital <= 0) { $object->account_capital = ''; } else { $object->account_capital = $accountancy_account_capital; } if ($accountancy_account_insurance <= 0) { $object->account_insurance = ''; } else { $object->account_insurance = $accountancy_account_insurance; } if ($accountancy_account_interest <= 0) { $object->account_interest = ''; } else { $object->account_interest = $accountancy_account_interest; } - + $id=$object->create($user); if ($id <= 0) { @@ -157,7 +157,7 @@ if (empty($reshook)) exit(); } } - + // Update record else if ($action == 'update' && $user->rights->loan->write) { @@ -168,7 +168,7 @@ if (empty($reshook)) $datestart = dol_mktime(12, 0, 0, GETPOST('startmonth','int'), GETPOST('startday','int'), GETPOST('startyear','int')); $dateend = dol_mktime(12, 0, 0, GETPOST('endmonth','int'), GETPOST('endday','int'), GETPOST('endyear','int')); $capital = price2num(GETPOST('capital')); - + if (! $capital) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("LoanCapital")), null, 'errors'); @@ -185,14 +185,14 @@ if (empty($reshook)) $accountancy_account_capital = GETPOST('accountancy_account_capital'); $accountancy_account_insurance = GETPOST('accountancy_account_insurance'); $accountancy_account_interest = GETPOST('accountancy_account_interest'); - + if ($accountancy_account_capital <= 0) { $object->account_capital = ''; } else { $object->account_capital = $accountancy_account_capital; } if ($accountancy_account_insurance <= 0) { $object->account_insurance = ''; } else { $object->account_insurance = $accountancy_account_insurance; } if ($accountancy_account_interest <= 0) { $object->account_interest = ''; } else { $object->account_interest = $accountancy_account_interest; } } - + $result = $object->update($user); - + if ($result > 0) { header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id); @@ -209,7 +209,7 @@ if (empty($reshook)) exit; } } - + // Link to a project if ($action == 'classin' && $user->rights->loan->write) { @@ -307,12 +307,12 @@ if ($action == 'create') $langs->load("projects"); print '<tr><td>'.$langs->trans("Project").'</td><td>'; - + $numproject=$formproject->select_projects(-1,GETPOST("fk_project"),'fk_project',16,0,1,1); - + print '</td></tr>'; } - + // Note Private print '<tr>'; print '<td class="tdtop">'.$langs->trans('NotePrivate').'</td>'; @@ -352,7 +352,7 @@ if ($action == 'create') print $formaccounting->select_account($object->accountancy_account_interest, 'accountancy_account_interest', 1, '', 0, 1); print '</td></tr>'; } - else // For external software + else // For external software { // Accountancy_account_capital print '<tr><td class="titlefieldcreate">'.$langs->trans("LoanAccountancyCapitalCode").'</td>'; @@ -417,10 +417,22 @@ if ($id > 0) dol_fiche_head($head, 'card', $langs->trans("Loan"), 0, 'bill'); + print '<script type="text/javascript">' . "\n"; + print ' function popEcheancier() {' . "\n"; + print ' $div = $(\'<div id="popCalendar"><iframe width="100%" height="100%" frameborder="0" src="createschedule.php?loanid=' . $object->id . '"></iframe></div>\');' . "\n"; + print ' $div.dialog({' . "\n"; + print ' modal:true' . "\n"; + print ' ,width:"90%"' . "\n"; + print ' ,height:$(window).height() - 150' . "\n"; + print ' });' . "\n"; + print ' }' . "\n"; + print '</script>'; + + // Loan card - + $linkback = '<a href="' . DOL_URL_ROOT . '/loan/index.php">' . $langs->trans("BackToList") . '</a>'; - + $morehtmlref='<div class="refidno">'; // Ref loan $morehtmlref.=$form->editfieldkey("Label", 'label', $object->label, $object, $user->rights->loan->write, 'string', '', 0, 1); @@ -458,7 +470,7 @@ if ($id > 0) } } $morehtmlref.='</div>'; - + $object->totalpaid = $totalpaid; // To give a chance to dol_banner_tab to use already paid amount to show correct status dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright); @@ -652,7 +664,7 @@ if ($id > 0) while ($i < $num) { $objp = $db->fetch_object($resql); - + print '<tr class="oddeven">'; print '<td><a href="'.DOL_URL_ROOT.'/loan/payment/card.php?id='.$objp->rowid.'">'.img_object($langs->trans("Payment"),"payment").' '.$objp->rowid.'</a></td>'; print '<td>'.dol_print_date($db->jdate($objp->dp),'day')."</td>\n"; @@ -713,31 +725,33 @@ if ($id > 0) if (empty($reshook)) { print '<div class="tabsAction">'; - + // Edit if ($user->rights->loan->write) { + print '<a href="javascript:popEcheancier()" class="butAction">'.$langs->trans('CreateCalcSchedule').'</a>'; + print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&action=edit">'.$langs->trans("Modify").'</a>'; } - + // Emit payment if ($object->paid == 0 && ((price2num($object->capital) > 0 && round($staytopay) < 0) || (price2num($object->capital) > 0 && round($staytopay) > 0)) && $user->rights->loan->write) { print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/payment/payment.php?id='.$object->id.'&action=create">'.$langs->trans("DoPayment").'</a>'; } - + // Classify 'paid' if ($object->paid == 0 && round($staytopay) <=0 && $user->rights->loan->write) { print '<a class="butAction" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&action=paid">'.$langs->trans("ClassifyPaid").'</a>'; } - + // Delete if ($user->rights->loan->delete) { print '<a class="butActionDelete" href="'.DOL_URL_ROOT.'/loan/card.php?id='.$object->id.'&action=delete">'.$langs->trans("Delete").'</a>'; } - + print "</div>"; } } diff --git a/htdocs/loan/class/loanschedule.class.php b/htdocs/loan/class/loanschedule.class.php new file mode 100644 index 0000000000000000000000000000000000000000..1e519e6a2af6e2d0a845e1914c1e162fe7d29ebe --- /dev/null +++ b/htdocs/loan/class/loanschedule.class.php @@ -0,0 +1,526 @@ +<?php +/* Copyright (C) 2017 Florian HENRY <florian.henry@atm-consulting.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/loan/class/loanschedule.class.php + * \ingroup facture + * \brief File of class to manage schedule of loans + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; + + +/** \class LoanSchedule + * \brief Class to manage Schedule of loans + */ +class LoanSchedule extends CommonObject +{ + public $element='loan_schedule'; //!< Id that identify managed objects + public $table_element='loan_schedule'; //!< Name of table without prefix where object is stored + + var $fk_loan; + var $datec=''; + var $tms=''; + var $datep=''; + var $amounts=array(); // Array of amounts + var $amount_capital; // Total amount of payment + var $amount_insurance; + var $amount_interest; + var $fk_typepayment; + var $num_payment; + var $fk_bank; + var $fk_user_creat; + var $fk_user_modif; + var $lines=array(); + + /** + * @deprecated + * @see amount, amounts + */ + var $total; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db = $db; + } + + /** + * Create payment of loan into database. + * Use this->amounts to have list of lines for the payment + * + * @param User $user User making payment + * @return int <0 if KO, id of payment if OK + */ + function create($user) + { + global $conf, $langs; + + $error=0; + + $now=dol_now(); + + // Validate parameters + if (! $this->datepaid) + { + $this->error='ErrorBadValueForParameter'; + return -1; + } + + // Clean parameters + if (isset($this->fk_loan)) $this->fk_loan = trim($this->fk_loan); + if (isset($this->amount_capital)) $this->amount_capital = trim($this->amount_capital?$this->amount_capital:0); + if (isset($this->amount_insurance)) $this->amount_insurance = trim($this->amount_insurance?$this->amount_insurance:0); + if (isset($this->amount_interest)) $this->amount_interest = trim($this->amount_interest?$this->amount_interest:0); + if (isset($this->fk_typepayment)) $this->fk_typepayment = trim($this->fk_typepayment); + if (isset($this->fk_bank)) $this->fk_bank = trim($this->fk_bank); + if (isset($this->fk_user_creat)) $this->fk_user_creat = trim($this->fk_user_creat); + if (isset($this->fk_user_modif)) $this->fk_user_modif = trim($this->fk_user_modif); + + $totalamount = $this->amount_capital + $this->amount_insurance + $this->amount_interest; + $totalamount = price2num($totalamount); + + // Check parameters + if ($totalamount == 0) { + $this->errors[]='step1'; + return -1; // Negative amounts are accepted for reject prelevement but not null + } + + + $this->db->begin(); + + if ($totalamount != 0) + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,"; + $sql.= " fk_typepayment, fk_user_creat, fk_bank)"; + $sql.= " VALUES (".$this->fk_loan.", '".$this->db->idate($now)."',"; + $sql.= " '".$this->db->idate($this->datepaid)."',"; + $sql.= " ".$this->amount_capital.","; + $sql.= " ".$this->amount_insurance.","; + $sql.= " ".$this->amount_interest.","; + $sql.= " ".$this->fk_typepayment.", "; + $sql.= " ".$user->id.","; + $sql.= " ".$this->fk_bank . ")"; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."payment_loan"); + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + + } + + if ($totalamount != 0 && ! $error) + { + $this->amount_capital=$totalamount; + $this->total=$totalamount; // deprecated + $this->db->commit(); + return $this->id; + } + else + { + $this->errors[]=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from database + * + * @param int $id Id object + * @return int <0 if KO, >0 if OK + */ + function fetch($id) + { + global $langs; + $sql = "SELECT"; + $sql.= " t.rowid,"; + $sql.= " t.fk_loan,"; + $sql.= " t.datec,"; + $sql.= " t.tms,"; + $sql.= " t.datep,"; + $sql.= " t.amount_capital,"; + $sql.= " t.amount_insurance,"; + $sql.= " t.amount_interest,"; + $sql.= " t.fk_typepayment,"; + $sql.= " t.num_payment,"; + $sql.= " t.note_private,"; + $sql.= " t.note_public,"; + $sql.= " t.fk_bank,"; + $sql.= " t.fk_user_creat,"; + $sql.= " t.fk_user_modif,"; + $sql.= " pt.code as type_code, pt.libelle as type_libelle,"; + $sql.= ' b.fk_account'; + $sql.= " FROM (".MAIN_DB_PREFIX."c_paiement as pt, ".MAIN_DB_PREFIX.$this->table_element." as t)"; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON t.fk_bank = b.rowid'; + $sql.= " WHERE t.rowid = ".$id." AND t.fk_typepayment = pt.id"; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + $this->ref = $obj->rowid; + + $this->fk_loan = $obj->fk_loan; + $this->datec = $this->db->jdate($obj->datec); + $this->tms = $this->db->jdate($obj->tms); + $this->datep = $this->db->jdate($obj->datep); + $this->amount_capital = $obj->amount_capital; + $this->amount_insurance = $obj->amount_insurance; + $this->amount_interest = $obj->amount_interest; + $this->fk_typepayment = $obj->fk_typepayment; + $this->num_payment = $obj->num_payment; + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->fk_bank = $obj->fk_bank; + $this->fk_user_creat = $obj->fk_user_creat; + $this->fk_user_modif = $obj->fk_user_modif; + + $this->type_code = $obj->type_code; + $this->type_libelle = $obj->type_libelle; + + $this->bank_account = $obj->fk_account; + $this->bank_line = $obj->fk_bank; + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + return -1; + } + } + + + /** + * Update database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user=0, $notrigger=0) + { + global $conf, $langs; + $error=0; + + // Clean parameters + if (isset($this->fk_loan)) $this->fk_loan=trim($this->fk_loan); + if (isset($this->amount_capital)) $this->amount_capital=trim($this->amount_capital); + if (isset($this->amount_insurance)) $this->amount_insurance=trim($this->amount_insurance); + if (isset($this->amount_interest)) $this->amount_interest=trim($this->amount_interest); + if (isset($this->fk_typepayment)) $this->fk_typepayment=trim($this->fk_typepayment); + if (isset($this->num_payment)) $this->num_payment=trim($this->num_payment); + if (isset($this->note_private)) $this->note_private=trim($this->note_private); + if (isset($this->note_public)) $this->note_public=trim($this->note_public); + if (isset($this->fk_bank)) $this->fk_bank=trim($this->fk_bank); + if (isset($this->fk_user_creat)) $this->fk_user_creat=trim($this->fk_user_creat); + if (isset($this->fk_user_modif)) $this->fk_user_modif=trim($this->fk_user_modif); + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + + $sql.= " fk_loan=".(isset($this->fk_loan)?$this->fk_loan:"null").","; + $sql.= " datec=".(dol_strlen($this->datec)!=0 ? "'".$this->db->idate($this->datec)."'" : 'null').","; + $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').","; + $sql.= " datep=".(dol_strlen($this->datep)!=0 ? "'".$this->db->idate($this->datep)."'" : 'null').","; + $sql.= " amount_capital=".(isset($this->amount_capital)?$this->amount_capital:"null").","; + $sql.= " amount_insurance=".(isset($this->amount_insurance)?$this->amount_insurance:"null").","; + $sql.= " amount_interest=".(isset($this->amount_interest)?$this->amount_interest:"null").","; + $sql.= " fk_typepayment=".(isset($this->fk_typepayment)?$this->fk_typepayment:"null").","; + $sql.= " num_payment=".(isset($this->num_payment)?"'".$this->db->escape($this->num_payment)."'":"null").","; + $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").","; + $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").","; + $sql.= " fk_bank=".(isset($this->fk_bank)?$this->fk_bank:"null").","; + $sql.= " fk_user_creat=".(isset($this->fk_user_creat)?$this->fk_user_creat:"null").","; + $sql.= " fk_user_modif=".(isset($this->fk_user_modif)?$this->fk_user_modif:"null").""; + + $sql.= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action call a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) + { + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + + /** + * Delete object in database + * + * @param User $user User that delete + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function delete($user, $notrigger=0) + { + global $conf, $langs; + $error=0; + + $this->db->begin(); + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " WHERE rowid=".$this->id; + + dol_syslog(get_class($this)."::delete", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + } + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action call a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + function calc_mens($capital,$rate,$nbterm) + { + $result=''; + + if (!empty($capital)&&!empty($rate)&&!empty($nbterm)) + { + $result=($capital*($rate/12))/(1-pow((1+($rate/12)),($nbterm*-1))); + } + + return $result; + } + + + /** + * Load all object in memory from database + * + * @param int $id Id object + * @return int <0 if KO, >0 if OK + */ + function fetchall($loan) + { + global $langs; + + $sql = "SELECT"; + $sql.= " t.rowid,"; + $sql.= " t.fk_loan,"; + $sql.= " t.datec,"; + $sql.= " t.tms,"; + $sql.= " t.datep,"; + $sql.= " t.amount_capital,"; + $sql.= " t.amount_insurance,"; + $sql.= " t.amount_interest,"; + $sql.= " t.fk_typepayment,"; + $sql.= " t.num_payment,"; + $sql.= " t.note_private,"; + $sql.= " t.note_public,"; + $sql.= " t.fk_bank,"; + $sql.= " t.fk_user_creat,"; + $sql.= " t.fk_user_modif"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql.= " WHERE t.fk_loan = ".$loan; + + dol_syslog(get_class($this)."::fetchall", LOG_DEBUG); + $resql=$this->db->query($sql); + + if ($resql) + { + while($obj = $this->db->fetch_object($resql)) + { + $line = New LoanSchedule($this->db); + $line->id = $obj->rowid; + $line->ref = $obj->rowid; + + $line->fk_loan = $obj->fk_loan; + $line->datec = $this->db->jdate($obj->datec); + $line->tms = $this->db->jdate($obj->tms); + $line->datep = $this->db->jdate($obj->datep); + $line->amount_capital = $obj->amount_capital; + $line->amount_insurance = $obj->amount_insurance; + $line->amount_interest = $obj->amount_interest; + $line->fk_typepayment = $obj->fk_typepayment; + $line->num_payment = $obj->num_payment; + $line->note_private = $obj->note_private; + $line->note_public = $obj->note_public; + $line->fk_bank = $obj->fk_bank; + $line->fk_user_creat = $obj->fk_user_creat; + $line->fk_user_modif = $obj->fk_user_modif; + + $this->lines[] = $line; + } + $this->db->free($resql); + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + return -1; + } + } + + function trans_paiment() + { + require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; + + $toinsert = array(); + + $sql = "SELECT l.rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."loan as l "; + $sql.= " WHERE l.paid = 0"; + $resql=$this->db->query($sql); + + if($resql){ + while($obj = $this->db->fetch_object($resql)){ + $lastrecorded = $this->lastpaiment($obj->rowid); + $toinsert = $this->paimenttorecord($obj->rowid, $lastrecorded); + if(count($toinsert)>0){ + foreach ($toinsert as $echid){ + $this->db->begin(); + $sql = "INSERT INTO " .MAIN_DB_PREFIX . "payment_loan "; + $sql.= "(fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif) "; + $sql.= "SELECT fk_loan,datec,tms,datep,amount_capital,amount_insurance,amount_interest,fk_typepayment,num_payment,note_private,note_public,fk_bank,fk_user_creat,fk_user_modif FROM " . MAIN_DB_PREFIX . "loan_schedule WHERE rowid =" .$echid; + $res=$this->db->query($sql); + if($res){ + $this->db->commit(); + }else { + $this->db->rollback(); + } + } + } + } + } + } + + + function lastpaiment($loan) + { + $sql = "SELECT p.datep"; + $sql.= " FROM ".MAIN_DB_PREFIX."payment_loan as p "; + $sql.= " WHERE p.fk_loan = " . $loan; + $sql.= " ORDER BY p.datep DESC "; + $sql.= " LIMIT 1 "; + + $resql=$this->db->query($sql); + + if($resql){ + $obj = $this->db->fetch_object($resql); + return $this->db->jdate($obj->datep); + }else{ + return -1; + } + } + + function paimenttorecord($loan,$datemax) + { + $sql = "SELECT p.rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p "; + $sql.= " WHERE p.fk_loan = " . $loan; + if(!empty($datemax)){ $sql.= " AND p.datep > '" . $this->db->idate($datemax) ."'";} + $sql.= " AND p.datep <= '" . $this->db->idate(dol_now()). "'"; + + + $resql=$this->db->query($sql); + + if($resql){ + while($obj = $this->db->fetch_object($resql)) + { + $result[] = $obj->rowid; + + } + + } + + return $result; + } +} + diff --git a/htdocs/loan/createschedule.php b/htdocs/loan/createschedule.php new file mode 100644 index 0000000000000000000000000000000000000000..0d15d1b2de652284ba296f84de418fba1ef5d5d3 --- /dev/null +++ b/htdocs/loan/createschedule.php @@ -0,0 +1,208 @@ +<?php +/* Copyright (C) 2017 Franck Moreau <franck.moreau@theobald.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/loan/createecheancier.php + * \ingroup loan + * \brief Schedule card + */ + +require '../main.inc.php'; + +require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php'; + +global $user; + +$loanid = GETPOST('loanid', 'int'); +$action = GETPOST('action'); + +$object = new Loan($db); +$object->fetch($loanid); + +$langs->load('loan'); + +if ($action == 'createecheancier') { + + $i=1; + while($i <$object->nbterm+1){ + + $date = GETPOST('hi_date'.$i,'int'); + $mens = GETPOST('mens'.$i); + $int = GETPOST('hi_interets'.$i); + + $echeance = new LoanSchedule($db); + + $echeance->fk_loan = $object->id; + $echeance->datec = dol_now(); + $echeance->tms = dol_now(); + $echeance->datepaid = $date; + $echeance->amount_capital = $mens-$int; + $echeance->amount_insurance = 0; + $echeance->amount_interest = $int; + $echeance->fk_typepayment = 3; + $echeance->fk_bank = 1; + $echeance->fk_user_creat = $user->id; + $echeance->fk_user_modif = $user->id; + $result=$echeance->create($user); + if ($result<0) { + setEventMessages(null, $echeance->errors,'errors'); + } + $i++; + } +} + +if ($action == 'updateecheancier') { + + $i=1; + while($i <$object->nbterm+1){ + + $mens = GETPOST('mens'.$i); + $int = GETPOST('hi_interets'.$i); + $id = GETPOST('hi_rowid'.$i); + $echeance = new LoanSchedule($db); + $echeance->fetch($id); + $echeance->tms = dol_now(); + $echeance->amount_capital = $mens-$int; + $echeance->amount_insurance = 0; + $echeance->amount_interest = $int; + $echeance->fk_user_modif = $user->id; + $result= $echeance->update($user,0); + if ($result<0) { + setEventMessages(null, $echeance->errors,'errors'); + } + $i++; + } +} + +$echeance = new LoanSchedule($db); +$echeance->fetchall($object->id); + +top_htmlhead('', ''); +$var = ! $var; + + +?> +<script type="text/javascript" language="javascript"> +$(document).ready(function() { + $('[name^="mens"]').focusout(function() { + var echeance=$(this).attr('ech'); + var mens=$(this).val(); + var idcap=echeance-1; + idcap = '#hi_capital'+idcap; + var capital=$(idcap).val(); + $.ajax({ + dataType: 'json', + url: 'calcmens.php', + data: { echeance: echeance, mens: mens, capital:capital, rate:<?php echo $object->rate/100;?> , nbterm : <?php echo $object->nbterm;?>}, + success: function(data) { + $.each(data, function(index, element) { + var idcap_res='#hi_capital'+index; + var idcap_res_srt='#capital'+index; + var interet_res='#hi_interets'+index; + var interet_res_str='#interets'+index; + var men_res='#mens'+index; + $(idcap_res).val(element.cap_rest); + $(idcap_res_srt).text(element.cap_rest_str+' €'); + $(interet_res).val(element.interet); + $(interet_res_str).text(element.interet_str+' €'); + $(men_res).val(element.mens); + }); + } + }); + }); +}); +</script> +<?php + + +print '<form name="createecheancier" action="' . $_SERVER["PHP_SELF"] . '" method="POST">'; +print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">'; +print '<input type="hidden" name="loanid" value="' . $loanid . '">'; +if(count($echeance->lines)>0){ + print '<input type="hidden" name="action" value="updateecheancier">'; +}else{ + print '<input type="hidden" name="action" value="createecheancier">'; +} +print '<table class="border" width="100%">'; +print '<tr class="liste_titre">'; +print '<th align="center" colspan="5">' . "Création d'échéancier</th>"; +print '</tr>'; + +print '<tr class="liste_titre">'; +Print '<th width="10%" align="center"> Echéance </th>'; +Print '<th width="10%" align="center"> Date </th>'; +Print '<th width="10%" align="center"> Montant </th>'; +Print '<th width="20%" align="center"> Intérêts </th>'; +Print '<th width="40%" align="center"> Capital restant du </th>'; +print '</tr>'; + +if ($object->nbterm > 0 && count($echeance->lines)==0) +{ + $i=1; + $capital = $object->capital; + while($i <$object->nbterm+1){ + $mens = round($echeance->calc_mens($capital, $object->rate/100, $object->nbterm-$i+1),2,PHP_ROUND_HALF_UP); + $int = ($capital*($object->rate/12))/100; + $int = round($int ,2,PHP_ROUND_HALF_UP); + $cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); + print '<tr>'; + print '<td align="center" id="n'.$i.'">' . $i .'</td>'; + print '<td align="center" id ="date' .$i .'"><input type="hidden" name="hi_date' .$i .'" id ="hi_date' .$i .'" value="' . dol_time_plus_duree($object->datestart, $i-1, 'm') . '">' . dol_print_date(dol_time_plus_duree($object->datestart, $i-1, 'm'),'day') . '</td>'; + print '<td align="center"><input name="mens'.$i.'" id="mens'.$i.'" size="5" value="'.$mens.'" ech="'.$i.'"> €</td>'; + print '<td align="center" id="interets'.$i.'">'.price($int,0,'',1).' €</td><input type="hidden" name="hi_interets' .$i .'" id ="hi_interets' .$i .'" value="' . $int . '">'; + print '<td align="center" id="capital'.$i.'">'.price($cap_rest).' €</td><input type="hidden" name="hi_capital' .$i .'" id ="hi_capital' .$i .'" value="' . $cap_rest . '">'; + print '</tr>'; + $i++; + $capital = $cap_rest; + } +}elseif(count($echeance->lines)>0){ + $i=1; + $capital = $object->capital; + foreach ($echeance->lines as $line){ + $mens = $line->amount_capital+$line->amount_insurance+$line->amount_interest; + $int = $line->amount_interest; + $cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); + print '<tr>'; + print '<td align="center" id="n'.$i.'"><input type="hidden" name="hi_rowid' .$i .'" id ="hi_rowid' .$i .'" value="' . $line->id . '">' . $i .'</td>'; + print '<td align="center" id ="date' .$i .'"><input type="hidden" name="hi_date' .$i .'" id ="hi_date' .$i .'" value="' . $line->datep . '">' . dol_print_date($line->datep,'day') . '</td>'; + if($line->datep > dol_now()){ + print '<td align="center"><input name="mens'.$i.'" id="mens'.$i.'" size="5" value="'.$mens.'" ech="'.$i.'"> €</td>'; + }else{ + print '<td align="center">' . price($mens) . ' €</td><input type="hidden" name="mens' .$i .'" id ="mens' .$i .'" value="' . $mens . '">'; + } + print '<td align="center" id="interets'.$i.'">'.price($int,0,'',1).' €</td><input type="hidden" name="hi_interets' .$i .'" id ="hi_interets' .$i .'" value="' . $int . '">'; + print '<td align="center" id="capital'.$i.'">'.price($cap_rest).' €</td><input type="hidden" name="hi_capital' .$i .'" id ="hi_capital' .$i .'" value="' . $cap_rest . '">'; + print '</tr>'; + $i++; + $capital = $cap_rest; + } +} + +print '</table>'; +print '</br>'; +print '</br>'; +print '<div align="center"><input class="button" type="submit" value="'.$langs->trans("Save").'"></div>'; +print '</form>'; + +llxFooter(); +$db->close(); + + +