* Copyright (C) 2015-2024 Frédéric France * Copyright (C) 2017 Laurent Destailleur * Copyright (C) 2020 Maxime DEMAREST * Copyright (C) 2024 MDW * * 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 . */ /** * \file htdocs/loan/card.php * \ingroup loan * \brief Loan card */ // Load Dolibarr environment require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php'; require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php'; if (isModEnabled('accounting')) { require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; } if (isModEnabled('project')) { require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; } /** * @var Conf $conf * @var DoliDB $db * @var HookManager $hookmanager * @var Translate $langs * @var User $user */ // Load translation files required by the page $langs->loadLangs(array("banks", "bills", "compta", "loan")); $id = GETPOSTINT('id'); $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm'); $cancel = GETPOST('cancel', 'alpha'); $projectid = GETPOSTINT('projectid'); // Security check $socid = GETPOSTINT('socid'); if ($user->socid) { $socid = $user->socid; } $hookmanager->initHooks(array('loancard', 'globalcard')); $result = restrictedArea($user, 'loan', $id, '', ''); $object = new Loan($db); $permissiontoadd = $user->hasRight('loan', 'write'); $error = 0; $staytopay = 0; /* * Actions */ $parameters = array(); $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } if (empty($reshook)) { // Classify paid if ($action == 'confirm_paid' && $confirm == 'yes' && $permissiontoadd) { $object->fetch($id); $result = $object->setPaid($user); if ($result > 0) { setEventMessages($langs->trans('LoanPaid'), null, 'mesgs'); } else { setEventMessages($object->error, $object->errors, 'errors'); } } // Delete loan if ($action == 'confirm_delete' && $confirm == 'yes' && $permissiontoadd) { $object->fetch($id); $result = $object->delete($user); if ($result > 0) { setEventMessages($langs->trans('LoanDeleted'), null, 'mesgs'); header("Location: list.php"); exit; } else { setEventMessages($object->error, $object->errors, 'errors'); } } // Add loan if ($action == 'add' && $permissiontoadd) { if (!$cancel) { $datestart = dol_mktime(12, 0, 0, GETPOSTINT('startmonth'), GETPOSTINT('startday'), GETPOSTINT('startyear')); $dateend = dol_mktime(12, 0, 0, GETPOSTINT('endmonth'), GETPOSTINT('endday'), GETPOSTINT('endyear')); $capital = (float) price2num(GETPOST('capital')); $rate = (float) price2num(GETPOST('rate')); if (!$capital) { $error++; $action = 'create'; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("LoanCapital")), null, 'errors'); } if (!$datestart) { $error++; $action = 'create'; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("DateStart")), null, 'errors'); } if (!$dateend) { $error++; $action = 'create'; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("DateEnd")), null, 'errors'); } if ($rate == '') { $error++; $action = 'create'; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Rate")), null, 'errors'); } if (!$error) { $object->label = GETPOST('label'); $object->fk_bank = GETPOSTINT('accountid'); $object->capital = $capital; $object->datestart = $datestart; $object->dateend = $dateend; $object->nbterm = (float) price2num(GETPOST('nbterm')); $object->rate = $rate; $object->note_private = GETPOST('note_private', 'restricthtml'); $object->note_public = GETPOST('note_public', 'restricthtml'); $object->fk_project = GETPOSTINT('projectid'); $object->insurance_amount = GETPOSTINT('insurance_amount'); $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) { $error++; setEventMessages($object->error, $object->errors, 'errors'); $action = 'create'; } } } else { header("Location: list.php"); exit(); } } elseif ($action == 'update' && $permissiontoadd) { // Update record if (!$cancel) { $result = $object->fetch($id); $datestart = dol_mktime(12, 0, 0, GETPOSTINT('startmonth'), GETPOSTINT('startday'), GETPOSTINT('startyear')); $dateend = dol_mktime(12, 0, 0, GETPOSTINT('endmonth'), GETPOSTINT('endday'), GETPOSTINT('endyear')); $capital = (float) price2num(GETPOST('capital')); if (!$capital) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("LoanCapital")), null, 'errors'); $action = 'edit'; } else { $object->datestart = $datestart; $object->dateend = $dateend; $object->capital = $capital; $object->nbterm = (float) price2num(GETPOSTINT("nbterm")); $object->rate = (float) price2num(GETPOST("rate", 'alpha')); $object->insurance_amount = (float) price2num(GETPOSTINT('insurance_amount')); $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); exit; } else { $error++; setEventMessages($object->error, $object->errors, 'errors'); } } else { header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id); exit; } } // Link to a project if ($action == 'classin' && $permissiontoadd) { $object->fetch($id); $result = $object->setProject($projectid); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } } if ($action == 'setlabel' && $permissiontoadd) { $object->fetch($id); $result = $object->setValueFrom('label', GETPOST('label'), '', null, 'text', '', $user, 'LOAN_MODIFY'); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } } // Actions to build doc include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; } /* * View */ $form = new Form($db); $formproject = new FormProjets($db); $morehtmlstatus = ''; $outputlangs = $langs; if (isModEnabled('accounting')) { $formaccounting = new FormAccounting($db); } $title = $langs->trans("Loan").' - '.$langs->trans("Card"); $help_url = 'EN:Module_Loan|FR:Module_Emprunt'; llxHeader("", $title, $help_url, '', 0, 0, '', '', '', 'mod-loan page-card'); // Create mode if ($action == 'create') { //WYSIWYG Editor require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; print load_fiche_titre($langs->trans("NewLoan"), '', 'money-bill-alt'); $datec = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear')); print '
'."\n"; print ''; print ''; print dol_get_fiche_head(); print ''; // Label print ''; // Bank account if (isModEnabled("bank")) { print ''; } else { print ''; } // Capital print ''; // Date Start print ""; print ''; // Date End print ""; print ''; // Number of terms print ''; // Rate print ''; // Insurance amount print ''; // Project if (isModEnabled('project')) { $formproject = new FormProjets($db); // Linked Project $langs->loadLangs(array("projects")); print ''; } // Note Private print ''; print ''; print ''; // Note Public print ''; print ''; print ''; // Accountancy if (isModEnabled('accounting')) { /** @var FormAccounting $formaccounting */ // Accountancy_account_capital print ''; print ''; // Accountancy_account_insurance print ''; print ''; // Accountancy_account_interest print ''; print ''; } else { // For external software // Accountancy_account_capital print ''; print ''; // Accountancy_account_insurance print ''; print ''; // Accountancy_account_interest print ''; print ''; } print '
'.$langs->trans("Label").'
'.$langs->trans("BankAccount").''; $form->select_comptes(GETPOST("accountid"), "accountid", 0, "courant=1", 1); // Show list of bank account with courant print '
'.$langs->trans("BankAccount").''; print $langs->trans("NoBankAccountDefined"); print '
'.$langs->trans("LoanCapital").'
'.$langs->trans("DateStart").''; print $form->selectDate(!empty($datestart) ? $datestart : -1, 'start', 0, 0, 0, 'add', 1, 1); print '
'.$langs->trans("DateEnd").''; print $form->selectDate(!empty($dateend) ? $dateend : -1, 'end', 0, 0, 0, 'add', 1, 1); print '
'.$langs->trans("Nbterms").'
'.$langs->trans("Rate").' %
'.$langs->trans("Insurance").'
'.$langs->trans("Project").''; $numproject = $formproject->select_projects(-1, $projectid, 'projectid', 16, 0, 1, 1); print '
'.$langs->trans('NotePrivate').''; $doleditor = new DolEditor('note_private', GETPOST('note_private', 'alpha'), '', 160, 'dolibarr_notes', 'In', false, true, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_6, '90%'); print $doleditor->Create(1); print '
'.$langs->trans('NotePublic').''; $doleditor = new DolEditor('note_public', GETPOST('note_public', 'alpha'), '', 160, 'dolibarr_notes', 'In', false, true, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_6, '90%'); print $doleditor->Create(1); print '
'.$langs->trans("LoanAccountancyCapitalCode").''; print $formaccounting->select_account(GETPOST('accountancy_account_capital') ? GETPOST('accountancy_account_capital') : getDolGlobalString('LOAN_ACCOUNTING_ACCOUNT_CAPITAL'), 'accountancy_account_capital', 1, '', 1, 1); print '
'.$langs->trans("LoanAccountancyInsuranceCode").''; print $formaccounting->select_account(GETPOST('accountancy_account_insurance') ? GETPOST('accountancy_account_insurance') : getDolGlobalString('LOAN_ACCOUNTING_ACCOUNT_INSURANCE'), 'accountancy_account_insurance', 1, '', 1, 1); print '
'.$langs->trans("LoanAccountancyInterestCode").''; print $formaccounting->select_account(GETPOST('accountancy_account_interest') ? GETPOST('accountancy_account_interest') : getDolGlobalString('LOAN_ACCOUNTING_ACCOUNT_INTEREST'), 'accountancy_account_interest', 1, '', 1, 1); print '
'.$langs->trans("LoanAccountancyCapitalCode").''; print '
'.$langs->trans("LoanAccountancyInsuranceCode").''; print '
'.$langs->trans("LoanAccountancyInterestCode").''; print '
'; print dol_get_fiche_end(); print $form->buttonsSaveCancel("Add"); print '
'; } // View if ($id > 0) { $object = new Loan($db); $result = $object->fetch($id); if ($result > 0) { $head = loan_prepare_head($object); $totalpaid = $object->getSumPayment(); // Confirm for loan if ($action == 'paid') { $text = $langs->trans('ConfirmPayLoan'); print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans('PayLoan'), $text, "confirm_paid", '', '', 2); } if ($action == 'delete') { $text = $langs->trans('ConfirmDeleteLoan'); print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('DeleteLoan'), $text, 'confirm_delete', '', '', 2); } if ($action == 'edit') { print '
'."\n"; print ''; print ''; print ''; } print dol_get_fiche_head($head, 'card', $langs->trans("Loan"), -1, 'money-bill-alt', 0, '', '', 0, '', 1); // Loan card $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; // Ref loan $morehtmlref .= $form->editfieldkey("Label", 'label', $object->label, $object, $user->hasRight('loan', 'write'), 'string', '', 0, 1); $morehtmlref .= $form->editfieldval("Label", 'label', $object->label, $object, $user->hasRight('loan', 'write'), 'string', '', null, null, '', 1); // Project if (isModEnabled('project')) { $langs->loadLangs(array("projects")); $morehtmlref .= '
'.$langs->trans('Project').' '; if ($user->hasRight('loan', 'write')) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' : '; } if ($action == 'classify') { $maxlength = 0; //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); $morehtmlref .= ''; $morehtmlref .= ''; $morehtmlref .= ''; $morehtmlref .= $formproject->select_projects(-1, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); $morehtmlref .= ''; $morehtmlref .= ''; } else { $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, -1, $object->fk_project, 'none', 0, 0, 0, 1, '', 'maxwidth300'); } } else { if (!empty($object->fk_project)) { $proj = new Project($db); $proj->fetch($object->fk_project); $morehtmlref .= ' : '.$proj->getNomUrl(1); if ($proj->title) { $morehtmlref .= ' - '.$proj->title; } } else { $morehtmlref .= ''; } } } $morehtmlref .= '
'; $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, '', $morehtmlstatus); print '
'; print '
'; print '
'; print ''; // Capital if ($action == 'edit') { print ''; print ''; } else { print ''; } // Insurance if ($action == 'edit') { print ''; print ''; } else { print ''; } // Date start print '"; print ""; // Date end print '"; print ""; // Nbterms print ''; print ''; // Rate print ''; print ''; // Accountancy account capital print ''; if ($action == 'edit') { print ''; } else { print ''; } print ''; // Accountancy account insurance print ''; if ($action == 'edit') { print ''; } else { print ''; } print ''; // Accountancy account interest print ''; if ($action == 'edit') { print ''; } else { print ''; } print ''; // Other attributes $parameters = array(); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; print '
'.$langs->trans("LoanCapital").''; print '
'.$langs->trans("LoanCapital").''.price($object->capital, 0, $outputlangs, 1, -1, -1, $conf->currency).'
'.$langs->trans("Insurance").''; print '
'.$langs->trans("Insurance").''.price($object->insurance_amount, 0, $outputlangs, 1, -1, -1, $conf->currency).'
'.$langs->trans("DateStart").""; if ($action == 'edit') { print $form->selectDate($object->datestart, 'start', 0, 0, 0, 'update', 1, 0); } else { print dol_print_date($object->datestart, "day"); } print "
'.$langs->trans("DateEnd").""; if ($action == 'edit') { print $form->selectDate($object->dateend, 'end', 0, 0, 0, 'update', 1, 0); } else { print dol_print_date($object->dateend, "day"); } print "
'.$langs->trans("Nbterms").''; if ($action == 'edit') { print ''; } else { print $object->nbterm; } print '
'.$langs->trans("Rate").''; if ($action == 'edit') { print '%'; } else { print price($object->rate).'%'; } print '
'; print $langs->trans("LoanAccountancyCapitalCode"); print ''; if (isModEnabled('accounting')) { /** @var FormAccounting $formaccounting */ print $formaccounting->select_account($object->account_capital, 'accountancy_account_capital', 1, '', 1, 1); } else { print ''; } print ''; print $langs->trans("LoanAccountancyCapitalCode"); print ''; if (isModEnabled('accounting')) { $accountingaccount = new AccountingAccount($db); $accountingaccount->fetch('', $object->account_capital, 1); print $accountingaccount->getNomUrl(0, 1, 1, '', 1); } else { print $object->account_capital; } print '
'; print $langs->trans("LoanAccountancyInsuranceCode"); print ''; if (isModEnabled('accounting')) { /** @var FormAccounting $formaccounting */ print $formaccounting->select_account($object->account_insurance, 'accountancy_account_insurance', 1, '', 1, 1); } else { print ''; } print ''; print $langs->trans("LoanAccountancyInsuranceCode"); print ''; if (isModEnabled('accounting')) { $accountingaccount = new AccountingAccount($db); $accountingaccount->fetch('', $object->account_insurance, 1); print $accountingaccount->getNomUrl(0, 1, 1, '', 1); } else { print $object->account_insurance; } print '
'; print $langs->trans("LoanAccountancyInterestCode"); print ''; if (isModEnabled('accounting')) { /** @var FormAccounting $formaccounting */ print $formaccounting->select_account($object->account_interest, 'accountancy_account_interest', 1, '', 1, 1); } else { print ''; } print ''; print $langs->trans("LoanAccountancyInterestCode"); print ''; if (isModEnabled('accounting')) { $accountingaccount = new AccountingAccount($db); $accountingaccount->fetch('', $object->account_interest, 1); print $accountingaccount->getNomUrl(0, 1, 1, '', 1); } else { print $object->account_interest; } print '
'; print '
'; print '
'; /* * Payments */ $sql = "SELECT p.rowid, p.num_payment, p.datep as dp,"; $sql .= " p.amount_capital, p.amount_insurance, p.amount_interest,"; $sql .= " b.fk_account,"; $sql .= " c.libelle as paiement_type"; $sql .= " FROM ".MAIN_DB_PREFIX."payment_loan as p"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON p.fk_bank = b.rowid"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as c ON p.fk_typepayment = c.id,"; $sql .= " ".MAIN_DB_PREFIX."loan as l"; $sql .= " WHERE p.fk_loan = ".((int) $id); $sql .= " AND p.fk_loan = l.rowid"; $sql .= " AND l.entity IN ( ".getEntity('loan').")"; $sql .= " ORDER BY dp DESC"; //print $sql; $resql = $db->query($sql); if ($resql) { $num = $db->num_rows($resql); $i = 0; $total_insurance = 0; $total_interest = 0; $total_capital = 0; print '
'; // You can use div-table-responsive-no-min if you don't need reserved height for your table print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; $conf->cache['bankaccount'] = array(); while ($i < $num) { $objp = $db->fetch_object($resql); print ''; print ''; print '\n"; print "\n"; print "\n"; print '\n"; print '\n"; print '\n"; print ""; $total_capital += $objp->amount_capital; $i++; } $totalpaid = $total_capital; if ($object->paid == 0 || $object->paid == 2) { print ''; print ''; $staytopay = $object->capital - $totalpaid; print ''; print ''; } print "
'.$langs->trans("RefPayment").''.$langs->trans("Date").''.$langs->trans("Type").''.$langs->trans("BankAccount").''.$langs->trans("Insurance").''.$langs->trans("Interest").''.$langs->trans("LoanCapital").'
'.img_object($langs->trans("Payment"), "payment").' '.$objp->rowid.''.dol_print_date($db->jdate($objp->dp), 'day')."".$objp->paiement_type.' '.$objp->num_payment.""; if (!empty($conf->cache['bankaccount'][$objp->fk_account])) { $tmpbank = $conf->cache['bankaccount'][$objp->fk_account]; } else { $tmpbank = new Account($db); $tmpbank->fetch($objp->fk_account); $conf->cache['bankaccount'][$objp->fk_account] = $tmpbank; } print $tmpbank->getNomUrl(1); print "'.price($objp->amount_insurance, 0, $outputlangs, 1, -1, -1, $conf->currency)."'.price($objp->amount_interest, 0, $outputlangs, 1, -1, -1, $conf->currency)."'.price($objp->amount_capital, 0, $outputlangs, 1, -1, -1, $conf->currency)."
'.$langs->trans("AlreadyPaid").' :'.price($totalpaid, 0, $langs, 0, -1, -1, $conf->currency).'
'.$langs->trans("AmountExpected").' :'.price($object->capital, 0, $outputlangs, 1, -1, -1, $conf->currency).'
'.$langs->trans("RemainderToPay").' :'; print price($staytopay, 0, $langs, 0, -1, -1, $conf->currency); print '
"; print '
'; $db->free($resql); } else { dol_print_error($db); } print '
'; print '
'; print '
'; print dol_get_fiche_end(); if ($action == 'edit') { print $form->buttonsSaveCancel(); print ''; } /* * Buttons actions */ if ($action != 'edit') { $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook if (empty($reshook)) { print '
'; // Edit if (($object->paid == 0 || $object->paid == 2) && $user->hasRight('loan', 'write')) { print ''; } // Emit payment if (($object->paid == 0 || $object->paid == 2) && ((price2num($object->capital) > 0 && round($staytopay) < 0) || (price2num($object->capital) > 0 && round($staytopay) > 0)) && $user->hasRight('loan', 'write')) { print ''; } // Classify 'paid' if (($object->paid == 0 || $object->paid == 2) && round($staytopay) <= 0 && $user->hasRight('loan', 'write')) { print ''; } // Delete if (($object->paid == 0 || $object->paid == 2) && $user->hasRight('loan', 'delete')) { print ''; } print "
"; } } } else { // Loan not found dol_print_error(null, $object->error); } } // End of page llxFooter(); $db->close();