diff --git a/ChangeLog b/ChangeLog index 2a72296477c..43fecf4d2e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,8 +2,20 @@ English Dolibarr ChangeLog -------------------------------------------------------------- + +***** ChangeLog for 8.0.0 compared to 7.0.0 ***** + +WARNING: + +Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: +* Hook 'maildao' was renamed into 'mail' into the method sendfile that send emails, and method was renamed from + 'doaction' into 'sendMail'. + + ***** ChangeLog for 7.0.0 compared to 6.0.5 ***** For users: +NEW: When payment is registered, PDF of invoices are also regenerated so payments + appears with no need to click on regenerate. NEW: #5711 Add shipment line deleting and editing for draft shipments. NEW: Accept substitution key __[ABC]__ replaced with value of const ABC NEW: Accountancy Add variant on sell account for intracommunity sales & export sales @@ -276,6 +288,12 @@ Following changes may create regressions for some external modules, but were nec and add 'td.' to the beginning of the dragHandle match string. * IE8 and earlier and Firefox 12 and earlier (< 2012) are no more supported. +* If you use the external module "multicompany", you must also upgrade the module. Multicompany module for + Dolibarr v7 is required because with Dolibarr v7, payment modes and payment conditions are management as data + that are dedicated to each company. If you keep your old version of multicompany module, mode and + condition of payments will appears empty in all companies that are not the first one. By upgrading the + multicompany module to a version that support Dolibarr v7, everything should work as expected. + ***** ChangeLog for 6.0.5 compared to 6.0.4 ***** FIX: security vulnerability reported by ADLab of Venustech diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 8ecf04fdbc8..42328fbc1ed 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -87,7 +87,7 @@ $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; if ($sortorder == "") $sortorder = "ASC"; -if ($sortfield == "") $sortfield = "t.rowid"; +if ($sortfield == "") $sortfield = "t.piece_num,t.rowid"; $object = new BookKeeping($db); @@ -98,25 +98,30 @@ $form = new Form($db); if (! in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && ! isset($_POST['begin']) && ! isset($_GET['begin']) && ! isset($_POST['formfilteraction']) && GETPOST('page','int') == '' && ! GETPOST('noreset','int')) { - $query = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; - $query.= " where date_start < '".$this->idate(dol_now())."' and date_end > '".$this->idate(dol_now())."' limit 1"; - $res = $db->query($query); - if ($res->num_rows > 0) { - $fiscalYear = $db->fetch_object($res); - $search_date_start = strtotime($fiscalYear->date_start); - $search_date_end = strtotime($fiscalYear->date_end); - } else { - $month_start= ($conf->global->SOCIETE_FISCAL_MONTH_START?($conf->global->SOCIETE_FISCAL_MONTH_START):1); - $year_start = dol_print_date(dol_now(), '%Y'); - $year_end = $year_start + 1; - $month_end = $month_start - 1; - if ($month_end < 1) - { - $month_end = 12; - $year_end--; + if (empty($search_date_start) && empty($search_date_end)) + { + $query = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; + $query.= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."' limit 1"; + $res = $db->query($query); + + if ($res->num_rows > 0) { + $fiscalYear = $db->fetch_object($res); + $search_date_start = strtotime($fiscalYear->date_start); + $search_date_end = strtotime($fiscalYear->date_end); + } else { + $month_start= ($conf->global->SOCIETE_FISCAL_MONTH_START?($conf->global->SOCIETE_FISCAL_MONTH_START):1); + $year_start = dol_print_date(dol_now(), '%Y'); + if (dol_print_date(dol_now(), '%m') < $month_start) $year_start--; // If current month is lower that starting fiscal month, we start last year + $year_end = $year_start + 1; + $month_end = $month_start - 1; + if ($month_end < 1) + { + $month_end = 12; + $year_end--; + } + $search_date_start = dol_mktime(0, 0, 0, $month_start, 1, $year_start); + $search_date_end = dol_get_last_day($year_end, $month_end); } - $search_date_start = dol_mktime(0, 0, 0, $month_start, 1, $year_start); - $search_date_end = dol_get_last_day($year_end, $month_end); } } @@ -124,7 +129,7 @@ if (! in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && ! $arrayfields=array( 't.piece_num'=>array('label'=>$langs->trans("TransactionNumShort"), 'checked'=>1), 't.doc_date'=>array('label'=>$langs->trans("Docdate"), 'checked'=>1), - 't.doc_ref'=>array('label'=>$langs->trans("Docref"), 'checked'=>1), + 't.doc_ref'=>array('label'=>$langs->trans("Piece"), 'checked'=>1), 't.numero_compte'=>array('label'=>$langs->trans("AccountAccountingShort"), 'checked'=>1), 't.subledger_account'=>array('label'=>$langs->trans("SubledgerAccount"), 'checked'=>1), 't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1), @@ -430,7 +435,7 @@ else $button.= $langs->trans("ExportList"); $button.= ''; -$groupby = ' ' . $langs->trans("GroupByAccountAccounting") . ''; +$groupby = ' ' . $langs->trans("GroupByAccountAccounting") . ''; $addbutton = '' . $langs->trans("NewAccountingMvt") . ''; print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, $groupby.$addbutton, '', $limit); @@ -576,17 +581,17 @@ print ''; print "\n"; print ''; -if (! empty($arrayfields['t.piece_num']['checked'])) print_liste_field_titre("TransactionNumShort", $_SERVER['PHP_SELF'], "t.piece_num", "", $param, "", $sortfield, $sortorder); -if (! empty($arrayfields['t.doc_date']['checked'])) print_liste_field_titre("Docdate", $_SERVER['PHP_SELF'], "t.doc_date", "", $param, 'align="center"', $sortfield, $sortorder); -if (! empty($arrayfields['t.doc_ref']['checked'])) print_liste_field_titre("Docref", $_SERVER['PHP_SELF'], "t.doc_ref", "", $param, "", $sortfield, $sortorder); -if (! empty($arrayfields['t.numero_compte']['checked'])) print_liste_field_titre("AccountAccountingShort", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder); -if (! empty($arrayfields['t.subledger_account']['checked'])) print_liste_field_titre("SubledgerAccount", $_SERVER['PHP_SELF'], "t.subledger_account", "", $param, "", $sortfield, $sortorder); -if (! empty($arrayfields['t.label_operation']['checked'])) print_liste_field_titre("Label", $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder); -if (! empty($arrayfields['t.debit']['checked'])) print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $param, 'align="right"', $sortfield, $sortorder); -if (! empty($arrayfields['t.credit']['checked'])) print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $param, 'align="right"', $sortfield, $sortorder); -if (! empty($arrayfields['t.code_journal']['checked'])) print_liste_field_titre("Codejournal", $_SERVER['PHP_SELF'], "t.code_journal", "", $param, 'align="center"', $sortfield, $sortorder); -if (! empty($arrayfields['t.date_creation']['checked'])) print_liste_field_titre("DateCreation", $_SERVER['PHP_SELF'], "t.date_creation", "", $param, 'align="center"', $sortfield, $sortorder); -if (! empty($arrayfields['t.tms']['checked'])) print_liste_field_titre("DateModification", $_SERVER['PHP_SELF'], "t.tms", "", $param, 'align="center"', $sortfield, $sortorder); +if (! empty($arrayfields['t.piece_num']['checked'])) print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, "", $sortfield, $sortorder); +if (! empty($arrayfields['t.doc_date']['checked'])) print_liste_field_titre($arrayfields['t.doc_date']['label'], $_SERVER['PHP_SELF'], "t.doc_date", "", $param, 'align="center"', $sortfield, $sortorder); +if (! empty($arrayfields['t.doc_ref']['checked'])) print_liste_field_titre($arrayfields['t.doc_ref']['label'], $_SERVER['PHP_SELF'], "t.doc_ref", "", $param, "", $sortfield, $sortorder); +if (! empty($arrayfields['t.numero_compte']['checked'])) print_liste_field_titre($arrayfields['t.numero_compte']['label'], $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder); +if (! empty($arrayfields['t.subledger_account']['checked'])) print_liste_field_titre($arrayfields['t.subledger_account']['label'], $_SERVER['PHP_SELF'], "t.subledger_account", "", $param, "", $sortfield, $sortorder); +if (! empty($arrayfields['t.label_operation']['checked'])) print_liste_field_titre($arrayfields['t.label_operation']['label'], $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder); +if (! empty($arrayfields['t.debit']['checked'])) print_liste_field_titre($arrayfields['t.debit']['label'], $_SERVER['PHP_SELF'], "t.debit", "", $param, 'align="right"', $sortfield, $sortorder); +if (! empty($arrayfields['t.credit']['checked'])) print_liste_field_titre($arrayfields['t.credit']['label'], $_SERVER['PHP_SELF'], "t.credit", "", $param, 'align="right"', $sortfield, $sortorder); +if (! empty($arrayfields['t.code_journal']['checked'])) print_liste_field_titre($arrayfields['t.code_journal']['label'], $_SERVER['PHP_SELF'], "t.code_journal", "", $param, 'align="center"', $sortfield, $sortorder); +if (! empty($arrayfields['t.date_creation']['checked'])) print_liste_field_titre($arrayfields['t.date_creation']['label'], $_SERVER['PHP_SELF'], "t.date_creation", "", $param, 'align="center"', $sortfield, $sortorder); +if (! empty($arrayfields['t.tms']['checked'])) print_liste_field_titre($arrayfields['t.tms']['label'], $_SERVER['PHP_SELF'], "t.tms", "", $param, 'align="center"', $sortfield, $sortorder); print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch '); print "\n"; @@ -677,14 +682,14 @@ if ($num > 0) // Creation operation date if (! empty($arrayfields['t.date_creation']['checked'])) { - print '' . dol_print_date($line->date_creation, 'day') . ''; + print '' . dol_print_date($line->date_creation, 'dayhour') . ''; if (! $i) $totalarray['nbfield']++; } // Modification operation date if (! empty($arrayfields['t.tms']['checked'])) { - print '' . dol_print_date($line->date_modification, 'day') . ''; + print '' . dol_print_date($line->date_modification, 'dayhour') . ''; if (! $i) $totalarray['nbfield']++; } @@ -704,6 +709,7 @@ if ($num > 0) if (isset($totalarray['totaldebitfield']) || isset($totalarray['totalcreditfield'])) { $i=0; + print ''; while ($i < $totalarray['nbfield']) { $i++; diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index 08aa1aac19d..c450fb5bb63 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -68,7 +68,7 @@ $pagenext = $page + 1; if ($sortorder == "") $sortorder = "ASC"; if ($sortfield == "") $sortfield = "t.rowid"; -if (empty($search_date_start)) { +if (empty($search_date_start) && empty($search_date_end)) { $sql = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; $sql.= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."'"; $sql.= $db->plimit(1); @@ -81,6 +81,7 @@ if (empty($search_date_start)) { } else { $month_start= ($conf->global->SOCIETE_FISCAL_MONTH_START?($conf->global->SOCIETE_FISCAL_MONTH_START):1); $year_start = dol_print_date(dol_now(), '%Y'); + if (dol_print_date(dol_now(), '%m') < $month_start) $year_start--; // If current month is lower that starting fiscal month, we start last year $year_end = $year_start + 1; $month_end = $month_start - 1; if ($month_end < 1) @@ -225,14 +226,13 @@ if ($action == 'delbookkeepingyear') { } - +$param=$options; print '
'; -$viewflat = ' ' . $langs->trans("ViewFlatList") . ''; +$viewflat = ' ' . $langs->trans("ViewFlatList") . ''; $addbutton = '' . $langs->trans("NewAccountingMvt") . ''; -$param=$options; if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 4aba5bb0591..b59258f6cd7 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -781,7 +781,8 @@ class BookKeeping extends CommonObject $sql .= " t.code_journal,"; $sql .= " t.journal_label,"; $sql .= " t.piece_num,"; - $sql .= " t.date_creation"; + $sql .= " t.date_creation,"; + $sql .= " t.tms as date_modification"; $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; // Manage filter $sqlwhere = array (); @@ -849,7 +850,8 @@ class BookKeeping extends CommonObject $line->code_journal = $obj->code_journal; $line->journal_label = $obj->journal_label; $line->piece_num = $obj->piece_num; - $line->date_creation = $obj->date_creation; + $line->date_creation = $this->db->jdate($obj->date_creation); + $line->date_modification = $this->db->jdate($obj->date_modification); $this->lines[] = $line; } diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index b9b079067b8..8b9215f5c4c 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -271,7 +271,8 @@ if ($result) { if ($links[$key]['type'] == 'payment') { $paymentstatic->id = $links[$key]['url_id']; - $tabpay[$obj->rowid]["lib"] .= ' ' . $paymentstatic->getNomUrl(2); + $paymentstatic->ref = $links[$key]['url_id']; + $tabpay[$obj->rowid]["lib"] .= ' ' . $paymentstatic->getNomUrl(2, '', ''); // TODO Do not include list of invoice in tooltip, the dol_string_nohtmltag is ko with this $tabpay[$obj->rowid]["paymentid"] = $paymentstatic->id; } else if ($links[$key]['type'] == 'payment_supplier') { $paymentsupplierstatic->id = $links[$key]['url_id']; @@ -303,6 +304,7 @@ if ($result) { } $chargestatic->ref = $chargestatic->lib; $tabpay[$obj->rowid]["soclib"] = $chargestatic->getNomUrl(1, 30); + $tabpay[$obj->rowid]["paymentscid"] = $chargestatic->id; $sqlmid = 'SELECT cchgsoc.accountancy_code'; $sqlmid .= " FROM " . MAIN_DB_PREFIX . "c_chargesociales cchgsoc "; @@ -319,11 +321,12 @@ if ($result) { } } else if ($links[$key]['type'] == 'payment_donation') { $paymentdonstatic->id = $links[$key]['url_id']; + $paymentdonstatic->ref = $links[$key]['url_id']; $paymentdonstatic->fk_donation = $links[$key]['url_id']; $tabpay[$obj->rowid]["lib"] .= ' ' . $paymentdonstatic->getNomUrl(2); $tabpay[$obj->rowid]["paymentdonationid"] = $paymentdonstatic->id; $tabtp[$obj->rowid][$account_pay_donation] += $obj->amount; - } else if ($links[$key]['type'] == 'payment_vat') { + } else if ($links[$key]['type'] == 'payment_vat') { // Payment VAT $paymentvatstatic->id = $links[$key]['url_id']; $paymentvatstatic->ref = $links[$key]['url_id']; $paymentvatstatic->label = $links[$key]['label']; @@ -401,7 +404,9 @@ if (! $error && $action == 'writebookkeeping') { $now = dol_now(); $error = 0; - foreach ( $tabpay as $key => $val ) { // $key is rowid into llx_bank + foreach ( $tabpay as $key => $val ) // $key is rowid into llx_bank + { + $date = dol_print_date($db->jdate($val["date"]), 'day'); $ref = getSourceDocRef($val, $tabtype[$key]); @@ -423,7 +428,13 @@ if (! $error && $action == 'writebookkeeping') { // Line into bank account foreach ( $tabbq[$key] as $k => $mt ) { - if ($mt) { + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . " - "; + $reflabel.= $langs->trans("Bank").' '.dol_string_nohtmltag($val['bank_account_ref']); + if (! empty($val['soclib'])) $reflabel .= " - " . dol_string_nohtmltag($val['soclib']); + $bookkeeping = new BookKeeping($db); $bookkeeping->doc_date = $val["date"]; $bookkeeping->doc_ref = $ref; @@ -442,31 +453,8 @@ if (! $error && $action == 'writebookkeeping') { $bookkeeping->date_create = $now; // No subledger_account value for the bank line but add a specific label_operation - if ($tabtype[$key] == 'payment') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $tabcompany[$key]['name'] . ' - ' . $ref; - } else if ($tabtype[$key] == 'payment_supplier') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $tabcompany[$key]['name'] . ' - ' . $ref; - } else if ($tabtype[$key] == 'payment_expensereport') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $tabuser[$key]['name'] . ' - ' . $ref; - } else if ($tabtype[$key] == 'payment_salary') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $tabuser[$key]['name'] . ' - ' . $ref; - } else if ($tabtype[$key] == 'payment_vat') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $ref; - } else if ($tabtype[$key] == 'payment_donation') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $ref; - } else if ($tabtype[$key] == 'payment_various') { - $bookkeeping->subledger_account = ''; - $bookkeeping->label_operation = $ref; - } else if ($tabtype[$key] == 'unknown') { - // ??? - $bookkeeping->subledger_account = ''; - } + $bookkeeping->subledger_account = ''; + $bookkeeping->label_operation = $reflabel; $totaldebit += $bookkeeping->debit; $totalcredit += $bookkeeping->credit; @@ -491,108 +479,155 @@ if (! $error && $action == 'writebookkeeping') { } // Third party - if (! $errorforline && is_array($tabtp[$key])) + if (! $errorforline) { - // Line into thirdparty account - foreach ( $tabtp[$key] as $k => $mt ) { - if ($mt) { - $bookkeeping = new BookKeeping($db); - $bookkeeping->doc_date = $val["date"]; - $bookkeeping->doc_ref = $ref; - $bookkeeping->doc_type = 'bank'; - $bookkeeping->fk_doc = $key; - $bookkeeping->fk_docdet = $val["fk_bank"]; - $bookkeeping->montant = $mt; - $bookkeeping->sens = ($mt < 0) ? 'D' : 'C'; - $bookkeeping->debit = ($mt < 0 ? - $mt : 0); - $bookkeeping->credit = ($mt >= 0) ? $mt : 0; - $bookkeeping->code_journal = $journal; - $bookkeeping->journal_label = $journal_label; - $bookkeeping->fk_user_author = $user->id; - $bookkeeping->date_create = $now; + if (is_array($tabtp[$key])) + { + // Line into thirdparty account + foreach ( $tabtp[$key] as $k => $mt ) { + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . ($val['soclib']?" - ":""); + $reflabel.= dol_string_nohtmltag($val['soclib']); - if ($tabtype[$key] == 'payment') { // If payment is payment of customer invoice, we get ref of invoice - $bookkeeping->label_operation = $tabcompany[$key]['name'] . ' - ' . $ref; - $bookkeeping->subledger_account = $tabcompany[$key]['code_compta']; - $bookkeeping->subledger_label = $tabcompany[$key]['name']; - $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'payment_supplier') { // If payment is payment of supplier invoice, we get ref of invoice - $bookkeeping->label_operation = $tabcompany[$key]['name'] . ' - ' . $ref; - $bookkeeping->subledger_account = $tabcompany[$key]['code_compta']; - $bookkeeping->subledger_label = $tabcompany[$key]['name']; - $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'payment_expensereport') { - $bookkeeping->label_operation = $tabuser[$key]['name'] . ' - ' . $ref; - $bookkeeping->subledger_account = $tabuser[$key]['accountancy_code']; - $bookkeeping->subledger_label = $tabuser[$key]['name']; - $bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'payment_salary') { - $bookkeeping->label_operation = $tabuser[$key]['name'] . ' - ' . $ref; - $bookkeeping->subledger_account = $tabuser[$key]['accountancy_code']; - $bookkeeping->subledger_label = $tabuser[$key]['name']; - $bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT; - $bookkeeping->label_compte = ''; - } else if (in_array($tabtype[$key], array('sc', 'payment_sc'))) { // If payment is payment of social contribution - $bookkeeping->label_operation = $ref; - $bookkeeping->subledger_account = ''; - $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $k; - $bookkeeping->label_compte = $objmid->labelc; - } else if ($tabtype[$key] == 'payment_vat') { - $bookkeeping->label_operation = $ref; - $bookkeeping->subledger_account = ''; - $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $k; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'payment_donation') { - $bookkeeping->label_operation = $ref; - $bookkeeping->subledger_account = ''; - $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $k; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'payment_various') { - $bookkeeping->label_operation = $ref; - $bookkeeping->subledger_account = ''; - $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $k; - $bookkeeping->label_compte = ''; - } else if ($tabtype[$key] == 'banktransfert') { - $bookkeeping->label_operation = $ref; - $bookkeeping->subledger_account = ''; - $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $k; - $bookkeeping->label_compte = ''; - } else { - if ($tabtype[$key] == 'unknown') // Unknown transaction, we will use a waiting account for thirdparty. - { - // Temporary account - $bookkeeping->label_operation = ''; + $bookkeeping = new BookKeeping($db); + $bookkeeping->doc_date = $val["date"]; + $bookkeeping->doc_ref = $ref; + $bookkeeping->doc_type = 'bank'; + $bookkeeping->fk_doc = $key; + $bookkeeping->fk_docdet = $val["fk_bank"]; + $bookkeeping->montant = $mt; + $bookkeeping->sens = ($mt < 0) ? 'D' : 'C'; + $bookkeeping->debit = ($mt < 0 ? - $mt : 0); + $bookkeeping->credit = ($mt >= 0) ? $mt : 0; + $bookkeeping->code_journal = $journal; + $bookkeeping->journal_label = $journal_label; + $bookkeeping->fk_user_author = $user->id; + $bookkeeping->date_create = $now; + + if ($tabtype[$key] == 'payment') { // If payment is payment of customer invoice, we get ref of invoice + $bookkeeping->subledger_account = $tabcompany[$key]['code_compta']; + $bookkeeping->subledger_label = $tabcompany[$key]['name']; + $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER; + $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'payment_supplier') { // If payment is payment of supplier invoice, we get ref of invoice + $bookkeeping->subledger_account = $tabcompany[$key]['code_compta']; + $bookkeeping->subledger_label = $tabcompany[$key]['name']; + $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER; + $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'payment_expensereport') { + $bookkeeping->subledger_account = $tabuser[$key]['accountancy_code']; + $bookkeeping->subledger_label = $tabuser[$key]['name']; + $bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT; + $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'payment_salary') { + $bookkeeping->subledger_account = $tabuser[$key]['accountancy_code']; + $bookkeeping->subledger_label = $tabuser[$key]['name']; + $bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT; + $bookkeeping->label_compte = ''; + } else if (in_array($tabtype[$key], array('sc', 'payment_sc'))) { // If payment is payment of social contribution $bookkeeping->subledger_account = ''; $bookkeeping->subledger_label = ''; - $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUSPENSE; + $bookkeeping->numero_compte = $k; + $bookkeeping->label_compte = $objmid->labelc; + } else if ($tabtype[$key] == 'payment_vat') { + $bookkeeping->subledger_account = ''; + $bookkeeping->subledger_label = ''; + $bookkeeping->numero_compte = $k; $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'payment_donation') { + $bookkeeping->subledger_account = ''; + $bookkeeping->subledger_label = ''; + $bookkeeping->numero_compte = $k; + $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'payment_various') { + $bookkeeping->subledger_account = ''; + $bookkeeping->subledger_label = ''; + $bookkeeping->numero_compte = $k; + $bookkeeping->label_compte = ''; + } else if ($tabtype[$key] == 'banktransfert') { + $bookkeeping->subledger_account = ''; + $bookkeeping->subledger_label = ''; + $bookkeeping->numero_compte = $k; + $bookkeeping->label_compte = ''; + } else { + if ($tabtype[$key] == 'unknown') // Unknown transaction, we will use a waiting account for thirdparty. + { + // Temporary account + $bookkeeping->subledger_account = ''; + $bookkeeping->subledger_label = ''; + $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUSPENSE; + $bookkeeping->label_compte = ''; + } + } + + $bookkeeping->label_operation = $reflabel; + + $totaldebit += $bookkeeping->debit; + $totalcredit += $bookkeeping->credit; + + $result = $bookkeeping->create($user); + if ($result < 0) { + if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') // Already exists + { + $error++; + $errorforline++; + setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings'); + } + else + { + $error++; + $errorforline++; + setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors'); + } } } + } + } + else { // If thirdparty unkown, output the waiting account + foreach ( $tabbq[$key] as $k => $mt ) { + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . " - "; + $reflabel.= dol_string_nohtmltag('WaitingAccount'); - $totaldebit += $bookkeeping->debit; - $totalcredit += $bookkeeping->credit; + $bookkeeping = new BookKeeping($db); + $bookkeeping->doc_date = $val["date"]; + $bookkeeping->doc_ref = $ref; + $bookkeeping->doc_type = 'bank'; + $bookkeeping->fk_doc = $key; + $bookkeeping->fk_docdet = $val["fk_bank"]; + $bookkeeping->montant = $mt; + $bookkeeping->sens = ($mt < 0) ? 'D' : 'C'; + $bookkeeping->debit = ($mt < 0 ? - $mt : 0); + $bookkeeping->credit = ($mt >= 0) ? $mt : 0; + $bookkeeping->code_journal = $journal; + $bookkeeping->journal_label = $journal_label; + $bookkeeping->fk_user_author = $user->id; + $bookkeeping->date_create = $now; + $bookkeeping->label_compte = ''; - $result = $bookkeeping->create($user); - if ($result < 0) { - if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') // Already exists - { - $error++; - $errorforline++; - setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings'); - } - else - { - $error++; - $errorforline++; - setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors'); + $bookkeeping->label_operation = $reflabel; + + $totaldebit += $bookkeeping->debit; + $totalcredit += $bookkeeping->credit; + + $result = $bookkeeping->create($user); + if ($result < 0) { + if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') // Already exists + { + $error++; + $errorforline++; + setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->fk_doc.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings'); + } + else + { + $error++; + $errorforline++; + setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors'); + } } } } @@ -662,101 +697,105 @@ if ($action == 'exportcsv') { // ISO and not UTF8 ! include DOL_DOCUMENT_ROOT . '/accountancy/tpl/export_journal.tpl.php'; - $companystatic = new Client($db); - $userstatic = new User($db); + // CSV header line + print '"' . $langs->trans("BankId").'"' . $sep; + print '"' . $langs->trans("Date") . '"' . $sep; + print '"' . $langs->trans("PaymentMode") . '"' . $sep; + print '"' . $langs->trans("AccountAccounting") . '"' . $sep; + print '"' . $langs->trans("LedgerAccount") . '"' . $sep; + print '"' . $langs->trans("SubledgerAccount") . '"' . $sep; + print '"' . $langs->trans("Label"). '"' . $sep; + print '"' . $langs->trans("Amount") . '"' . $sep; + print '"' . $langs->trans("Amount") . '"' . $sep; + print '"' . $langs->trans("Journal") . '"' . $sep; + print '"' . $langs->trans("Note") . '"' . $sep; + print "\n"; - foreach ( $tabpay as $key => $val ) { + + foreach ( $tabpay as $key => $val ) + { $date = dol_print_date($db->jdate($val["date"]), 'day'); $ref = getSourceDocRef($val, $tabtype[$key]); - // - if (! empty($tabcompany[$key]['id'])) - { - $companystatic->id = $tabcompany[$key]['id']; - $companystatic->name = $tabcompany[$key]['name']; - } - else - { - $companystatic->id = 0; - $companystatic->name = ''; - } - if (! empty($tabuser[$key]['id'])) - { - $userstatic->id = $tabuser[$key]['id']; - $userstatic->lastname = $tabuser[$key]['lastname']; - $userstatic->firstname = $tabuser[$key]['firstname']; - } - else - { - $userstatic->id = 0; - $userstatic->lastname = ''; - $userstatic->firstname = ''; - } - // Bank foreach ( $tabbq[$key] as $k => $mt ) { - print '"' . $key . '"' . $sep; - print '"' . $date . '"' . $sep; - print '"' . $val["type_payment"] . '"' . $sep; - print '"' . length_accountg(html_entity_decode($k)) . '"' . $sep; - print '"' . length_accountg(html_entity_decode($k)) . '"' . $sep; - print " " . $sep; - if ($companystatic->name == '') { - print '"' . $val['bank_account_ref'] . " - " . utf8_decode($reflabel) . '"' . $sep; - } else { - print '"' . $val['bank_account_ref'] . ' - ' . utf8_decode($companystatic->name) . '"' . $sep; + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . " - "; + $reflabel.= $langs->trans("Bank").' '.dol_string_nohtmltag($val['bank_account_ref']); + if (! empty($val['soclib'])) $reflabel .= " - " . dol_string_nohtmltag($val['soclib']); + + print '"' . $key . '"' . $sep; + print '"' . $date . '"' . $sep; + print '"' . $val["type_payment"] . '"' . $sep; + print '"' . length_accountg(html_entity_decode($k)) . '"' . $sep; + print '"' . length_accountg(html_entity_decode($k)) . '"' . $sep; + print " " . $sep; + print '"' . $reflabel . '"' . $sep; + print '"' . ($mt >= 0 ? price($mt) : '') . '"' . $sep; + print '"' . ($mt < 0 ? price(- $mt) : '') . '"' . $sep; + print '"' . $journal . '"' . $sep; + print '"' . dol_string_nohtmltag($ref) . '"' . $sep; + print "\n"; } - print '"' . ($mt >= 0 ? price($mt) : '') . '"' . $sep; - print '"' . ($mt < 0 ? price(- $mt) : '') . '"' . $sep; - print '"' . $journal . '"' . $sep; - print "\n"; } // Third party if (is_array($tabtp[$key])) { foreach ( $tabtp[$key] as $k => $mt ) { - if ($mt) { + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . ($val['soclib']?" - ":""); + $reflabel.= dol_string_nohtmltag($val['soclib']); + print '"' . $key . '"' . $sep; print '"' . $date . '"' . $sep; print '"' . $val["type_payment"] . '"' . $sep; print '"' . length_accounta(html_entity_decode($k)) . '"' . $sep; if ($tabtype[$key] == 'payment_supplier') { - print '"' . $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER . '"' . $sep; + print '"' . $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER . '"' . $sep; } else if($tabtype[$key] == 'payment') { - print '"' . $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER . '"' . $sep; + print '"' . $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER . '"' . $sep; + } else if($tabtype[$key] == 'payment_expensereport') { + print '"' . $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT . '"' . $sep; + } else if($tabtype[$key] == 'payment_salary') { + print '"' . $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT . '"' . $sep; } else { - print '"' . length_accounta(html_entity_decode($k)) . '"' . $sep; + print '"' . length_accounta(html_entity_decode($k)) . '"' . $sep; } print '"' . length_accounta(html_entity_decode($k)) . '"' . $sep; - if ($companystatic->name == '') { - print '"' . $langs->trans('ThirdParty') . " - " . utf8_decode($reflabel) . '"' . $sep; - } else { - print '"' . $langs->trans('ThirdParty') . " - " . utf8_decode($companystatic->name) . '"' . $sep; - } + print '"' . $reflabel . '"' . $sep; print '"' . ($mt < 0 ? price(- $mt) : '') . '"' . $sep; print '"' . ($mt >= 0 ? price($mt) : '') . '"' . $sep; print '"' . $journal . '"' . $sep; + print '"' . dol_string_nohtmltag($ref) . '"' . $sep; print "\n"; } } - } else { + } else { // If thirdparty unkown, output the waiting account foreach ( $tabbq[$key] as $k => $mt ) { - print '"' . $key . '"' . $sep; - print '"' . $date . '"' . $sep; - print '"' . $val["type_payment"] . '"' . $sep; - print '"' . length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE) . '"' . $sep; - print '"' . length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE) . '"' . $sep; - print " " . $sep; - if ($companystatic->name == '') { - print '"' . $val['bank_account_ref'] . ' - ' . utf8_decode($reflabel) . '"' . $sep; - } else { - print '"' . $val['bank_account_ref'] . ' - ' . utf8_decode($companystatic->name) . '"' . $sep; + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= dol_string_nohtmltag($val['lib']) . " - "; + $reflabel.= dol_string_nohtmltag('WaitingAccount'); + + print '"' . $key . '"' . $sep; + print '"' . $date . '"' . $sep; + print '"' . $val["type_payment"] . '"' . $sep; + print '"' . length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE) . '"' . $sep; + print '"' . length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE) . '"' . $sep; + print "" . $sep; + print '"' . $reflabel . '"' . $sep; + print '"' . ($mt < 0 ? price(- $mt) : '') . '"' . $sep; + print '"' . ($mt >= 0 ? price($mt) : '') . '"' . $sep; + print '"' . $journal . '"' . $sep; + print '"' . dol_string_nohtmltag($ref) . '"' . $sep; + print "\n"; } - print '"' . ($mt < 0 ? price(- $mt) : '') . '"' . $sep; - print '"' . ($mt >= 0 ? price($mt) : '') . '"' . $sep; - print '"' . $journal . '"' . $sep; - print "\n"; } } } @@ -862,7 +901,8 @@ if (empty($action) || $action == 'view') { $r = ''; - foreach ( $tabpay as $key => $val ) { // $key is rowid in llx_bank + foreach ( $tabpay as $key => $val ) // $key is rowid in llx_bank + { $date = dol_print_date($db->jdate($val["date"]), 'day'); $ref = getSourceDocRef($val, $tabtype[$key]); @@ -870,48 +910,56 @@ if (empty($action) || $action == 'view') { // Bank foreach ( $tabbq[$key] as $k => $mt ) { - //var_dump($tabpay[$key]); - print ''; - print ''; - print ""; - print "" . $date . ""; - print "" . $ref . ""; - // Ledger account - print ""; - $accounttoshow = length_accountg($k); - if (empty($accounttoshow) || $accounttoshow == 'NotDefined') + if ($mt) { - print ''.$langs->trans("BankAccountNotDefined").''; + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= $val['lib'] . " - "; + $reflabel.= $langs->trans("Bank").' '.$val['bank_account_ref']; + if (! empty($val['soclib'])) $reflabel .= " - " . $val['soclib']; + + //var_dump($tabpay[$key]); + print ''; + print ''; + print ""; + print "" . $date . ""; + print "" . $ref . ""; + // Ledger account + print ""; + $accounttoshow = length_accountg($k); + if (empty($accounttoshow) || $accounttoshow == 'NotDefined') + { + print ''.$langs->trans("BankAccountNotDefined").''; + } + else print $accounttoshow; + print ""; + // Subledger account + print ""; + /*$accounttoshow = length_accountg($k); + if (empty($accounttoshow) || $accounttoshow == 'NotDefined') + { + print ''.$langs->trans("BankAccountNotDefined").''; + } + else print $accounttoshow;*/ + print ""; + print ""; + print $reflabel; + print ""; + print "" . $val["type_payment"] . ""; + print "" . ($mt >= 0 ? price($mt) : '') . ""; + print "" . ($mt < 0 ? price(- $mt) : '') . ""; + print ""; } - else print $accounttoshow; - print ""; - // Subledger account - print ""; - /*$accounttoshow = length_accountg($k); - if (empty($accounttoshow) || $accounttoshow == 'NotDefined') - { - print ''.$langs->trans("BankAccountNotDefined").''; - } - else print $accounttoshow;*/ - print ""; - print ""; - //var_dump($tabpay[$key]); - print $langs->trans("Bank"); - print ' '.$val['bank_account_ref']; - if (! empty($val['soclib'])) { - print " - " . $val['soclib']; - } - print ""; - print "" . $val["type_payment"] . ""; - print "" . ($mt >= 0 ? price($mt) : '') . ""; - print "" . ($mt < 0 ? price(- $mt) : '') . ""; - print ""; } // Third party if (is_array($tabtp[$key])) { foreach ( $tabtp[$key] as $k => $mt ) { - if ($k != 'type') { + if ($mt) + { + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= $val['lib'] . ($val['soclib']?" - ":""); + $reflabel.= $val['soclib']; + print ''; print ''; print ""; @@ -974,42 +1022,49 @@ if (empty($action) || $action == 'view') { } } print ""; - print "" . $reflabel . ' ' . $val['soclib'] . ""; + print "" . $reflabel . ""; print "" . $val["type_payment"] . ""; print "" . ($mt < 0 ? price(- $mt) : '') . ""; print "" . ($mt >= 0 ? price($mt) : '') . ""; print ""; } } - } else { + } else { // Waiting account foreach ( $tabbq[$key] as $k => $mt ) { - print ''; - print ''; - print ""; - print "" . $date . ""; - print "" . $ref . ""; - // Ledger account - print ""; - /*if (empty($accounttoshow) || $accounttoshow == 'NotDefined') + if ($mt) { - print ''.$langs->trans("WaitAccountNotDefined").''; + $reflabel = ''; + if (! empty($val['lib'])) $reflabel .= $val['lib'] . " - "; + $reflabel.= 'WaitingAccount'; + + print ''; + print ''; + print ""; + print "" . $date . ""; + print "" . $ref . ""; + // Ledger account + print ""; + /*if (empty($accounttoshow) || $accounttoshow == 'NotDefined') + { + print ''.$langs->trans("WaitAccountNotDefined").''; + } + else */ print length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE); + print ""; + // Subledger account + print ""; + /*if (empty($accounttoshowsubledger) || $accounttoshowsubledger == 'NotDefined') + { + print ''.$langs->trans("WaitAccountNotDefined").''; + } + else print length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE); + */ + print ""; + print "" . $reflabel . ""; + print "" . $val["type_payment"] . ""; + print "" . ($mt < 0 ? price(- $mt) : '') . ""; + print "" . ($mt >= 0 ? price($mt) : '') . ""; + print ""; } - else */ print length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE); - print ""; - // Subledger account - print ""; - /*if (empty($accounttoshowsubledger) || $accounttoshowsubledger == 'NotDefined') - { - print ''.$langs->trans("WaitAccountNotDefined").''; - } - else print length_accountg($conf->global->ACCOUNTING_ACCOUNT_SUSPENSE); - */ - print ""; - print "" . $reflabel . ""; - print "" . $val["type_payment"] . ""; - print "" . ($mt < 0 ? price(- $mt) : '') . ""; - print "" . ($mt >= 0 ? price($mt) : '') . ""; - print ""; } } } @@ -1089,6 +1144,13 @@ function getSourceDocRef($val, $typerecord) $sqlmid .= " WHERE s.rowid=" . $val["paymentsalid"]; $ref = $langs->trans("SalaryPayment"); } + elseif ($typerecord == 'sc') + { + $sqlmid = 'SELECT sc.rowid as ref'; + $sqlmid .= " FROM " . MAIN_DB_PREFIX . "paiementcharge as sc"; + $sqlmid .= " WHERE sc.rowid=" . $val["paymentscid"]; + $ref = $langs->trans("SocialContribution"); + } elseif ($typerecord == 'payment_vat') { $sqlmid = 'SELECT v.rowid as ref'; diff --git a/htdocs/adherents/agenda.php b/htdocs/adherents/agenda.php index 61cb960f05c..927bd22f7fa 100644 --- a/htdocs/adherents/agenda.php +++ b/htdocs/adherents/agenda.php @@ -148,10 +148,10 @@ if ($object->id > 0) //print ''; - $morehtmlcenter = ''; + $createbutton = ''; if (! empty($conf->agenda->enabled)) { - $morehtmlcenter.=''.$langs->trans("AddAction").''; + $createbutton.=''.$langs->trans("AddAction").''; } if (! empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read) )) @@ -162,7 +162,7 @@ if ($object->id > 0) if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; - print_barre_liste($langs->trans("ActionsOnMember"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $morehtmlcenter, 0, -1, '', '', '', '', 0, 1, 1); + print_barre_liste($langs->trans("ActionsOnMember"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', 0, -1, '', '', $createbutton, '', 0, 1, 1); // List of all actions $filters=array(); diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index d482322a054..bbac43b5c18 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -70,6 +70,7 @@ complete_substitutions_array($substitutionarrayfortest, $langs); if ($action == 'update' && empty($_POST["cancel"])) { dolibarr_set_const($db, "MAIN_DISABLE_ALL_MAILS", GETPOST("MAIN_DISABLE_ALL_MAILS"),'chaine',0,'',$conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_FORCE_SENDTO", GETPOST("MAIN_MAIL_FORCE_SENDTO"),'chaine',0,'',$conf->entity); // Send mode parameters dolibarr_set_const($db, "MAIN_MAIL_SENDMODE", GETPOST("MAIN_MAIL_SENDMODE"),'chaine',0,'',$conf->entity); dolibarr_set_const($db, "MAIN_MAIL_SMTP_PORT", GETPOST("MAIN_MAIL_SMTP_PORT"),'chaine',0,'',$conf->entity); @@ -239,6 +240,11 @@ if ($action == 'edit') print $form->selectyesno('MAIN_DISABLE_ALL_MAILS',$conf->global->MAIN_DISABLE_ALL_MAILS,1); print ''; + // Force e-mail recipient + print ''.$langs->trans("MAIN_MAIL_FORCE_SENDTO").''; + print ''; + print ''; + // Separator print ' '; @@ -478,6 +484,11 @@ else print ''.$langs->trans("MAIN_DISABLE_ALL_MAILS").''.yn($conf->global->MAIN_DISABLE_ALL_MAILS).''; + // Force e-mail recipient + print ''.$langs->trans("MAIN_MAIL_FORCE_SENDTO").''.$conf->global->MAIN_MAIL_FORCE_SENDTO; + if (! empty($conf->global->MAIN_MAIL_FORCE_SENDTO) && ! isValidEmail($conf->global->MAIN_MAIL_FORCE_SENDTO)) print img_warning($langs->trans("ErrorBadEMail")); + print ''; + // Separator print ' '; @@ -644,25 +655,7 @@ else dol_fiche_end(); - if ($conf->global->MAIN_MAIL_SENDMODE == 'mail' && empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA)) - { - print '
'; - /* - // Warning 1 - if ($linuxlike) - { - $sendmailoption=ini_get('mail.force_extra_parameters'); - if (empty($sendmailoption) || ! preg_match('/ba/',$sendmailoption)) - { - print info_admin($langs->trans("SendmailOptionNotComplete")); - } - }*/ - // Warning 2 - print info_admin($langs->trans("SendmailOptionMayHurtBuggedMTA")); - } - - - // Boutons actions + // Actions button print '
'; print ''.$langs->trans("Modify").''; @@ -689,6 +682,22 @@ else print '
'; + if ($conf->global->MAIN_MAIL_SENDMODE == 'mail' && empty($conf->global->MAIN_FIX_FOR_BUGGED_MTA)) + { + /* + // Warning 1 + if ($linuxlike) + { + $sendmailoption=ini_get('mail.force_extra_parameters'); + if (empty($sendmailoption) || ! preg_match('/ba/',$sendmailoption)) + { + print info_admin($langs->trans("SendmailOptionNotComplete")); + } + }*/ + // Warning 2 + print info_admin($langs->trans("SendmailOptionMayHurtBuggedMTA")); + } + if ($conf->global->MAIN_MAIL_SENDMODE == 'mail' && ! in_array($action, array('testconnect', 'test', 'testhtml'))) { $text = $langs->trans("WarningPHPMail"); diff --git a/htdocs/admin/salaries.php b/htdocs/admin/salaries.php index 85603de2ae5..f5a3624939d 100644 --- a/htdocs/admin/salaries.php +++ b/htdocs/admin/salaries.php @@ -39,8 +39,7 @@ $action = GETPOST('action', 'alpha'); // Other parameters SALARIES_* $list = array ( - 'SALARIES_ACCOUNTING_ACCOUNT_PAYMENT', - 'SALARIES_ACCOUNTING_ACCOUNT_CHARGE' + 'SALARIES_XXX', ); /* @@ -97,7 +96,7 @@ print "\n"; foreach ($list as $key) { - + print ''; diff --git a/htdocs/api/admin/explorer.php b/htdocs/api/admin/explorer.php index a9f13928217..0aecfcd5d7e 100644 --- a/htdocs/api/admin/explorer.php +++ b/htdocs/api/admin/explorer.php @@ -87,7 +87,13 @@ foreach ($modulesdir as $dir) $part = 'compta/facture'; $obj = 'facture'; } - if (empty($conf->$module->enabled)) $enabled=false; + if ($module == 'ficheinter') { + $obj = 'fichinter'; + $part = 'fichinter'; + $module='fichinter'; + } + + if (empty($conf->$module->enabled)) $enabled=false; if ($enabled) { diff --git a/htdocs/api/index.php b/htdocs/api/index.php index 99334880d3a..353b945cfda 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -145,6 +145,7 @@ if (! empty($reg[1]) && $reg[1] == 'explorer' && ($reg[2] == '/swagger.json' || $modulenameforenabled = $module; if ($module == 'propale') { $modulenameforenabled='propal'; } if ($module == 'supplierproposal') { $modulenameforenabled='supplier_proposal'; } + if ($module == 'ficheinter') { $modulenameforenabled='ficheinter'; } dol_syslog("Found module file ".$file." - module=".$module." - modulenameforenabled=".$modulenameforenabled." - moduledirforclass=".$moduledirforclass); @@ -217,7 +218,7 @@ if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/swagger.json' && $moduledirforclass = getModuleDirForApiClass($module); // Load a dedicated API file - dol_syslog("Load a dedicated API file moduledirforclass=".$moduledirforclass); + dol_syslog("Load a dedicated API file module=".$module." moduledirforclass=".$moduledirforclass); $tmpmodule = $module; if ($tmpmodule != 'api') @@ -229,6 +230,11 @@ if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/swagger.json' && $classfile = 'supplier_orders'; if ($module == 'supplierinvoices') $classfile = 'supplier_invoices'; + if ($module == 'ficheinter') + $classfile = 'interventions'; + if ($module == 'interventions') + $classfile = 'interventions'; + $dir_part_file = dol_buildpath('/' . $moduledirforclass . '/class/api_' . $classfile . '.class.php', 0, 2); $classname = ucwords($module); diff --git a/htdocs/blockedlog/admin/blockedlog_list.php b/htdocs/blockedlog/admin/blockedlog_list.php index 08b384d7ac5..d508d1edceb 100644 --- a/htdocs/blockedlog/admin/blockedlog_list.php +++ b/htdocs/blockedlog/admin/blockedlog_list.php @@ -453,24 +453,36 @@ if (is_array($blocks)) if (empty($search_showonlyerrors) || ! $checkresult[$block->id]) { print ''; + // ID print ''.$block->id.''; + // Date print ''.dol_print_date($block->date_creation,'dayhour').''; + // User print ''; + //print $block->getUser() print $block->user_fullname; print ''; + // Action print ''.$langs->trans('log'.$block->action).''; + // Ref print ''.$block->ref_object.''; + // Link to source object print ''.$object_link.''; + + // Amount print ''.price($block->amounts).''; + + // Details link print ''.img_info($langs->trans('ShowDetails')).''; + // Fingerprint print ''; print $form->textwithpicto(dol_trunc($block->signature, '12'), $block->signature, 1, 'help', '', 0, 2, 'fingerprint'); print ''; diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index 2f3c5d60640..3dc3ade52e5 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -149,11 +149,10 @@ class BlockedLog if ($conf->adherent->enabled) $this->trackedevents['MEMBER_SUBSCRIPTION_MODIFY']='logMEMBER_SUBSCRIPTION_MODIFY'; if ($conf->adherent->enabled) $this->trackedevents['MEMBER_SUBSCRIPTION_DELETE']='logMEMBER_SUBSCRIPTION_DELETE'; - /* - $trackedevents['PAYMENT_VARIOUS_CREATE']='BlockedLogVariousPaymentCreate'; - $trackedevents['PAYMENT_VARIOUS_MODIFY']='BlockedLogVariousPaymentModify'; - $trackedevents['PAYMENT_VARIOUS_DELETE']='BlockedLogVariousPaymentDelete'; - */ + + if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_CREATE']='logPAYMENT_VARIOUS_CREATE'; + if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_MODIFY']='logPAYMENT_VARIOUS_MODIFY'; + if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_DELETE']='logPAYMENT_VARIOUS_DELETE'; } /** @@ -218,6 +217,17 @@ class BlockedLog $this->error++; } } + else if($this->element === 'payment_various') { + require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php'; + + $object = new PaymentVarious($this->db); + if ($object->fetch($this->fk_object)>0) { + return $object->getNomUrl(1); + } + else{ + $this->error++; + } + } else if($this->element === 'don' || $this->element === 'donation') { require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php'; @@ -299,7 +309,7 @@ class BlockedLog { $this->date_object = $object->datev; } - elseif ($object->element == 'payment_donation') + elseif ($object->element == 'payment_donation' || $object->element == 'payment_various') { $this->date_object = $object->datepaid?$object->datepaid:$object->datep; } @@ -401,21 +411,26 @@ class BlockedLog if (! empty($object->newref)) $this->object_data->ref = $object->newref; } - elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation') + elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') { $datepayment = $object->datepaye?$object->datepaye:($object->datepaid?$object->datepaid:$object->datep); - $paymenttypeid = $object->paiementid?$object->paiementid:$object->paymenttype; + $paymenttypeid = $object->paiementid?$object->paiementid:($object->paymenttype?$object->paymenttype:$object->type_payment); $this->object_data->ref = $object->ref; $this->object_data->date = $datepayment; $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code'); - $this->object_data->payment_num = $object->num_paiement; + $this->object_data->payment_num = ($object->num_paiement?$object->num_paiement:$object->num_payment); //$this->object_data->fk_account = $object->fk_account; $this->object_data->note = $object->note; //var_dump($this->object_data);exit; $totalamount=0; + if (! is_array($object->amounts) && $object->amount) + { + $object->amounts=array($object->id => $object->amount); + } + $paymentpartnumber=0; foreach($object->amounts as $objid => $amount) { @@ -439,26 +454,41 @@ class BlockedLog include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php'; $tmpobject = new Don($this->db); } + elseif ($this->element == 'payment_various') + { + include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php'; + $tmpobject = new PaymentVarious($this->db); + } + if (! is_object($tmpobject)) { continue; } $result = $tmpobject->fetch($objid); + if ($result <= 0) { $this->error = $tmpobject->error; $this->errors = $tmpobject->errors; + dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR); return -1; } $paymentpart = new stdClass(); $paymentpart->amount = $amount; - if ($this->element != 'payment_donation') + if (! in_array($this->element, array('payment_donation', 'payment_various'))) { $result = $tmpobject->fetch_thirdparty(); - if ($result <= 0) + if ($result == 0) + { + $this->error='Failed to fetch thirdparty for object with id '.$tmpobject->id; + $this->errors[] = $this->error; + dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR); + return -1; + } + elseif ($result < 0) { $this->error = $tmpobject->error; $this->errors = $tmpobject->errors; @@ -481,21 +511,25 @@ class BlockedLog if ($this->element == 'payment_donation') $paymentpart->donation = new stdClass(); else $paymentpart->invoice = new stdClass(); - foreach($tmpobject as $key=>$value) + if ($this->element != 'payment_various') { - if (in_array($key, array('fields'))) continue; // Discard some properties - if (! in_array($key, array( - 'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public' - ))) continue; // Discard if not into a dedicated list - if (!is_object($value)) + foreach($tmpobject as $key=>$value) { - if ($this->element == 'payment_donation') $paymentpart->donation->{$key} = $value; - else $paymentpart->invoice->{$key} = $value; + if (in_array($key, array('fields'))) continue; // Discard some properties + if (! in_array($key, array( + 'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public' + ))) continue; // Discard if not into a dedicated list + if (!is_object($value)) + { + if ($this->element == 'payment_donation') $paymentpart->donation->{$key} = $value; + elseif ($this->element == 'payment_various') $paymentpart->various->{$key} = $value; + else $paymentpart->invoice->{$key} = $value; + } } - } - $paymentpartnumber++; - $this->object_data->payment_part[$paymentpartnumber] = $paymentpart; + $paymentpartnumber++; // first payment will be 1 + $this->object_data->payment_part[$paymentpartnumber] = $paymentpart; + } } $this->object_data->amount = $totalamount; diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 87594b2031f..5658460927c 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -825,7 +825,7 @@ class Categorie extends CommonObject $sql = "SELECT c.fk_" . $this->MAP_CAT_FK[$type]; $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_" . $this->MAP_CAT_TABLE[$type] . " as c"; $sql .= ", " . MAIN_DB_PREFIX . $this->MAP_OBJ_TABLE[$type] . " as o"; - $sql .= " WHERE o.entity IN (" . getEntity( $obj->element, 1).")"; + $sql .= " WHERE o.entity IN (" . getEntity( $obj->element).")"; $sql.= " AND c.fk_categorie = ".$this->id; $sql .= " AND c.fk_" . $this->MAP_CAT_FK[$type] . " = o.rowid"; @@ -1066,7 +1066,7 @@ class Categorie extends CommonObject if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= ", t.label as label_trans, t.description as description_trans"; $sql.= " FROM ".MAIN_DB_PREFIX."categorie as c"; if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."categorie_lang as t ON t.fk_category=c.rowid AND t.lang='".$current_lang."'"; - $sql .= " WHERE c.entity IN (" . getEntity( 'category', 1 ) . ")"; + $sql .= " WHERE c.entity IN (" . getEntity( 'category') . ")"; $sql .= " AND c.type = " . $type; dol_syslog(get_class($this)."::get_full_arbo get category list", LOG_DEBUG); @@ -1481,7 +1481,7 @@ class Categorie extends CommonObject $sql = "SELECT ct.fk_categorie, c.label, c.rowid"; $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_" . $this->MAP_CAT_TABLE[$type] . " as ct, " . MAIN_DB_PREFIX . "categorie as c"; $sql .= " WHERE ct.fk_categorie = c.rowid AND ct.fk_" . $this->MAP_CAT_FK[$type] . " = " . (int) $id . " AND c.type = " . $this->MAP_ID[$type]; - $sql .= " AND c.entity IN (" . getEntity( 'category', 1 ) . ")"; + $sql .= " AND c.entity IN (" . getEntity( 'category') . ")"; $res = $this->db->query($sql); if ($res) @@ -1542,7 +1542,7 @@ class Categorie extends CommonObject // Generation requete recherche $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "categorie"; $sql .= " WHERE type = " . $this->MAP_ID[$type]; - $sql .= " AND entity IN (" . getEntity( 'category', 1 ) . ")"; + $sql .= " AND entity IN (" . getEntity( 'category') . ")"; if ($nom) { if (! $exact) diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 985a50df9ec..c7aa1d80800 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -1633,6 +1633,7 @@ class ActionComm extends CommonObject if (empty($conf->global->AGENDA_REMINDER_EMAIL)) { + $langs->load("agenda"); $this->output = $langs->trans('EventRemindersByEmailNotEnabled', $langs->transnoentitiesnoconv("Agenda")); return 0; } diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index fa2af2dc3eb..49f351be4c3 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -773,7 +773,7 @@ if ($object->id > 0) } /* - * Last sendings + * Last shipments */ if (! empty($conf->expedition->enabled) && $user->rights->expedition->lire) { $sendingstatic = new Expedition($db); @@ -1245,7 +1245,7 @@ if ($object->id > 0) print ''; - if (! empty($conf->global->MAIN_REPEATCONTACTONEACHTAB)) + if (! empty($conf->global->MAIN_DUPLICATE_CONTACTS_TAB_ON_CUSTOMER_CARD)) { // List of contacts show_contacts($conf,$langs,$db,$object,$_SERVER["PHP_SELF"].'?socid='.$object->id); diff --git a/htdocs/comm/index.php b/htdocs/comm/index.php index 9edad60f400..c394ef69d8d 100644 --- a/htdocs/comm/index.php +++ b/htdocs/comm/index.php @@ -470,7 +470,7 @@ if (! empty($conf->societe->enabled) && $user->rights->societe->lire) $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.client IN (1, 2, 3)"; - $sql.= " AND s.entity IN (".getEntity($companystatic->element, 1).")"; + $sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND s.rowid = $socid"; $sql .= " ORDER BY s.tms DESC"; @@ -534,7 +534,7 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->societe->lire) $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; if (! $user->rights->societe->client->voir && ! $user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.fournisseur = 1"; - $sql.= " AND s.entity IN (".getEntity($companystatic->element, 1).")"; + $sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; if (! $user->rights->societe->client->voir && ! $user->societe_id) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND s.rowid = ".$socid; $sql.= " ORDER BY s.datec DESC"; diff --git a/htdocs/comm/mailing/card.php b/htdocs/comm/mailing/card.php index cedd04c46c1..db19e943b4b 100644 --- a/htdocs/comm/mailing/card.php +++ b/htdocs/comm/mailing/card.php @@ -156,6 +156,7 @@ if (empty($reshook)) $sql = "SELECT mc.rowid, mc.fk_mailing, mc.lastname, mc.firstname, mc.email, mc.other, mc.source_url, mc.source_id, mc.source_type, mc.tag"; $sql .= " FROM ".MAIN_DB_PREFIX."mailing_cibles as mc"; $sql .= " WHERE mc.statut < 1 AND mc.fk_mailing = ".$object->id; + $sql .= " ORDER BY mc.statut DESC"; // first status 0, then status -1 dol_syslog("card.php: select targets", LOG_DEBUG); $resql=$db->query($sql); @@ -840,7 +841,7 @@ else if (! empty($conf->global->MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS)) setEventMessages($langs->trans("MailSendSetupIs3", $conf->global->MAILING_SMTP_SETUP_EMAILS_FOR_QUESTIONS), null, 'warnings'); $_GET["action"]=''; } - else if ($conf->global->MAILING_LIMIT_SENDBYWEB == '-1') + else if ($conf->global->MAILING_LIMIT_SENDBYWEB < 0) { if (! empty($conf->global->MAILING_LIMIT_WARNING_PHPMAIL) && $sendingmode == 'mail') setEventMessages($langs->transnoentitiesnoconv($conf->global->MAILING_LIMIT_WARNING_PHPMAIL), null, 'warnings'); if (! empty($conf->global->MAILING_LIMIT_WARNING_NOPHPMAIL) && $sendingmode != 'mail') setEventMessages($langs->transnoentitiesnoconv($conf->global->MAILING_LIMIT_WARNING_NOPHPMAIL), null, 'warnings'); @@ -875,7 +876,16 @@ else $linkback = ''.$langs->trans("BackToList").''; $morehtmlright=''; - if ($object->statut == 2) $morehtmlright.=' ('.$object->countNbOfTargets('alreadysent').'/'.$object->nbemail.') '; + $nbtry = $nbok = 0; + if ($object->statut == 2 || $object->statut == 3) + { + $nbtry = $object->countNbOfTargets('alreadysent'); + $nbko = $object->countNbOfTargets('alreadysentko'); + + $morehtmlright.=' ('.$nbtry.'/'.$object->nbemail; + if ($nbko) $morehtmlright.=' - '.$nbko.' '.$langs->trans("Error"); + $morehtmlright.=')   '; + } dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', '', '', 0, '', $morehtmlright); @@ -903,11 +913,11 @@ else print ''; print $langs->trans("TotalNbOfDistinctRecipients"); print ''; - $nbemail = ($object->nbemail?$object->nbemail:img_warning('').' '.$langs->trans("NoTargetYet").''); - if ($object->statut != 3 && is_numeric($nbemail)) + $nbemail = ($object->nbemail?$object->nbemail:0); + if (is_numeric($nbemail)) { $text=''; - if (! empty($conf->global->MAILING_LIMIT_SENDBYWEB) && $conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) + if ((! empty($conf->global->MAILING_LIMIT_SENDBYWEB) && $conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) && ($object->statut == 1 || ($object->statut == 2 && $nbtry < $nbemail))) { if ($conf->global->MAILING_LIMIT_SENDBYWEB > 0) { @@ -915,9 +925,10 @@ else } else { - $text.=$langs->trans('NotEnoughPermissions'); + $text.=$langs->trans('SendingFromWebInterfaceIsNotAllowed'); } } + if (empty($nbemail)) $nbemail.=' '.img_warning('').' '.$langs->trans("NoTargetYet").''; if ($text) { print $form->textwithpicto($nbemail,$text,1,'warning'); @@ -1008,7 +1019,11 @@ else if (($object->statut == 1 || $object->statut == 2) && $object->nbemail > 0 && $user->rights->mailing->valider) { - if ($conf->global->MAILING_LIMIT_SENDBYWEB < 0 || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! $user->rights->mailing->mailing_advance->send)) + if ($conf->global->MAILING_LIMIT_SENDBYWEB < 0) + { + print ''.$langs->trans("SendMailing").''; + } + else if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! $user->rights->mailing->mailing_advance->send) { print ''.$langs->trans("SendMailing").''; } @@ -1183,15 +1198,30 @@ else print ''; print $langs->trans("TotalNbOfDistinctRecipients"); print ''; - $nbemail = ($object->nbemail?$object->nbemail:img_warning('').' '.$langs->trans("NoTargetYet").''); - if (!empty($conf->global->MAILING_LIMIT_SENDBYWEB) && is_numeric($nbemail) && $conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) + $nbemail = ($object->nbemail?$object->nbemail:0); + if (is_numeric($nbemail)) { - $text=$langs->trans('LimitSendingEmailing',$conf->global->MAILING_LIMIT_SENDBYWEB); - print $form->textwithpicto($nbemail,$text,1,'warning'); - } - else - { - print $nbemail; + $text=''; + if ((! empty($conf->global->MAILING_LIMIT_SENDBYWEB) && $conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) && ($object->statut == 1 || $object->statut == 2)) + { + if ($conf->global->MAILING_LIMIT_SENDBYWEB > 0) + { + $text.=$langs->trans('LimitSendingEmailing',$conf->global->MAILING_LIMIT_SENDBYWEB); + } + else + { + $text.=$langs->trans('SendingFromWebInterfaceIsNotAllowed'); + } + } + if (empty($nbemail)) $nbemail.=' '.img_warning('').' '.$langs->trans("NoTargetYet").''; + if ($text) + { + print $form->textwithpicto($nbemail,$text,1,'warning'); + } + else + { + print $nbemail; + } } print ''; diff --git a/htdocs/comm/mailing/cibles.php b/htdocs/comm/mailing/cibles.php index 7729c2737cc..57af9f5c601 100644 --- a/htdocs/comm/mailing/cibles.php +++ b/htdocs/comm/mailing/cibles.php @@ -171,6 +171,7 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', /* * View */ + llxHeader('',$langs->trans("Mailing"),'EN:Module_EMailing|FR:Module_Mailing|ES:Módulo_Mailing'); $form = new Form($db); @@ -185,7 +186,16 @@ if ($object->fetch($id) >= 0) $linkback = ''.$langs->trans("BackToList").''; $morehtmlright=''; - if ($object->statut == 2) $morehtmlright.=' ('.$object->countNbOfTargets('alreadysent').'/'.$object->nbemail.') '; + $nbtry = $nbok = 0; + if ($object->statut == 2 || $object->statut == 3) + { + $nbtry = $object->countNbOfTargets('alreadysent'); + $nbko = $object->countNbOfTargets('alreadysentko'); + + $morehtmlright.=' ('.$nbtry.'/'.$object->nbemail; + if ($nbko) $morehtmlright.=' - '.$nbko.' '.$langs->trans("Error"); + $morehtmlright.=')   '; + } dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', '', '', 0, '', $morehtmlright); @@ -206,15 +216,30 @@ if ($object->fetch($id) >= 0) print ''; print $langs->trans("TotalNbOfDistinctRecipients"); print ''; - $nbemail = ($object->nbemail?$object->nbemail:'0'); - if (!empty($conf->global->MAILING_LIMIT_SENDBYWEB) && ($conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) && ($object->statut == 1 || $object->statut == 2)) + $nbemail = ($object->nbemail?$object->nbemail:0); + if (is_numeric($nbemail)) { - $text=$langs->trans('LimitSendingEmailing',$conf->global->MAILING_LIMIT_SENDBYWEB); - print $form->textwithpicto($nbemail,$text,1,'warning'); - } - else - { - print $nbemail; + $text=''; + if ((! empty($conf->global->MAILING_LIMIT_SENDBYWEB) && $conf->global->MAILING_LIMIT_SENDBYWEB < $nbemail) && ($object->statut == 1 || ($object->statut == 2 && $nbtry < $nbemail))) + { + if ($conf->global->MAILING_LIMIT_SENDBYWEB > 0) + { + $text.=$langs->trans('LimitSendingEmailing',$conf->global->MAILING_LIMIT_SENDBYWEB); + } + else + { + $text.=$langs->trans('SendingFromWebInterfaceIsNotAllowed'); + } + } + if (empty($nbemail)) $nbemail.=' '.img_warning('').' '.$langs->trans("NoTargetYet").''; + if ($text) + { + print $form->textwithpicto($nbemail,$text,1,'warning'); + } + else + { + print $nbemail; + } } print ''; @@ -411,6 +436,8 @@ if ($object->fetch($id) >= 0) $num = $db->num_rows($resql); $param = "&id=".$object->id; + //if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); if ($search_lastname) $param.= "&search_lastname=".urlencode($search_lastname); if ($search_firstname) $param.= "&search_firstname=".urlencode($search_firstname); if ($search_email) $param.= "&search_email=".urlencode($search_email); @@ -552,7 +579,7 @@ if ($object->fetch($id) >= 0) } print ''; - // Statut pour l'email destinataire (Attentioon != statut du mailing) + // Status of recipient sending email (Warning != status of emailing) if ($obj->statut == 0) { print ' '; @@ -563,18 +590,22 @@ if ($object->fetch($id) >= 0) { print ''.$obj->date_envoi.''; print ''; - print $object::libStatutDest($obj->statut,2,$obj->error_text); + print $object::libStatutDest($obj->statut, 2, $obj->error_text); print ''; } // Search Icon print ''; - if ($obj->statut == 0) + if ($obj->statut == 0) // Not sent yet { if ($user->rights->mailing->creer && $allowaddtarget) { - print ''.img_delete($langs->trans("RemoveRecipient")); + print ''.img_delete($langs->trans("RemoveRecipient")).''; } } + /*if ($obj->statut == -1) // Sent with error + { + print ''.$langs->trans("Retry").''; + }*/ print ''; print ''; diff --git a/htdocs/comm/mailing/class/mailing.class.php b/htdocs/comm/mailing/class/mailing.class.php index 72c2b6d4690..63fc0a2caab 100644 --- a/htdocs/comm/mailing/class/mailing.class.php +++ b/htdocs/comm/mailing/class/mailing.class.php @@ -34,7 +34,7 @@ class Mailing extends CommonObject public $element='mailing'; public $table_element='mailing'; public $picto='email'; - + var $titre; var $sujet; var $body; @@ -43,7 +43,7 @@ class Mailing extends CommonObject var $bgimage; var $statut; // Status 0=Draft, 1=Validated, 2=Sent partially, 3=Sent completely - + var $email_from; var $email_replyto; var $email_errorsto; @@ -431,7 +431,7 @@ class Mailing extends CommonObject return -1; } } - + /** * Delete targets emailing * @@ -481,11 +481,11 @@ class Mailing extends CommonObject } } - + /** * Count number of target with status * - * @param string $mode Mode ('alreadysent' = Sent success or error) + * @param string $mode Mode ('alreadysent' = Sent success or error, 'alreadysentok' = Sent success, 'alreadysentko' = Sent error) * @return int Nb of target with status */ function countNbOfTargets($mode) @@ -493,12 +493,14 @@ class Mailing extends CommonObject $sql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."mailing_cibles"; $sql.= " WHERE fk_mailing = ".$this->id; if ($mode == 'alreadysent') $sql.= " AND statut <> 0"; - else + elseif ($mode == 'alreadysentok') $sql.= " AND statut > 0"; + elseif ($mode == 'alreadysentko') $sql.= " AND statut = -1"; + else { $this->error='BadValueForParameterMode'; return -2; } - + $resql=$this->db->query($sql); if ($resql) { @@ -512,10 +514,10 @@ class Mailing extends CommonObject } return 0; } - + /** - * Retourne le libelle du statut d'un mailing (brouillon, validee, ... + * Return label of status of emailing (draft, validated, ...) * * @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long * @return string Label diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index bf0c691084f..8bd9f7ffa98 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -2130,6 +2130,22 @@ if ($action == 'create') print ''; } + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + if ($totalWeight) { + print '' . $langs->trans("CalculatedWeight") . ''; + print ''; + print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND)?$conf->global->MAIN_WEIGHT_DEFAULT_ROUND:-1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT)?$conf->global->MAIN_WEIGHT_DEFAULT_UNIT:'no'); + print ''; + } + if ($totalVolume) { + print '' . $langs->trans("CalculatedVolume") . ''; + print ''; + print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + print ''; + } + // Incoterms if (!empty($conf->incoterm->enabled)) { diff --git a/htdocs/comm/prospect/index.php b/htdocs/comm/prospect/index.php index 0ec6f20ae46..8db5308bf3f 100644 --- a/htdocs/comm/prospect/index.php +++ b/htdocs/comm/prospect/index.php @@ -76,7 +76,7 @@ $sql.= ", ".MAIN_DB_PREFIX."c_stcomm as st "; if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.fk_stcomm = st.id"; $sql.= " AND s.client IN (2, 3)"; -$sql.= " AND s.entity IN (".getEntity($companystatic->element, 1).")"; +$sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; $sql.= " GROUP BY st.id"; $sql.= " ORDER BY st.id"; @@ -96,7 +96,7 @@ if ($resql) while ($i < $num) { $obj = $db->fetch_object($resql); - + print ''; print ''; print img_action($langs->trans("Show"),$obj->id).' '; @@ -140,7 +140,7 @@ if (! empty($conf->propal->enabled) && $user->rights->propale->lire) while ($i < $num) { $obj = $db->fetch_object($resql); - + print ''; print ''.img_object($langs->trans("ShowPropal"),"propal").' '.$obj->ref.''; print ''; @@ -150,7 +150,7 @@ if (! empty($conf->propal->enabled) && $user->rights->propale->lire) $total += $obj->price; } if ($total>0) { - + print ''.$langs->trans("Total")."".price($total).""; } print "
"; @@ -205,7 +205,7 @@ if (! empty($conf->propal->enabled) && $user->rights->propale->lire) while ($i < $num) { $obj = $db->fetch_object($resql); - + print ''; print ''; print img_object($langs->trans("ShowPropal"),"propal").' '.$obj->ref.''; @@ -243,7 +243,7 @@ $sql = "SELECT s.nom as name, s.rowid as socid, s.client, s.canvas"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.fk_stcomm = 1"; -$sql.= " AND s.entity IN (".getEntity($companystatic->element, 1).")"; +$sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; $sql.= " ORDER BY s.tms ASC"; $sql.= $db->plimit(15, 0); @@ -263,7 +263,7 @@ if ($resql) while ($i < $num) { $obj = $db->fetch_object($resql); - + print ''; $companystatic->id=$obj->socid; $companystatic->name=$obj->name; diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index 2d4d138f61a..24ab03c831a 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -2300,12 +2300,15 @@ if ($action == 'create' && $user->rights->commande->creer) $tmparray=$object->getTotalWeightVolume(); $totalWeight=$tmparray['weight']; $totalVolume=$tmparray['volume']; - if ($totalWeight || $totalVolume) + if ($totalWeight) { print ''.$langs->trans("CalculatedWeight").''; print ''; print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND)?$conf->global->MAIN_WEIGHT_DEFAULT_ROUND:-1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT)?$conf->global->MAIN_WEIGHT_DEFAULT_UNIT:'no'); print ''; + } + if ($totalVolume) + { print ''.$langs->trans("CalculatedVolume").''; print ''; print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index e1edde93922..cbd505a41b8 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -153,6 +153,7 @@ class Orders extends DolibarrApi { $num = $db->num_rows($result); $min = min($num, ($limit <= 0 ? $num : $limit)); + $i=0; while ($i < $min) { $obj = $db->fetch_object($result); @@ -276,7 +277,7 @@ class Orders extends DolibarrApi $request_data->product_type, $request_data->rang, $request_data->special_code, - $fk_parent_line, + $request_data->fk_parent_line, $request_data->fk_fournprice, $request_data->pa_ht, $request_data->label, @@ -424,14 +425,6 @@ class Orders extends DolibarrApi if ($this->commande->availability($this->commande->availability_id) < 0) throw new RestException(400, 'Error while updating availability'); } - // update bank account - if(!empty($this->commande->fk_account)) - { - if($this->commande->setBankAccount($this->commande->fk_account) == 0) - { - throw new RestException(400,$this->commande->error); - } - } if ($this->commande->update(DolibarrApiAccess::$user) > 0) { @@ -479,7 +472,7 @@ class Orders extends DolibarrApi /** * Validate an order * - * If you get a bad value for param notrigger check that ou provide this in body + * If you get a bad value for param notrigger check, provide this in body * { * "idwarehouse": 0, * "notrigger": 0 diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 7998a25bd13..65b704693fb 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -3036,6 +3036,8 @@ class Commande extends CommonOrder */ function update(User $user, $notrigger=0) { + global $conf; + $error=0; // Clean parameters @@ -3069,6 +3071,7 @@ class Commande extends CommonOrder $sql.= " fk_projet=".(isset($this->fk_project)?$this->fk_project:"null").","; $sql.= " fk_cond_reglement=".(isset($this->cond_reglement_id)?$this->cond_reglement_id:"null").","; $sql.= " fk_mode_reglement=".(isset($this->mode_reglement_id)?$this->mode_reglement_id:"null").","; + $sql.= " fk_account=".($this->fk_account>0?$this->fk_account:"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.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").","; diff --git a/htdocs/compta/bank/bankentries_list.php b/htdocs/compta/bank/bankentries_list.php index 0493ffef3b0..380392c6805 100644 --- a/htdocs/compta/bank/bankentries_list.php +++ b/htdocs/compta/bank/bankentries_list.php @@ -387,7 +387,7 @@ if ($optioncss != '') $param.='&optioncss='.$optioncss; // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; - +$options = array(); if ($id > 0 || ! empty($ref)) { @@ -398,7 +398,6 @@ if ($id > 0 || ! empty($ref)) // Load bank groups require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/bankcateg.class.php'; $bankcateg = new BankCateg($db); - $options = array(); foreach ($bankcateg->fetchAll() as $bankcategory) { $options[$bankcategory->id] = $bankcategory->label; @@ -531,7 +530,6 @@ dol_syslog('compta/bank/bankentries_list.php', LOG_DEBUG); $resql = $db->query($sql); if ($resql) { - $var=True; $num = $db->num_rows($resql); $arrayofselected=is_array($toselect)?$toselect:array(); @@ -569,14 +567,12 @@ if ($resql) // Form to reconcile if ($user->rights->banque->consolidate && $action == 'reconcile') { -// print ''; -// print ''; -// print '
'; print '
'; print ''.$langs->trans("InputReceiptNumber").': '; print ''; // The only default value is value we just entered print '
'; - if ($options) { + if (is_array($options) && count($options)) + { print $langs->trans("EventualyAddCategory").': '; print Form::selectarray('cat', $options, GETPOST('cat'), 1); } @@ -629,7 +625,6 @@ if ($resql) '; } print '

'; -// print '
'; } // Form to add a transaction with no invoice @@ -663,7 +658,8 @@ if ($resql) print ''; print ''; print ''; - if (is_array($options) && count($options)) { + if (is_array($options) && count($options)) + { print '
'.$langs->trans("Rubrique").': '; print Form::selectarray('cat1', $options, GETPOST('cat1'), 1); } diff --git a/htdocs/compta/bank/class/paymentvarious.class.php b/htdocs/compta/bank/class/paymentvarious.class.php index 5922b3f5aa7..fe56ea99504 100644 --- a/htdocs/compta/bank/class/paymentvarious.class.php +++ b/htdocs/compta/bank/class/paymentvarious.class.php @@ -34,6 +34,8 @@ class PaymentVarious extends CommonObject public $table_element='payment_various'; //!< Name of table without prefix where object is stored public $picto = 'bill'; + var $id; + var $ref; var $tms; var $datep; var $datev; @@ -87,8 +89,7 @@ class PaymentVarious extends CommonObject // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."payment_various SET"; - - $sql.= " tms='".$this->db->idate($this->tms)."',"; + if ($this->tms) $sql.= " tms='".$this->db->idate($this->tms)."',"; $sql.= " datep='".$this->db->idate($this->datep)."',"; $sql.= " datev='".$this->db->idate($this->datev)."',"; $sql.= " sens=".$this->sens.","; @@ -102,7 +103,6 @@ class PaymentVarious extends CommonObject $sql.= " fk_bank=".($this->fk_bank > 0 ? $this->fk_bank:"null").","; $sql.= " fk_user_author=".$this->fk_user_author.","; $sql.= " fk_user_modif=".$this->fk_user_modif; - $sql.= " WHERE rowid=".$this->id; dol_syslog(get_class($this)."::update", LOG_DEBUG); @@ -146,7 +146,6 @@ class PaymentVarious extends CommonObject global $langs; $sql = "SELECT"; $sql.= " v.rowid,"; - $sql.= " v.tms,"; $sql.= " v.datep,"; $sql.= " v.datev,"; @@ -164,7 +163,6 @@ class PaymentVarious extends CommonObject $sql.= " b.fk_account,"; $sql.= " b.fk_type,"; $sql.= " b.rappro"; - $sql.= " FROM ".MAIN_DB_PREFIX."payment_various as v"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON v.fk_bank = b.rowid"; $sql.= " WHERE v.rowid = ".$id; @@ -184,7 +182,7 @@ class PaymentVarious extends CommonObject $this->datev = $this->db->jdate($obj->datev); $this->sens = $obj->sens; $this->amount = $obj->amount; - $this->type_payement = $obj->fk_typepayment; + $this->type_payment = $obj->fk_typepayment; $this->num_payment = $obj->num_payment; $this->label = $obj->label; $this->note = $obj->note; @@ -350,6 +348,7 @@ class PaymentVarious extends CommonObject if ($result) { $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."payment_various"); + $this->ref = $this->id; if ($this->id > 0) { diff --git a/htdocs/compta/bank/various_payment/card.php b/htdocs/compta/bank/various_payment/card.php index 90aa3e5e432..b6649250e64 100644 --- a/htdocs/compta/bank/various_payment/card.php +++ b/htdocs/compta/bank/various_payment/card.php @@ -49,7 +49,7 @@ $sens=GETPOST("sens","int"); $amount=GETPOST("amount"); $paymenttype=GETPOST("paymenttype"); $accountancy_code=GETPOST("accountancy_code","int"); -$projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0); +$projectid = (GETPOST('projectid','int') ? GETPOST('projectid', 'int') : GETPOST('fk_project','int')); // Security check $socid = GETPOST("socid","int"); @@ -96,22 +96,23 @@ if (empty($reshook)) { $error=0; - $datep=dol_mktime(12,0,0, GETPOST("datepmonth"), GETPOST("datepday"), GETPOST("datepyear")); - $datev=dol_mktime(12,0,0, GETPOST("datevmonth"), GETPOST("datevday"), GETPOST("datevyear")); + $datep=dol_mktime(12,0,0, GETPOST("datepmonth",'int'), GETPOST("datepday",'int'), GETPOST("datepyear",'int')); + $datev=dol_mktime(12,0,0, GETPOST("datevmonth",'int'), GETPOST("datevday",'int'), GETPOST("datevyear",'int')); if (empty($datev)) $datev=$datep; - $object->accountid=GETPOST("accountid") > 0 ? GETPOST("accountid","int") : 0; + $object->ref=''; // TODO + $object->accountid=GETPOST("accountid",'int') > 0 ? GETPOST("accountid","int") : 0; $object->datev=$datev; $object->datep=$datep; - $object->amount=price2num(GETPOST("amount")); - $object->label=GETPOST("label"); - $object->note=GETPOST("note"); - $object->type_payment=GETPOST("paymenttype") > 0 ? GETPOST("paymenttype", "int") : 0; - $object->num_payment=GETPOST("num_payment"); + $object->amount=price2num(GETPOST("amount",'alpha')); + $object->label=GETPOST("label",'none'); + $object->note=GETPOST("note",'none'); + $object->type_payment=GETPOST("paymenttype",'int') > 0 ? GETPOST("paymenttype", "int") : 0; + $object->num_payment=GETPOST("num_payment",'alpha'); $object->fk_user_author=$user->id; $object->accountancy_code=GETPOST("accountancy_code") > 0 ? GETPOST("accountancy_code","int") : ""; $object->sens=GETPOST('sens'); - $object->fk_project= GETPOST('fk_project'); + $object->fk_project= GETPOST('fk_project','int'); if (empty($datep) || empty($datev)) { @@ -411,7 +412,7 @@ if ($id) print ''; // Label - print ''; + print ''; // Payment date print ""; diff --git a/htdocs/compta/bank/various_payment/index.php b/htdocs/compta/bank/various_payment/index.php index e32dc8818e2..d52cbeb7595 100644 --- a/htdocs/compta/bank/various_payment/index.php +++ b/htdocs/compta/bank/various_payment/index.php @@ -108,21 +108,19 @@ $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.row $sql.= " WHERE v.entity IN (".getEntity('payment_various').")"; // Search criteria -if ($search_ref) $sql.=" AND v.rowid=".$search_ref; -if ($search_label) $sql.=natural_search(array('v.label'), $search_label); -if ($search_amount_deb) $sql.=natural_search("v.amount", $search_amount_deb, 1); -if ($search_amount_cred) $sql.=natural_search("v.amount", $search_amount_cred, 1); -if ($search_account > 0) $sql.=" AND b.fk_account=".$search_account; -if ($search_date) $sql.=" AND v.datep=".$search_date; -if ($search_accountancy_code) $sql.=" AND v.accountancy_code=".$search_accountancy_code; - +if ($search_ref) $sql.=" AND v.rowid=".$search_ref; +if ($search_label) $sql.=natural_search(array('v.label'), $search_label); +if ($search_amount_deb) $sql.=natural_search("v.amount", $search_amount_deb, 1); +if ($search_amount_cred) $sql.=natural_search("v.amount", $search_amount_cred, 1); +if ($search_account > 0) $sql.=" AND b.fk_account=".$search_account; +if ($search_date) $sql.=" AND v.datep=".$search_date; +if ($search_accountancy_code > 0) $sql.=" AND v.accountancy_code=".$search_accountancy_code; +if ($typeid > 0) $sql .= " AND v.fk_typepayment=".$typeid; if ($filtre) { $filtre=str_replace(":","=",$filtre); $sql .= " AND ".$filtre; } -if ($typeid) { - $sql .= " AND v.fk_typepayment=".$typeid; -} + $sql.= $db->order($sortfield,$sortorder); $totalnboflines=0; @@ -142,10 +140,18 @@ if ($result) $var=true; $param=''; - if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; - if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; - if ($typeid) $param.='&typeid='.$typeid; - if ($optioncss != '') $param.='&optioncss='.$optioncss; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); + if ($search_ref) $param.='&search_ref='.urlencode($search_ref); + if ($search_label) $param.='&search_label='.urlencode($search_label); + if ($typeid > 0) $param.='&typeid='.urlencode($typeid); + if ($search_amount_deb) $param.='&search_amount_deb='.urlencode($search_amount_deb); + if ($search_amount_cred) $param.='&search_amount_cred='.urlencode($search_amount_cred); + if ($search_account > 0) $param.='&search_amount='.urlencode($search_account); + //if ($search_date) $param.='&search_date='.$search_date; + if ($search_accountancy_code > 0) $param.='&search_accountancy_code='.urlencode($search_accountancy_code); + + if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss); print ''; @@ -162,18 +168,6 @@ if ($result) print '
'; print '
'.$langs->trans("Label").''.$object->label.'
'.$langs->trans("Label").''.$object->label.'
'."\n"; - print ''; - print_liste_field_titre("Ref",$_SERVER["PHP_SELF"],"v.rowid","",$param,"",$sortfield,$sortorder); - print_liste_field_titre("Label",$_SERVER["PHP_SELF"],"v.label","",$param,'align="left"',$sortfield,$sortorder); - print_liste_field_titre("DatePayment",$_SERVER["PHP_SELF"],"v.datep","",$param,'align="center"',$sortfield,$sortorder); - print_liste_field_titre("PaymentMode",$_SERVER["PHP_SELF"],"type","",$param,'align="left"',$sortfield,$sortorder); - if (! empty($conf->banque->enabled)) print_liste_field_titre("BankAccount",$_SERVER["PHP_SELF"],"ba.label","",$param,"",$sortfield,$sortorder); - if (! empty($conf->accounting->enabled)) print_liste_field_titre("AccountAccounting",$_SERVER["PHP_SELF"],"v.accountancy_code","",$param,'align="left"',$sortfield,$sortorder); - print_liste_field_titre("Debit",$_SERVER["PHP_SELF"],"v.amount","",$param,'align="right"',$sortfield,$sortorder); - print_liste_field_titre("Credit",$_SERVER["PHP_SELF"],"v.amount","",$param,'align="right"',$sortfield,$sortorder); - print_liste_field_titre('',$_SERVER["PHP_SELF"],"",'','','',$sortfield,$sortorder,'maxwidthsearch '); - print "\n"; - print ''; // Ref @@ -227,6 +221,20 @@ if ($result) print "\n"; + + print ''; + print_liste_field_titre("Ref",$_SERVER["PHP_SELF"],"v.rowid","",$param,"",$sortfield,$sortorder); + print_liste_field_titre("Label",$_SERVER["PHP_SELF"],"v.label","",$param,'align="left"',$sortfield,$sortorder); + print_liste_field_titre("DatePayment",$_SERVER["PHP_SELF"],"v.datep","",$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre("PaymentMode",$_SERVER["PHP_SELF"],"type","",$param,'align="left"',$sortfield,$sortorder); + if (! empty($conf->banque->enabled)) print_liste_field_titre("BankAccount",$_SERVER["PHP_SELF"],"ba.label","",$param,"",$sortfield,$sortorder); + if (! empty($conf->accounting->enabled)) print_liste_field_titre("AccountAccounting",$_SERVER["PHP_SELF"],"v.accountancy_code","",$param,'align="left"',$sortfield,$sortorder); + print_liste_field_titre("Debit",$_SERVER["PHP_SELF"],"v.amount","",$param,'align="right"',$sortfield,$sortorder); + print_liste_field_titre("Credit",$_SERVER["PHP_SELF"],"v.amount","",$param,'align="right"',$sortfield,$sortorder); + print_liste_field_titre('',$_SERVER["PHP_SELF"],"",'','','',$sortfield,$sortorder,'maxwidthsearch '); + print "\n"; + + $totalarray=array(); while ($i < min($num,$limit)) { diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index c299c1d1de5..ca6d2bc8fdd 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -683,7 +683,7 @@ if (empty($reshook)) $i = 0; foreach ($object->lines as $line) { - if ($line->total_ht!=0) + if ($line->product_type < 9 && $line->total_ht != 0) // Remove lines with product_type greater than or equal to 9 { // no need to create discount if amount is null $amount_ht[$line->tva_tx] += $line->total_ht; $amount_tva[$line->tva_tx] += $line->total_tva; @@ -1570,7 +1570,7 @@ if (empty($reshook)) setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors'); $error ++; } - if ($prod_entry_mode == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '') && $price_ht_devise == '') // Unit price can be 0 but not '' + if ($prod_entry_mode == 'free' && empty($idprod) && (($price_ht < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) || $price_ht == '') && $price_ht_devise == '') // Unit price can be 0 but not '' { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors'); $error ++; @@ -3047,10 +3047,10 @@ else if ($id > 0 || ! empty($ref)) } } - // Confirmation de la validation + // Confirmation of validation if ($action == 'valid') { - // on verifie si l'objet est en numerotation provisoire + // we check object has a draft number $objectref = substr($object->ref, 1, 4); if ($objectref == 'PROV') { $savdate = $object->date; diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index e691d497194..c1f8774095a 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -60,30 +60,30 @@ class Invoices extends DolibarrApi * * @throws RestException */ - function get($id) - { + function get($id) + { if(! DolibarrApiAccess::$user->rights->facture->lire) { throw new RestException(401); } - $result = $this->invoice->fetch($id); - if( ! $result ) { - throw new RestException(404, 'Invoice not found'); - } + $result = $this->invoice->fetch($id); + if (! $result) { + throw new RestException(404, 'Invoice not found'); + } - // Get payment details - $this->invoice->totalpaye = $this->invoice->getSommePaiement(); - $this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed(); - $this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed(); - $this->invoice->resteapayer = price2num($this->invoice->total_ttc - $this->invoice->totalpaye - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT'); + // Get payment details + $this->invoice->totalpaye = $this->invoice->getSommePaiement(); + $this->invoice->totalcreditnotes = $this->invoice->getSumCreditNotesUsed(); + $this->invoice->totaldeposits = $this->invoice->getSumDepositsUsed(); + $this->invoice->resteapayer = price2num($this->invoice->total_ttc - $this->invoice->totalpaye - $this->invoice->totalcreditnotes - $this->invoice->totaldeposits, 'MT'); - if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { + if (! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } $this->invoice->fetchObjectLinked(); return $this->_cleanObjectDatas($this->invoice); - } + } /** * List invoices diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 8eed645edc4..35ab14454ef 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1163,9 +1163,9 @@ class Facture extends CommonInvoice $label.= '
' . $langs->trans('AmountHT') . ': ' . price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); if (! empty($this->total_tva)) $label.= '
' . $langs->trans('VAT') . ': ' . price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency); - if (! empty($this->total_tva)) + if (! empty($this->total_localtax1)) $label.= '
' . $langs->trans('LT1') . ': ' . price($this->total_localtax1, 0, $langs, 0, -1, -1, $conf->currency); - if (! empty($this->total_tva)) + if (! empty($this->total_localtax2)) $label.= '
' . $langs->trans('LT2') . ': ' . price($this->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency); if (! empty($this->total_ttc)) $label.= '
' . $langs->trans('AmountTTC') . ': ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency); diff --git a/htdocs/compta/facture/fiche-rec.php b/htdocs/compta/facture/fiche-rec.php index e7eea16f316..af81e797252 100644 --- a/htdocs/compta/facture/fiche-rec.php +++ b/htdocs/compta/facture/fiche-rec.php @@ -1056,7 +1056,7 @@ if ($action == 'create') print ''; - print ''; - print ''; print ''; @@ -1404,7 +1404,7 @@ else // Note private print ''; print ''; diff --git a/htdocs/compta/index.php b/htdocs/compta/index.php index 98b4a95b0e4..c36037940b9 100644 --- a/htdocs/compta/index.php +++ b/htdocs/compta/index.php @@ -140,8 +140,8 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $sql.= ", f.rowid, f.total as total_ht, f.tva as total_tva, f.total_ttc, f.ref_client"; $sql.= ", f.type"; $sql.= ", s.nom as name"; - $sql.= ", s.rowid as socid"; - $sql.= ",s.code_client"; + $sql.= ", s.rowid as socid, s.email"; + $sql.= ", s.code_client, s.code_compta, s.code_fournisseur, s.code_compta_fournisseur"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", sc.fk_soc, sc.fk_user "; $sql.= " FROM ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."societe as s"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; @@ -177,22 +177,28 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) while ($i < $num) { $obj = $db->fetch_object($resql); - print ''; print ''; print ''; @@ -226,8 +232,8 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- { $sql = "SELECT f.ref, f.rowid, f.total_ht, f.total_tva, f.total_ttc, f.type, f.ref_supplier"; $sql.= ", s.nom as name"; - $sql.= ", s.rowid as socid"; - $sql.= ", s.code_fournisseur"; + $sql.= ", s.rowid as socid, s.email"; + $sql.= ", s.code_fournisseur, s.code_compta_fournisseur"; $sql.= " FROM ".MAIN_DB_PREFIX."facture_fourn as f, ".MAIN_DB_PREFIX."societe as s"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.rowid = f.fk_soc AND f.fk_statut = 0"; @@ -256,22 +262,28 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- while ($i < $num) { $obj = $db->fetch_object($resql); - print ''; print ''; print ''; @@ -311,7 +323,7 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $sql.= ", f.date_lim_reglement as datelimite"; $sql.= ", s.nom as name"; $sql.= ", s.rowid as socid"; - $sql.= ", s.code_client"; + $sql.= ", s.code_client, s.code_compta"; $sql.= ", sum(pf.amount) as am"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf on f.rowid=pf.fk_facture"; @@ -325,7 +337,8 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $reshook=$hookmanager->executeHooks('printFieldListWhereCustomerLastModified',$parameters); $sql.=$hookmanager->resPrint; - $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid, s.code_client"; + $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement,"; + $sql.= " s.nom, s.rowid, s.code_client, s.code_compta"; $sql.= " ORDER BY f.tms DESC "; $sql.= $db->plimit($max, 0); @@ -350,19 +363,28 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) { $obj = $db->fetch_object($resql); + $facturestatic->ref=$obj->facnumber; + $facturestatic->id=$obj->rowid; + $facturestatic->total_ht=$obj->total_ht; + $facturestatic->total_tva=$obj->total_tva; + $facturestatic->total_ttc=$obj->total_ttc; + $facturestatic->statut = $obj->fk_statut; + $facturestatic->date_lim_reglement = $db->jdate($obj->datelimite); + $facturestatic->type=$obj->type; + + $thirdpartystatic->id=$obj->socid; + $thirdpartystatic->name=$obj->name; + $thirdpartystatic->client=1; + $thirdpartystatic->code_client = $obj->code_client; + //$thirdpartystatic->code_fournisseur = $obj->code_fournisseur; + $thirdpartystatic->code_compta = $obj->code_compta; + //$thirdpartystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + print ''; print '
'; print $form->textwithpicto($langs->trans('NotePublic'), $htmltext, 1, 'help', '', 0, 2, 'notepublic'); print ''; + print ''; $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); print $doleditor->Create(1); @@ -1067,7 +1067,7 @@ if ($action == 'create') print ''; print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext, 1, 'help', '', 0, 2, 'noteprivate'); print ''; + print ''; $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); print $doleditor->Create(1); // print ' @@ -1396,7 +1396,7 @@ else // Note public print '
'; print $form->editfieldkey($form->textwithpicto($langs->trans('NotePublic'), $htmltext, 1, 'help', '', 0, 2, 'notepublic'), 'note_public', $object->note_public, $object, $user->rights->facture->creer); - print ''; + print ''; print $form->editfieldval($langs->trans("NotePublic"), 'note_public', $object->note_public, $object, $user->rights->facture->creer, 'textarea:'.ROWS_4.':90%', '', null, null, '', 1); print '
'; print $form->editfieldkey($form->textwithpicto($langs->trans("NotePrivate"), $htmltext, 1, 'help', '', 0, 2, 'noteprivate'), 'note_private', $object->note_private, $object, $user->rights->facture->creer); - print ''; + print ''; print $form->editfieldval($langs->trans("NotePrivate"), 'note_private', $object->note_private, $object, $user->rights->facture->creer, 'textarea:'.ROWS_4.':90%', '', null, null, '', 1); print '
'; + $facturestatic->ref=$obj->facnumber; $facturestatic->id=$obj->rowid; - $facturestatic->total_ht=$obj->total_ht; - $facturestatic->total_tva=$obj->total_tva; - $facturestatic->total_ttc=$obj->total_ttc; - $facturestatic->ref_client=$obj->ref_client; + $facturestatic->total_ht=$obj->total_ht; + $facturestatic->total_tva=$obj->total_tva; + $facturestatic->total_ttc=$obj->total_ttc; + $facturestatic->ref_client=$obj->ref_client; $facturestatic->type=$obj->type; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->name; + $companystatic->email=$obj->email; + $companystatic->client = 1; + $companystatic->code_client = $obj->code_client; + $companystatic->code_fournisseur = $obj->code_fournisseur; + $companystatic->code_compta = $obj->code_compta; + $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + + print '
'; print $facturestatic->getNomUrl(1,''); print ''; - $companystatic->id=$obj->socid; - $companystatic->name=$obj->name; - $companystatic->client = 1; - $companystatic->code_client = $obj->code_client; - $companystatic->code_fournisseur = $obj->code_fournisseur; print $companystatic->getNomUrl(1,'',16); print ''.price($obj->total_ttc).'
'; + $facturesupplierstatic->ref=$obj->ref; $facturesupplierstatic->id=$obj->rowid; - $facturesupplierstatic->total_ht=$obj->total_ht; - $facturesupplierstatic->total_tva=$obj->total_tva; - $facturesupplierstatic->total_ttc=$obj->total_ttc; - $facturesupplierstatic->ref_supplier=$obj->ref_supplier; + $facturesupplierstatic->total_ht=$obj->total_ht; + $facturesupplierstatic->total_tva=$obj->total_tva; + $facturesupplierstatic->total_ttc=$obj->total_ttc; + $facturesupplierstatic->ref_supplier=$obj->ref_supplier; $facturesupplierstatic->type=$obj->type; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->name; + $companystatic->email=$obj->email; + $companystatic->fournisseur = 1; + $companystatic->code_client = $obj->code_client; + $companystatic->code_fournisseur = $obj->code_fournisseur; + $companystatic->code_compta = $obj->code_compta; + $companystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + + print '
'; print $facturesupplierstatic->getNomUrl(1,'',16); print ''; - $companystatic->id=$obj->socid; - $companystatic->name=$obj->name; - $companystatic->fournisseur = 1; - $companystatic->code_client = $obj->code_client; - $companystatic->code_fournisseur = $obj->code_fournisseur; print $companystatic->getNomUrl(1,'supplier',16); print ''.price($obj->total_ttc).'
'; print ''; print ''; print ''; print ''; if (! empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) print ''; print ''; @@ -425,7 +442,7 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $sql = "SELECT ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.total_tva, ff.total_ttc, ff.tms, ff.paye"; $sql.= ", s.nom as name"; $sql.= ", s.rowid as socid"; - $sql.= ", s.code_fournisseur"; + $sql.= ", s.code_fournisseur, s.code_compta_fournisseur"; $sql.= ", SUM(pf.amount) as am"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as ff"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf on ff.rowid=pf.fk_facturefourn"; @@ -439,7 +456,8 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $reshook=$hookmanager->executeHooks('printFieldListWhereSupplierLastModified',$parameters); $sql.=$hookmanager->resPrint; - $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.tms, ff.paye, s.nom, s.rowid, s.code_fournisseur"; + $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.tms, ff.paye,"; + $sql.= " s.nom, s.rowid, s.code_fournisseur, s.code_compta_fournisseur"; $sql.= " ORDER BY ff.tms DESC "; $sql.= $db->plimit($max, 0); @@ -463,20 +481,25 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- while ($i < $num) { $obj = $db->fetch_object($resql); - print ''; - print ''; + print ''; if (! empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) print ''; @@ -673,9 +696,9 @@ if (! empty($conf->facture->enabled) && ! empty($conf->commande->enabled) && $us $langs->load("orders"); $sql = "SELECT sum(f.total) as tot_fht, sum(f.total_ttc) as tot_fttc"; - $sql.= ", s.nom as name"; + $sql.= ", s.nom as name, s.email"; $sql.= ", s.rowid as socid"; - $sql.= ", s.code_client"; + $sql.= ", s.code_client, s.code_compta"; $sql.= ", c.rowid, c.ref, c.facture, c.fk_statut, c.total_ht, c.tva as total_tva, c.total_ttc"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; @@ -693,7 +716,7 @@ if (! empty($conf->facture->enabled) && ! empty($conf->commande->enabled) && $us $reshook=$hookmanager->executeHooks('printFieldListWhereCustomerOrderToBill',$parameters); $sql.=$hookmanager->resPrint; - $sql.= " GROUP BY s.nom, s.rowid, s.code_client, c.rowid, c.ref, c.facture, c.fk_statut, c.tva, c.total_ht, c.total_ttc"; + $sql.= " GROUP BY s.nom, s.rowid, s.email, s.code_client, s.code_compta, c.rowid, c.ref, c.facture, c.fk_statut, c.tva, c.total_ht, c.total_ttc"; $resql = $db->query($sql); if ( $resql ) @@ -712,18 +735,28 @@ if (! empty($conf->facture->enabled) && ! empty($conf->commande->enabled) && $us print ''; print ''; print ''; + $tot_ht=$tot_ttc=$tot_tobill=0; $societestatic = new Societe($db); while ($i < $num) { $obj = $db->fetch_object($resql); - print ''; - print ''; + print '
'; - $facturestatic->ref=$obj->facnumber; - $facturestatic->id=$obj->rowid; - $facturestatic->total_ht=$obj->total_ht; - $facturestatic->total_tva=$obj->total_tva; - $facturestatic->total_ttc=$obj->total_ttc; - $facturestatic->statut = $obj->fk_statut; - $facturestatic->date_lim_reglement = $db->jdate($obj->datelimite); - $facturestatic->type=$obj->type; print $facturestatic->getNomUrl(1,''); print ''; @@ -379,12 +401,7 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) print ''; - $thirdpartystatic->id=$obj->socid; - $thirdpartystatic->name=$obj->name; - $thirdpartystatic->client=1; - $thirdpartystatic->code_client = $obj->code_client; - $thirdpartystatic->code_fournisseur = $obj->code_fournisseur; - print $thirdpartystatic->getNomUrl(1,'customer',44); + print $thirdpartystatic->getNomUrl(1,'customer',44); print ''.price($obj->total_ht).''.price($obj->total_ttc).'
'; + $facstatic->ref=$obj->ref; - $facstatic->id = $obj->rowid; - $facstatic->total_ht = $obj->total_ht; - $facstatic->total_tva = $obj->total_tva; - $facstatic->total_ttc = $obj->total_ttc; - print $facstatic->getNomUrl(1,''); - print ''; + $facstatic->id = $obj->rowid; + $facstatic->total_ht = $obj->total_ht; + $facstatic->total_tva = $obj->total_tva; + $facstatic->total_ttc = $obj->total_ttc; + $thirdpartystatic->id=$obj->socid; $thirdpartystatic->name=$obj->name; $thirdpartystatic->fournisseur=1; - $thirdpartystatic->code_client = $obj->code_client; - $thirdpartystatic->code_fournisseur = $obj->code_fournisseur; + //$thirdpartystatic->code_client = $obj->code_client; + $thirdpartystatic->code_fournisseur = $obj->code_fournisseur; + //$thirdpartystatic->code_compta = $obj->code_compta; + $thirdpartystatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + + print '
'; + print $facstatic->getNomUrl(1,''); + print ''; print $thirdpartystatic->getNomUrl(1,'supplier',44); print ''.price($obj->total_ht).''.$langs->trans("ToBill").' 
'; + $societestatic->id=$obj->socid; + $societestatic->name=$obj->name; + $societestatic->email=$obj->email; + $societestatic->client=1; + $societestatic->code_client = $obj->code_client; + //$societestatic->code_fournisseur = $obj->code_fournisseur; + $societestatic->code_compta = $obj->code_compta; + //$societestatic->code_fournisseur = $obj->code_fournisseur; $commandestatic->id=$obj->rowid; $commandestatic->ref=$obj->ref; + print '
'; + print ''; print ''; print ''; if (! empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) print ''; @@ -787,8 +815,8 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $sql = "SELECT f.rowid, f.facnumber, f.fk_statut, f.datef, f.type, f.total as total_ht, f.tva as total_tva, f.total_ttc, f.paye, f.tms"; $sql.= ", f.date_lim_reglement as datelimite"; $sql.= ", s.nom as name"; - $sql.= ", s.rowid as socid"; - $sql.= ", s.code_client"; + $sql.= ", s.rowid as socid, s.email"; + $sql.= ", s.code_client, s.code_compta"; $sql.= ", sum(pf.amount) as am"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf on f.rowid=pf.fk_facture"; @@ -802,7 +830,8 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $reshook=$hookmanager->executeHooks('printFieldListWhereCustomerUnpaid',$parameters); $sql.=$hookmanager->resPrint; - $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.datef, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid, s.code_client"; + $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.datef, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement,"; + $sql.= " s.nom, s.rowid, s.email, s.code_client, s.code_compta"; $sql.= " ORDER BY f.datef ASC, f.facnumber ASC"; $resql = $db->query($sql); @@ -829,19 +858,29 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) { $obj = $db->fetch_object($resql); + $facturestatic->ref=$obj->facnumber; + $facturestatic->id=$obj->rowid; + $facturestatic->total_ht=$obj->total_ht; + $facturestatic->total_tva=$obj->total_tva; + $facturestatic->total_ttc=$obj->total_ttc; + $facturestatic->type=$obj->type; + $facturestatic->statut = $obj->fk_statut; + $facturestatic->date_lim_reglement = $db->jdate($obj->datelimite); + + $societestatic->id=$obj->socid; + $societestatic->name=$obj->name; + $societestatic->email=$obj->email; + $societestatic->client=1; + $societestatic->code_client = $obj->code_client; + $societestatic->code_fournisseur = $obj->code_fournisseur; + $societestatic->code_compta = $obj->code_compta; + $societestatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + print ''; print ''; @@ -1445,8 +1528,11 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= //$userstatic->id=$histo[$key]['userid']; //$userstatic->login=$histo[$key]['login']; //$out.=$userstatic->getLoginUrl(1); - $userstatic->fetch($histo[$key]['userid']); - $out.=$userstatic->getNomUrl(-1); + if ($histo[$key]['userid'] > 0) + { + $userstatic->fetch($histo[$key]['userid']); + $out.=$userstatic->getNomUrl(-1); + } $out.=''; // Type @@ -1598,7 +1684,6 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= function show_subsidiaries($conf,$langs,$db,$object) { global $user; - global $bc; $i=-1; diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 042d1318f77..206d1bb8099 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1706,7 +1706,15 @@ function dol_convert_file($fileinput, $ext='png', $fileoutput='') if (empty($fileoutput)) $fileoutput=$fileinput.".".$ext; $count = $image->getNumberImages(); - $ret = $image->writeImages($fileoutput, true); + + if (! dol_is_file($fileoutput) || is_writeable($fileoutput)) + { + $ret = $image->writeImages($fileoutput, true); + } + else + { + dol_syslog("Warning: Failed to write cache preview file '.$fileoutput.'. Check permission on file/dir", LOG_ERR); + } if ($ret) return $count; else return -3; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 699a8955fe8..a736f3c139a 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -111,7 +111,7 @@ function getDoliDBInstance($type, $host, $user, $pass, $name, $port) * 'commande', 'commande_fournisseur', 'expedition', 'intervention', 'survey', * 'contract', 'tax', 'expensereport', 'holiday', 'multicurrency', 'project', * 'email_template', 'event', 'donation' - * 'c_paiement', ... + * 'c_paiement', 'c_payment_term', ... * @param int $shared 0=Return id of current entity only, * 1=Return id of current entity + shared entities (default) * @param int $forceentity Entity id @@ -550,7 +550,7 @@ function GETPOST($paramname, $check='none', $method=0, $filter=NULL, $options=NU if (! is_array($out) || empty($out)) $out=array(); break; case 'nohtml': - $out=dol_string_nohtmltag($out); + $out=dol_string_nohtmltag($out, 0); break; case 'alphanohtml': // Recommended for search params if (! is_array($out)) diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 8f912f8dc89..3cbef60f5fd 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -995,7 +995,12 @@ function get_next_value($db,$mask,$table,$field,$where='',$objsoc='',$date='',$m else dol_print_error($db); // Check if we must force counter to maskoffset - if (empty($counter) || preg_match('/[^0-9]/i',$counter)) $counter=$maskoffset; + if (empty($counter)) $counter=$maskoffset; + else if (preg_match('/[^0-9]/i',$counter)) + { + $counter=0; + dol_syslog("Error, the last counter found is '".$counter."' so is not a numeric value. We will restart to 1.", LOG_ERR); + } else if ($counter < $maskoffset && empty($conf->global->MAIN_NUMBERING_OFFSET_ONLY_FOR_FIRST)) $counter=$maskoffset; if ($mode == 'last') // We found value for counter = last counter value. Now need to get corresponding ref of invoice. @@ -1503,7 +1508,7 @@ function dol_print_reduction($reduction,$langs) } else { - $string = price($reduction).'%'; + $string = vatrate($reduction,true); } return $string; @@ -2253,6 +2258,9 @@ function getModuleDirForApiClass($module) elseif ($module == 'users') { $moduledirforclass = 'user'; } + elseif ($module == 'ficheinter' || $module == 'interventions') { + $moduledirforclass = 'fichinter'; + } return $moduledirforclass; } diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index 9fac1aa93b0..b9dff516bbd 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -168,23 +168,25 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1600__+MAX_llx_menu__, 'billing', 'supplier_bills', 6__+MAX_llx_menu__, '/fourn/facture/list.php?leftmenu=suppliers_bills', 'BillsSuppliers', 0, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 3, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1601__+MAX_llx_menu__, 'billing', '', 1600__+MAX_llx_menu__, '/fourn/facture/card.php?action=create&leftmenu=suppliers_bills', 'NewBill', 1, 'bills', '$user->rights->fournisseur->facture->creer', '', 2, 0, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1602__+MAX_llx_menu__, 'billing', '', 1600__+MAX_llx_menu__, '/fourn/facture/list.php?leftmenu=suppliers_bills', 'List', 1, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1603__+MAX_llx_menu__, 'billing', '', 1600__+MAX_llx_menu__, '/fourn/facture/paiement.php?leftmenu=suppliers_bills', 'Payments', 1, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 2, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1605__+MAX_llx_menu__, 'billing', '', 1603__+MAX_llx_menu__, '/fourn/facture/rapport.php?leftmenu=suppliers_bills', 'Reporting', 2, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1604__+MAX_llx_menu__, 'billing', '', 1600__+MAX_llx_menu__, '/compta/facture/stats/index.php?leftmenu=customers_bills&mode=supplier', 'Statistics', 1, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 8, __ENTITY__); + +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1603__+MAX_llx_menu__, 'billing', 'suppliers_bills_payment', 1600__+MAX_llx_menu__, '/fourn/facture/paiement.php?leftmenu=suppliers_bills_payment', 'Payments', 1, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 2, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1605__+MAX_llx_menu__, 'billing', 'suppliers_bills_reports', 1603__+MAX_llx_menu__, '/fourn/facture/rapport.php?leftmenu=suppliers_bills_reports', 'Reporting', 2, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->supplier_invoice->enabled', __HANDLER__, 'left', 1604__+MAX_llx_menu__, 'billing', 'customers_bills_stats', 1600__+MAX_llx_menu__, '/compta/facture/stats/index.php?leftmenu=customers_bills_stats&mode=supplier', 'Statistics', 1, 'bills', '$user->rights->fournisseur->facture->lire', '', 2, 8, __ENTITY__); -- Billing - Customer invoice insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1700__+MAX_llx_menu__, 'billing', 'customer_bills', 6__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills', 'BillsCustomers', 0, 'bills', '$user->rights->facture->lire', '', 2, 3, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1701__+MAX_llx_menu__, 'billing', '', 1700__+MAX_llx_menu__, '/compta/facture/card.php?action=create&leftmenu=customers_bills', 'NewBill', 1, 'bills', '$user->rights->facture->creer', '', 2, 3, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1705__+MAX_llx_menu__, 'billing', '', 1700__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills', 'List', 1, 'bills', '$user->rights->facture->lire', '', 2, 4, __ENTITY__); + +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1720__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills_draft&search_status=0', 'BillShortStatusDraft', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1721__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills_notpaid&search_status=1', 'BillShortStatusNotPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 2, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1722__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills_paid&search_status=2', 'BillShortStatusPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 3, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1723__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills_canceled&search_status=3', 'BillShortStatusCanceled', 2, 'bills', '$user->rights->facture->lire', '', 2, 4, __ENTITY__); + insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1702__+MAX_llx_menu__, 'billing', '', 1700__+MAX_llx_menu__, '/compta/facture/invoicetemplate_list.php?leftmenu=customers_bills', 'ListOfTemplates', 1, 'bills', '$user->rights->facture->lire', '', 2, 5, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1720__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=0', 'BillShortStatusDraft', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1721__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=1', 'BillShortStatusNotPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 2, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1722__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=2', 'BillShortStatusPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 3, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1723__+MAX_llx_menu__, 'billing', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=3', 'BillShortStatusCanceled', 2, 'bills', '$user->rights->facture->lire', '', 2, 4, __ENTITY__); - -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1704__+MAX_llx_menu__, 'billing', '', 1700__+MAX_llx_menu__, '/compta/paiement/list.php?leftmenu=customers_bills', 'Payments', 1, 'bills', '$user->rights->facture->lire', '', 2, 6, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1710__+MAX_llx_menu__, 'billing', '', 1704__+MAX_llx_menu__, '/compta/paiement/rapport.php?leftmenu=customers_bills', 'Reportings', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1714__+MAX_llx_menu__, 'billing', '', 1700__+MAX_llx_menu__, '/compta/facture/stats/index.php?leftmenu=customers_bills', 'Statistics', 1, 'bills', '$user->rights->facture->lire', '', 2, 8, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1704__+MAX_llx_menu__, 'billing', 'customers_bills_payment', 1700__+MAX_llx_menu__, '/compta/paiement/list.php?leftmenu=customers_bills_payment', 'Payments', 1, 'bills', '$user->rights->facture->lire', '', 2, 6, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1710__+MAX_llx_menu__, 'billing', 'customers_bills_reports', 1704__+MAX_llx_menu__, '/compta/paiement/rapport.php?leftmenu=customers_bills_reports', 'Reportings', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1714__+MAX_llx_menu__, 'billing', 'customers_bills_stats', 1700__+MAX_llx_menu__, '/compta/facture/stats/index.php?leftmenu=customers_bills_stats', 'Statistics', 1, 'bills', '$user->rights->facture->lire', '', 2, 8, __ENTITY__); -- Billing - Orders to bill insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->commande->enabled', __HANDLER__, 'left', 1900__+MAX_llx_menu__, 'billing', 'orders', 6__+MAX_llx_menu__, '/commande/list.php?leftmenu=orders&viewstatut=3', 'MenuOrdersToBill', 0, 'orders', '$user->rights->commande->lire', '', 0, 3, __ENTITY__); -- Donations diff --git a/htdocs/core/menus/standard/auguria.lib.php b/htdocs/core/menus/standard/auguria.lib.php index 4dae9628c30..b7f2d220868 100644 --- a/htdocs/core/menus/standard/auguria.lib.php +++ b/htdocs/core/menus/standard/auguria.lib.php @@ -169,7 +169,8 @@ function print_start_menu_entry_auguria($idsel,$classname,$showmode) if ($showmode) { print '' . "\n"; diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 2d6178ed79b..d26a31b3cd2 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -131,7 +131,7 @@ if ($nolinesbefore) { if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { $coldisplay=2; ?> - > + global->MAIN_VIEW_LINE_NUMBER)) { print ''; } ?> "; //} - if($conf->categorie->enabled) { + if ($conf->categorie->enabled) { // Categories print '"; } @@ -1464,6 +1464,7 @@ else $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1); $c = new Categorie($db); $cats = $c->containing($object->id,Categorie::TYPE_PRODUCT); + $arrayselected=array(); foreach($cats as $cat) { $arrayselected[] = $cat->id; } diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index b21a6a34046..516c67f1fbe 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -197,7 +197,8 @@ class Products extends DolibarrApi } /** - * Update product + * Update product. + * Price will be updated by this API only if option is set on "One price per product". See other APIs for other price modes. * * @param int $id Id of product to update * @param array $request_data Datas @@ -209,6 +210,8 @@ class Products extends DolibarrApi */ function put($id, $request_data = NULL) { + global $conf; + if(! DolibarrApiAccess::$user->rights->produit->creer) { throw new RestException(401); } @@ -222,15 +225,63 @@ class Products extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } + $oldproduct = dol_clone($this->product, 0); + foreach($request_data as $field => $value) { if ($field == 'id') continue; $this->product->$field = $value; } - if($this->product->update($id, DolibarrApiAccess::$user,1,'update')) - return $this->get ($id); + $result = $this->product->update($id, DolibarrApiAccess::$user, 1, 'update'); - return false; + // If price mode is 1 price per product + if ($result > 0 && ! empty($conf->global->PRODUCT_PRICE_UNIQ)) + { + // We update price only if it was changed + $pricemodified = false; + if ($this->product->price_base_type != $oldproduct->price_base_type) $pricemodified = true; + else + { + if ($this->product->tva_tx != $oldproduct->tva_tx) $pricemodified = true; + if ($this->product->tva_npr != $oldproduct->tva_npr) $pricemodified = true; + if ($this->product->default_vat_code != $oldproduct->default_vat_code) $pricemodified = true; + + if ($this->product->price_base_type == 'TTC') + { + if ($this->product->price_ttc != $oldproduct->price_ttc) $pricemodified = true; + if ($this->product->price_min_ttc != $oldproduct->price_min_ttc) $pricemodified = true; + } + else + { + if ($this->product->price != $oldproduct->price) $pricemodified = true; + if ($this->product->price_min != $oldproduct->price_min) $pricemodified = true; + } + } + + if ($pricemodified) + { + $newvat = $this->product->tva_tx; + $newnpr = $this->product->tva_npr; + $newvatsrccode = $this->product->default_vat_code; + + $newprice = $this->product->price; + $newpricemin = $this->product->price_min; + if ($this->product->price_base_type == 'TTC') + { + $newprice = $this->product->price_ttc; + $newpricemin = $this->product->price_min_ttc; + } + + $result = $this->product->updatePrice($newprice, $this->product->price_base_type, DolibarrApiAccess::$user, $newvat, $newpricemin, 0, $newnpr, 0, 0, array(), $newvatsrccode); + } + } + + if ($result <= 0) + { + throw new RestException(500, "Error updating product", array_merge(array($this->product->error), $this->product->errors)); + } + + return $this->get($id); } /** @@ -431,6 +482,8 @@ class Products extends DolibarrApi unset($object->lastname); unset($object->civility_id); + unset($object->recuperableonly); + return $object; } diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 2b8633ca31f..b5646e37128 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -153,8 +153,8 @@ if (empty($reshook)) $object->socid = GETPOST('socid','int'); $object->description = GETPOST('description','none'); // Do not use 'alpha' here, we want field as it is $object->public = GETPOST('public','alpha'); - $object->opp_amount = price2num(GETPOST('opp_amount')); - $object->budget_amount = price2num(GETPOST('budget_amount')); + $object->opp_amount = price2num(GETPOST('opp_amount','alpha')); + $object->budget_amount = price2num(GETPOST('budget_amount','alpha')); $object->datec = dol_now(); $object->date_start = $date_start; $object->date_end = $date_end; @@ -251,13 +251,14 @@ if (empty($reshook)) $object->ref = GETPOST('ref','alpha'); $object->title = GETPOST('title','none'); // Do not use 'alpha' here, we want field as it is + $object->statut = GETPOST('status','int'); $object->socid = GETPOST('socid','int'); $object->description = GETPOST('description','none'); // Do not use 'alpha' here, we want field as it is $object->public = GETPOST('public','alpha'); $object->date_start = empty($_POST["projectstart"])?'':$date_start; $object->date_end = empty($_POST["projectend"])?'':$date_end; - if (isset($_POST['opp_amount'])) $object->opp_amount = price2num(GETPOST('opp_amount')); - if (isset($_POST['budget_amount'])) $object->budget_amount= price2num(GETPOST('budget_amount')); + if (isset($_POST['opp_amount'])) $object->opp_amount = price2num(GETPOST('opp_amount','alpha')); + if (isset($_POST['budget_amount'])) $object->budget_amount= price2num(GETPOST('budget_amount','alpha')); if (isset($_POST['opp_status'])) $object->opp_status = $opp_status; if (isset($_POST['opp_percent'])) $object->opp_percent = $opp_percent; @@ -737,6 +738,16 @@ elseif ($object->id > 0) print ''; print ''; + // Status + print ''; + // Thirdparty if ($conf->societe->enabled) { @@ -765,9 +776,6 @@ elseif ($object->id > 0) print $form->selectarray('public',$array,$object->public); print ''; - // Status - print ''; - if (! empty($conf->global->PROJECT_USE_OPPORTUNITIES)) { // Opportunity status @@ -781,18 +789,18 @@ elseif ($object->id > 0) print ''; print ''; - // Opportunity probability - print ''; - print ''; - print ''; + // Opportunity probability + print ''; + print ''; + print ''; - // Opportunity amount - print ''; - print ''; - print ''; - } + // Opportunity amount + print ''; + print ''; + print ''; + } // Date start print '
'; print $commandestatic->getNomUrl(1); @@ -741,11 +774,6 @@ if (! empty($conf->facture->enabled) && ! empty($conf->commande->enabled) && $us print ''; - $societestatic->id=$obj->socid; - $societestatic->name=$obj->name; - $societestatic->client=1; - $societestatic->code_client = $obj->code_client; - $societestatic->code_fournisseur = $obj->code_fournisseur; print $societestatic->getNomUrl(1,'customer',44); print ''.price($obj->total_ht).'
'; print ''; print ''; print ''; print ''; print ''; @@ -912,9 +946,9 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $sql = "SELECT ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.total_tva, ff.total_ttc, ff.paye"; $sql.= ", ff.date_lim_reglement"; $sql.= ", s.nom as name"; - $sql.= ", s.rowid as socid"; - $sql.= ", s.code_client"; - $sql.= ", s.code_fournisseur"; + $sql.= ", s.rowid as socid, s.email"; + $sql.= ", s.code_client, s.code_compta"; + $sql.= ", s.code_fournisseur, s.code_compta_fournisseur"; $sql.= ", sum(pf.amount) as am"; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as ff"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf on ff.rowid=pf.fk_facturefourn"; @@ -930,8 +964,8 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $reshook=$hookmanager->executeHooks('printFieldListWhereSupplierUnpaid',$parameters); $sql.=$hookmanager->resPrint; - $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.paye,"; - $sql.= " s.nom, s.rowid, s.code_client, s.code_fournisseur, ff.date_lim_reglement"; + $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.paye, ff.date_lim_reglement,"; + $sql.= " s.nom, s.rowid, s.email, s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur"; $sql.= " ORDER BY ff.date_lim_reglement ASC"; $resql=$db->query($sql); @@ -958,19 +992,25 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- { $obj = $db->fetch_object($resql); - print ''; - $societestatic->id=$obj->socid; - $societestatic->name=$obj->name; - $societestatic->client=0; - $societestatic->code_client = $obj->code_client; - $societestatic->code_fournisseur = $obj->code_fournisseur; print ''; print ''; if (! empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) print ''; diff --git a/htdocs/compta/paiement.php b/htdocs/compta/paiement.php index f2e1352cdbb..11751fe258b 100644 --- a/htdocs/compta/paiement.php +++ b/htdocs/compta/paiement.php @@ -257,7 +257,7 @@ if (empty($reshook)) if (! $error) { - $paiement_id = $paiement->create($user, (GETPOST('closepaidinvoices')=='on'?1:0)); // This include closing invoices + $paiement_id = $paiement->create($user, (GETPOST('closepaidinvoices')=='on'?1:0)); // This include closing invoices and regenerating documents if ($paiement_id < 0) { setEventMessages($paiement->error, $paiement->errors, 'errors'); diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index bbdc6f94dfb..fdcfc89c4e0 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -141,7 +141,7 @@ class Paiement extends CommonObject /** * Create payment of invoices into database. * Use this->amounts to have list of invoices for the payment. - * For payment of a customer invoice, amounts are postive, for payment of credit note, amounts are negative + * For payment of a customer invoice, amounts are positive, for payment of credit note, amounts are negative * * @param User $user Object user * @param int $closepaidinvoices 1=Also close payed invoices to paid, 0=Do nothing more @@ -233,11 +233,12 @@ class Paiement extends CommonObject $resql=$this->db->query($sql); if ($resql) { + $invoice=new Facture($this->db); + $invoice->fetch($facid); + // If we want to closed payed invoices if ($closepaidinvoices) { - $invoice=new Facture($this->db); - $invoice->fetch($facid); $paiement = $invoice->getSommePaiement(); $creditnotes=$invoice->getSumCreditNotesUsed(); $deposits=$invoice->getSumDepositsUsed(); @@ -338,26 +339,25 @@ class Paiement extends CommonObject $error++; } } - } - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - $outputlangs = $langs; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $invoice->thirdparty->default_lang; - if (! empty($newlang)) { - $outputlangs = new Translate("", $conf); - $outputlangs->setDefaultLang($newlang); - } - $ret = $invoice->fetch($id); // Reload to get new records - - $result = $invoice->generateDocument($invoice->modelpdf, $outputlangs); - if ($result < 0) { - setEventMessages($invoice->error, $invoice->errors, 'errors'); - $error++; - } - } } + + // Regenerate documents of invoices + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $invoice->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $ret = $invoice->fetch($facid); // Reload to get new records + $result = $invoice->generateDocument($invoice->modelpdf, $outputlangs); + if ($result < 0) { + setEventMessages($invoice->error, $invoice->errors, 'errors'); + $error++; + } + } } else { @@ -1042,12 +1042,15 @@ class Paiement extends CommonObject * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto * @param string $option Sur quoi pointe le lien * @param string $mode 'withlistofinvoices'=Include list of invoices into tooltip + * @param int $notooltip 1=Disable tooltip * @return string Chaine avec URL */ - function getNomUrl($withpicto=0,$option='',$mode='withlistofinvoices') + function getNomUrl($withpicto=0, $option='', $mode='withlistofinvoices', $notooltip=0) { global $langs; + if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips + $result=''; $label = $langs->trans("ShowPayment").': '.$this->ref; if ($mode == 'withlistofinvoices') @@ -1064,12 +1067,31 @@ class Paiement extends CommonObject } } } - $link = ''; + + $linkclose=''; + if (empty($notooltip)) + { + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label=$langs->trans("ShowMyObject"); + $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"'; + } + else $linkclose = ($morecss?' class="'.$morecss.'"':''); + + $url = DOL_URL_ROOT.'/compta/paiement/card.php?id='.$this->id; + + $linkstart = ''; $linkend=''; - if ($withpicto) $result.=($link.img_object($langs->trans("ShowPayment"), 'payment', 'class="classfortooltip"').$linkend); - if ($withpicto && $withpicto != 2) $result.=' '; - if ($withpicto != 2) $result.=$link.($this->ref?$this->ref:$this->id).$linkend; + $result .= $linkstart; + if ($withpicto) $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1); + if ($withpicto && $withpicto != 2) $result.= $this->ref; + $result .= $linkend; + return $result; } diff --git a/htdocs/compta/tva/class/tva.class.php b/htdocs/compta/tva/class/tva.class.php index ee34124b118..43b525ff230 100644 --- a/htdocs/compta/tva/class/tva.class.php +++ b/htdocs/compta/tva/class/tva.class.php @@ -652,26 +652,47 @@ class Tva extends CommonObject * * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto * @param string $option link option + * @param int $notooltip 1=Disable tooltip * @return string Chaine with URL */ - function getNomUrl($withpicto=0,$option='') + function getNomUrl($withpicto=0, $option='', $notooltip=0) { - global $langs; + global $langs, $conf; + + if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips $result=''; $label=$langs->trans("ShowVatPayment").': '.$this->ref; - $link = ''; - $linkend=''; + $url = DOL_URL_ROOT.'/compta/tva/card.php?id='.$this->id; + + $linkclose=''; + if (empty($notooltip)) + { + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label=$langs->trans("ShowMyObject"); + $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"'; + } + else $linkclose = ($morecss?' class="'.$morecss.'"':''); + + $linkstart = ''; + $linkend =''; $picto='payment'; - if ($withpicto) $result.=($link.img_object($label, $picto, 'class="classfortooltip"').$linkend); - if ($withpicto && $withpicto != 2) $result.=' '; - if ($withpicto != 2) $result.=$link.$this->ref.$linkend; + $result .= $linkstart; + if ($withpicto) $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1); + if ($withpicto != 2) $result.= $this->ref; + $result .= $linkend; + return $result; } - + /** * Return amount of payments already done * diff --git a/htdocs/compta/tva/reglement.php b/htdocs/compta/tva/reglement.php index c411013250f..66099cd63db 100644 --- a/htdocs/compta/tva/reglement.php +++ b/htdocs/compta/tva/reglement.php @@ -97,7 +97,7 @@ $formother=new FormOther($db); $tva_static = new Tva($db); $bankstatic = new Account($db); -$sql = "SELECT t.rowid, t.amount, t.label, t.datev as dv, t.datep as dp, t.fk_typepayment as type, t.num_payment, t.fk_bank, pst.code as payment_code,"; +$sql = "SELECT t.rowid, t.amount, t.label, t.datev, t.datep, t.fk_typepayment as type, t.num_payment, t.fk_bank, pst.code as payment_code,"; $sql.= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number, ba.fk_accountancy_journal, ba.label as blabel"; $sql.= " FROM ".MAIN_DB_PREFIX."tva as t"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pst ON t.fk_typepayment = pst.id AND pst.entity IN (".getEntity('c_paiement').")"; @@ -192,8 +192,8 @@ if ($result) print ''; print_liste_field_titre("Ref",$_SERVER["PHP_SELF"],"t.rowid","",$param,"",$sortfield,$sortorder); print_liste_field_titre("Label",$_SERVER["PHP_SELF"],"t.label","",$param,'align="left"',$sortfield,$sortorder); - print_liste_field_titre("DateValue",$_SERVER["PHP_SELF"],"dv","",$param,'align="center"',$sortfield,$sortorder); - print_liste_field_titre("DatePayment",$_SERVER["PHP_SELF"],"dp","",$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre("DateValue",$_SERVER["PHP_SELF"],"t.datev","",$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre("DatePayment",$_SERVER["PHP_SELF"],"t.datep","",$param,'align="center"',$sortfield,$sortorder); print_liste_field_titre("Type",$_SERVER["PHP_SELF"],"type","",$param,'align="left"',$sortfield,$sortorder); if (! empty($conf->banque->enabled)) print_liste_field_titre("Account",$_SERVER["PHP_SELF"],"ba.label","",$param,"",$sortfield,$sortorder); print_liste_field_titre("PayedByThisPayment",$_SERVER["PHP_SELF"],"t.amount","",$param,'align="right"',$sortfield,$sortorder); @@ -217,10 +217,13 @@ if ($result) $tva_static->id=$obj->rowid; $tva_static->ref=$obj->rowid; + + // Ref print "\n"; - print "\n"; - print '\n"; - print '\n"; + // Label + print "\n"; + print '\n"; + print '\n"; // Type print $type; // Account diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index 1f307b00c69..f616ca728b6 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -42,6 +42,27 @@ class Contact extends CommonObject public $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe public $picto = 'contact'; + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields=array( + 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'index'=>1, 'position'=>1, 'comment'=>'Id'), + 'lastname' =>array('type'=>'varchar(128)', 'label'=>'Name', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1), + 'firstname' =>array('type'=>'varchar(128)', 'label'=>'Firstname', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>11, 'searchall'=>1), + 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20), + 'note_public' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>60), + 'note_private' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>61), + 'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>500), + 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>501), + //'date_valid' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>502), + 'fk_user_creat' =>array('type'=>'integer', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>510), + 'fk_user_modif' =>array('type'=>'integer', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>511), + //'fk_user_valid' =>array('type'=>'integer', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>512), + 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>1, 'position'=>1000), + ); + public $civility_id; // In fact we store civility_code public $civility_code; public $address; @@ -96,9 +117,15 @@ class Contact extends CommonObject public $user_id; public $user_login; + // END MODULEBUILDER PROPERTIES + + public $oldcopy; // To contains a clone of this when we need to save old properties of object + + + /** * Constructor * @@ -131,7 +158,7 @@ class Contact extends CommonObject $sql.= " WHERE sp.fk_soc = s.rowid AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; $clause = "AND"; } - $sql.= ' '.$clause.' sp.entity IN ('.getEntity($this->element, 1).')'; + $sql.= ' '.$clause.' sp.entity IN ('.getEntity($this->element).')'; $sql.= " AND (sp.priv='0' OR (sp.priv='1' AND sp.fk_user_creat=".$user->id."))"; if ($user->societe_id > 0) $sql.=" AND sp.fk_soc = ".$user->societe_id; diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 21324613bdf..0ca4b4d879d 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -3,7 +3,7 @@ * Copyright (C) 2004-2014 Laurent Destailleur * Copyright (C) 2005-2014 Regis Houssin * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2010-2015 Juanjo Menent + * Copyright (C) 2010-2017 Juanjo Menent * Copyright (C) 2013 Christophe Battarel * Copyright (C) 2013-2014 Florian Henry * Copyright (C) 2014-2016 Ferran Marcet @@ -657,43 +657,53 @@ if (empty($reshook)) else if ($action == 'updateline' && $user->rights->contrat->creer && ! GETPOST('cancel','alpha')) { - if (!empty($date_start_update) && !empty($date_end_update) && $date_start_update > $date_end_update) - { - setEventMessages($langs->trans("Error").': '.$langs->trans("DateStartPlanned").' > '.$langs->trans("DateEndPlanned"), null, 'errors'); - $action = 'editline'; - $_GET['rowid'] = GETPOST('elrowid'); - $error++; - } + $error = 0; - if (!$error) { - $objectline = new ContratLigne($db); - if ($objectline->fetch(GETPOST('elrowid'))) - { - $db->begin(); + if (!empty($date_start_update) && !empty($date_end_update) && $date_start_update > $date_end_update) + { + setEventMessages($langs->trans("Error").': '.$langs->trans("DateStartPlanned").' > '.$langs->trans("DateEndPlanned"), null, 'errors'); + $action = 'editline'; + $_GET['rowid'] = GETPOST('elrowid'); + $error++; + } - if ($date_start_real_update == '') $date_start_real_update=$objectline->date_ouverture; - if ($date_end_real_update == '') $date_end_real_update=$objectline->date_cloture; + if (! $error) + { + $objectline = new ContratLigne($db); + if ($objectline->fetch(GETPOST('elrowid')) < 0) + { + setEventMessages($objectline->error, $objectline->errors, 'errors'); + $error++; + } + } - $vat_rate = GETPOST('eltva_tx'); - // Define info_bits - $info_bits = 0; - if (preg_match('/\*/', $vat_rate)) + $db->begin(); + + if (! $error) + { + if ($date_start_real_update == '') $date_start_real_update=$objectline->date_ouverture; + if ($date_end_real_update == '') $date_end_real_update=$objectline->date_cloture; + + $vat_rate = GETPOST('eltva_tx'); + // Define info_bits + $info_bits = 0; + if (preg_match('/\*/', $vat_rate)) $info_bits |= 0x01; // Define vat_rate $vat_rate = str_replace('*', '', $vat_rate); - $localtax1_tx=get_localtax($vat_rate, 1, $object->thirdparty, $mysoc); - $localtax2_tx=get_localtax($vat_rate, 2, $object->thirdparty, $mysoc); + $localtax1_tx=get_localtax($vat_rate, 1, $object->thirdparty, $mysoc); + $localtax2_tx=get_localtax($vat_rate, 2, $object->thirdparty, $mysoc); - $txtva = $vat_rate; + $txtva = $vat_rate; // Clean vat code - $vat_src_code=''; - if (preg_match('/\((.*)\)/', $txtva, $reg)) - { + $vat_src_code=''; + if (preg_match('/\((.*)\)/', $txtva, $reg)) + { $vat_src_code = $reg[1]; $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. - } + } // ajout prix d'achat $fk_fournprice = $_POST['fournprice']; @@ -704,22 +714,22 @@ if (empty($reshook)) $fk_unit = GETPOST('unit', 'alpha'); - $objectline->description=GETPOST('product_desc','none'); - $objectline->price_ht=GETPOST('elprice'); - $objectline->subprice=GETPOST('elprice'); - $objectline->qty=GETPOST('elqty'); - $objectline->remise_percent=GETPOST('elremise_percent'); - $objectline->tva_tx=($txtva?$txtva:0); // Field may be disabled, so we use vat rate 0 - $objectline->vat_src_code=$vat_src_code; - $objectline->localtax1_tx=is_numeric($localtax1_tx)?$localtax1_tx:0; - $objectline->localtax2_tx=is_numeric($localtax2_tx)?$localtax2_tx:0; - $objectline->date_ouverture_prevue=$date_start_update; - $objectline->date_ouverture=$date_start_real_update; - $objectline->date_fin_validite=$date_end_update; - $objectline->date_cloture=$date_end_real_update; - $objectline->fk_user_cloture=$user->id; - $objectline->fk_fournprice=$fk_fournprice; - $objectline->pa_ht=$pa_ht; + $objectline->description=GETPOST('product_desc','none'); + $objectline->price_ht=GETPOST('elprice'); + $objectline->subprice=GETPOST('elprice'); + $objectline->qty=GETPOST('elqty'); + $objectline->remise_percent=GETPOST('elremise_percent'); + $objectline->tva_tx=($txtva?$txtva:0); // Field may be disabled, so we use vat rate 0 + $objectline->vat_src_code=$vat_src_code; + $objectline->localtax1_tx=is_numeric($localtax1_tx)?$localtax1_tx:0; + $objectline->localtax2_tx=is_numeric($localtax2_tx)?$localtax2_tx:0; + $objectline->date_ouverture_prevue=$date_start_update; + $objectline->date_ouverture=$date_start_real_update; + $objectline->date_fin_validite=$date_end_update; + $objectline->date_cloture=$date_end_real_update; + $objectline->fk_user_cloture=$user->id; + $objectline->fk_fournprice=$fk_fournprice; + $objectline->pa_ht=$pa_ht; if ($fk_unit > 0) { $objectline->fk_unit = GETPOST('unit'); @@ -727,30 +737,30 @@ if (empty($reshook)) $objectline->fk_unit = null; } - // Extrafields - $extrafieldsline = new ExtraFields($db); - $extralabelsline = $extrafieldsline->fetch_name_optionals_label($objectline->table_element); - $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline, $predef); - $objectline->array_options=$array_options; + // Extrafields + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($objectline->table_element); + $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline, $predef); + $objectline->array_options=$array_options; - // TODO verifier price_min si fk_product et multiprix + // TODO verifier price_min si fk_product et multiprix - $result=$objectline->update($user); - if ($result > 0) - { - $db->commit(); - } - else - { + $result=$objectline->update($user); + if ($result < 0) + { + $error++; setEventMessages($objectline->error, $objectline->errors, 'errors'); - $db->rollback(); - } - } - else - { - setEventMessages($objectline->error, $objectline->errors, 'errors'); - } - } + } + } + + if (! $error) + { + $db->commit(); + } + else + { + $db->rollback(); + } } else if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->contrat->creer) @@ -771,6 +781,30 @@ if (empty($reshook)) else if ($action == 'confirm_valid' && $confirm == 'yes' && $user->rights->contrat->creer) { $result = $object->validate($user); + + if ($result > 0) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + + $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + } } else if ($action == 'reopen' && $user->rights->contrat->creer) diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index a6d557a0776..fd1019390be 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -1268,26 +1268,14 @@ class Contrat extends CommonObject { if (! $notrigger) { - // Uncomment this and change MYOBJECT to your own tag if you - // want this action calls a trigger. - - //// Call triggers - //$result=$this->call_trigger('MYOBJECT_MODIFY',$user); - //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} - //// End call triggers + // Call triggers + $result=$this->call_trigger('CONTRACT_MODIFY',$user); + if ($result < 0) { $error++; } + // End call triggers } } - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0) // For avoid conflicts if trigger used + if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0) // For avoid conflicts if trigger used { $result=$this->insertExtraFields(); if ($result < 0) @@ -2872,6 +2860,9 @@ class ContratLigne extends CommonObjectLine $this->db->begin(); + $this->oldcopy = new ContratLigne($this->db); + $this->oldcopy->fetch($this->id); + // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET"; $sql.= " fk_contrat=".$this->fk_contrat.","; @@ -2911,22 +2902,14 @@ class ContratLigne extends CommonObjectLine dol_syslog(get_class($this)."::update", LOG_DEBUG); $resql = $this->db->query($sql); - if ($resql) - { - $contrat=new Contrat($this->db); - $contrat->fetch($this->fk_contrat); - $result=$contrat->update_statut($user); - } - else + if (! $resql) { $this->error="Error ".$this->db->lasterror(); $error++; - //return -1; } if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($this->array_options) && count($this->array_options)>0) // For avoid conflicts if trigger used { - $result=$this->insertExtraFields(); if ($result < 0) { @@ -2934,19 +2917,52 @@ class ContratLigne extends CommonObjectLine } } - if (empty($error)) { - if (! $notrigger) + // If we change a planned date (start or end), sync dates for all services + if (! $error && ! empty($conf->global->CONTRACT_SYNC_PLANNED_DATE_OF_SERVICES)) { - // Call trigger - $result=$this->call_trigger('LINECONTRACT_UPDATE',$user); - if ($result < 0) { $error++; $this->db->rollback(); return -1; } - // End call triggers - } + if ($this->date_ouverture_prevue != $this->oldcopy->date_ouverture_prevue) + { + $sql ='UPDATE '.MAIN_DB_PREFIX.'contratdet SET'; + $sql.= " date_ouverture_prevue = ".($this->date_ouverture_prevue!=''?"'".$this->db->idate($this->date_ouverture_prevue)."'":"null"); + $sql.= " WHERE fk_contrat = ".$this->fk_contrat; + + $resql = $this->db->query($sql); + if (! $resql) + { + $error++; + $this->error="Error ".$this->db->lasterror(); + } + } + if ($this->date_fin_validite != $this->oldcopy->date_fin_validite) + { + $sql ='UPDATE '.MAIN_DB_PREFIX.'contratdet SET'; + $sql.= " date_fin_validite = ".($this->date_fin_validite!=''?"'".$this->db->idate($this->date_fin_validite)."'":"null"); + $sql.= " WHERE fk_contrat = ".$this->fk_contrat; + + $resql = $this->db->query($sql); + if (! $resql) + { + $error++; + $this->error="Error ".$this->db->lasterror(); + } + } } - if (empty($error)) { - $this->db->commit(); - return 1; + if (! $error) + { + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINECONTRACT_UPDATE', $user); + if ($result < 0) { $error++; $this->db->rollback(); } + // End call triggers + } + } + + if (! $error) + { + $this->db->commit(); + return 1; } else { $this->db->rollback(); $this->errors[]=$this->error; diff --git a/htdocs/core/actions_changeselectedfields.inc.php b/htdocs/core/actions_changeselectedfields.inc.php index 11884f81224..6d39272f74e 100644 --- a/htdocs/core/actions_changeselectedfields.inc.php +++ b/htdocs/core/actions_changeselectedfields.inc.php @@ -33,14 +33,14 @@ if (GETPOST('formfilteraction') == 'listafterchangingselectedfields') $tabparam=array(); $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; - + if (GETPOST("selectedfields")) $tabparam["MAIN_SELECTEDFIELDS_".$varpage]=GETPOST("selectedfields"); else $tabparam["MAIN_SELECTEDFIELDS_".$varpage]=''; include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; - + $result=dol_set_user_param($db, $conf, $user, $tabparam); - + //$action='list'; //var_dump($tabparam);exit; } diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php index eea69e37c13..962d00ee4b8 100644 --- a/htdocs/core/actions_sendmails.inc.php +++ b/htdocs/core/actions_sendmails.inc.php @@ -106,7 +106,6 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO $subject='';$actionmsg='';$actionmsg2=''; - if (! empty($conf->dolimail->enabled)) $langs->load("dolimail@dolimail"); $langs->load('mails'); if (is_object($object)) @@ -321,6 +320,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO // Feature to push mail sent into Sent folder + /* This code must be now included into the hook mail, method sendMailAfter if (! empty($conf->dolimail->enabled)) { $mailfromid = explode("#", $_POST['frommail'],3); // $_POST['frommail'] = 'aaa#Sent# ' // TODO Use a better way to define Sent dir. @@ -329,7 +329,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO { $mbid = $mailfromid[1]; - /*IMAP Postbox*/ + // IMAP Postbox $mailboxconfig = new IMAP($db); $mailboxconfig->fetch($mbid); if ($mailboxconfig->mailbox_imap_host) $ref=$mailboxconfig->get_ref(); @@ -361,6 +361,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO } } } + */ // Make substitution in email content $substitutionarray=getCommonSubstitutionArray($langs, 0, null, $object); @@ -393,7 +394,8 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO $result=$mailfile->sendfile(); if ($result) { - // FIXME This must be moved into the trigger for action $trigger_name + // Two hooks are available into method $mailfile->sendfile, so dedicated code is no more required + /* if (! empty($conf->dolimail->enabled)) { $mid = (GETPOST('mid','int') ? GETPOST('mid','int') : 0); // Original mail id is set ? @@ -411,7 +413,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO if ($movemail) setEventMessages($langs->trans("MailMovedToImapFolder",$folder), null, 'mesgs'); else setEventMessages($langs->trans("MailMovedToImapFolder_Warning",$folder), null, 'warnings'); } - } + }*/ // Initialisation of datas if (is_object($object)) @@ -446,12 +448,10 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO // This avoid sending mail twice if going out and then back to page $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); setEventMessages($mesg, null, 'mesgs'); - if ($conf->dolimail->enabled) - { - header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.(is_object($object)?$object->id:'').'&'.($paramname2?$paramname2:'mid').'='.$parm2val); - exit; - } - header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.(is_object($object)?$object->id:'')); + + $moreparam=''; + if (isset($paramname2) || isset($paramval2)) $moreparam.= '&'.($paramname2?$paramname2:'mid').'='.$paramval2; + header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.(is_object($object)?$object->id:'').$moreparam); exit; } else diff --git a/htdocs/core/boxes/box_produits.php b/htdocs/core/boxes/box_produits.php index 3ccbc05be24..3261572460e 100644 --- a/htdocs/core/boxes/box_produits.php +++ b/htdocs/core/boxes/box_produits.php @@ -84,7 +84,7 @@ class box_produits extends ModeleBoxes { $sql = "SELECT p.rowid, p.label, p.ref, p.price, p.price_base_type, p.price_ttc, p.fk_product_type, p.tms, p.tosell, p.tobuy, p.fk_price_expression, p.entity"; $sql.= " FROM ".MAIN_DB_PREFIX."product as p"; - $sql.= ' WHERE p.entity IN ('.getEntity($productstatic->element, 1).')'; + $sql.= ' WHERE p.entity IN ('.getEntity($productstatic->element).')'; if (empty($user->rights->produit->lire)) $sql.=' AND p.fk_product_type != 0'; if (empty($user->rights->service->lire)) $sql.=' AND p.fk_product_type != 1'; // Add where from hooks diff --git a/htdocs/core/boxes/box_produits_alerte_stock.php b/htdocs/core/boxes/box_produits_alerte_stock.php index e244d276fac..9dc75612773 100644 --- a/htdocs/core/boxes/box_produits_alerte_stock.php +++ b/htdocs/core/boxes/box_produits_alerte_stock.php @@ -88,7 +88,7 @@ class box_produits_alerte_stock extends ModeleBoxes $sql.= " SUM(".$db->ifsql("s.reel IS NULL","0","s.reel").") as total_stock"; $sql.= " FROM ".MAIN_DB_PREFIX."product as p"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as s on p.rowid = s.fk_product"; - $sql.= ' WHERE p.entity IN ('.getEntity($productstatic->element, 1).')'; + $sql.= ' WHERE p.entity IN ('.getEntity($productstatic->element).')'; $sql.= " AND p.tosell = 1 AND p.seuil_stock_alerte > 0"; if (empty($user->rights->produit->lire)) $sql.=' AND p.fk_product_type != 0'; if (empty($user->rights->service->lire)) $sql.=' AND p.fk_product_type != 1'; diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index d9469c11559..e19892e9a58 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -482,7 +482,7 @@ class CMailFile /** - * Send mail that was prepared by constructor + * Send mail that was prepared by constructor. * * @return boolean True if mail sent, false otherwise */ @@ -495,19 +495,25 @@ class CMailFile $res=false; - if (empty($conf->global->MAIN_DISABLE_ALL_MAILS)) + if (empty($conf->global->MAIN_DISABLE_ALL_MAILS) || !empty($conf->global->MAIN_MAIL_FORCE_SENDTO)) { require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); - $hookmanager->initHooks(array('maildao')); - $reshook = $hookmanager->executeHooks('doactions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks - if (! empty($reshook)) + $hookmanager->initHooks(array('mail')); + + $parameters=array(); $action=''; + $reshook = $hookmanager->executeHooks('sendMail', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) { - $this->error = "Error in hook maildao doactions " . $reshook; + $this->error = "Error in hook maildao sendMail " . $reshook; dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_ERR); return $reshook; } + if ($reshook == 1) // Hook replace standard code + { + return true; + } // Check number of recipient is lower or equal than MAIL_MAX_NB_OF_RECIPIENTS_IN_SAME_EMAIL if (empty($conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL)) $conf->global->MAIL_MAX_NB_OF_RECIPIENTS_TO_IN_SAME_EMAIL=10; @@ -557,6 +563,12 @@ class CMailFile $keyfortls ='MAIN_MAIL_EMAIL_TLS_EMAILING'; $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS_EMAILING'; } + + if(!empty($conf->global->MAIN_MAIL_FORCE_SENDTO)) { + $this->addr_to = $conf->global->MAIN_MAIL_FORCE_SENDTO; + $this->addr_cc = ''; + $this->addr_bcc = ''; + } // Action according to choosed sending method if ($this->sendmode == 'mail') @@ -760,13 +772,21 @@ class CMailFile } else { - // Send mail method not correctly defined // -------------------------------------- return 'Bad value for sendmode'; } + $parameters=array(); $action=''; + $reshook = $hookmanager->executeHooks('sendMailAfter', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) + { + $this->error = "Error in hook maildao sendMailAfter " . $reshook; + dol_syslog("CMailFile::sendfile: mail end error=" . $this->error, LOG_ERR); + + return $reshook; + } } else { diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 43c216de26c..a62c0d671ac 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -14,6 +14,7 @@ * Copyright (C) 2017 ATM Consulting * Copyright (C) 2017 Nicolas ZABOURI * Copyright (C) 2017 Rui Strecht + * Copyright (C) 2018 Frederic France * * 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 @@ -79,7 +80,7 @@ abstract class CommonObject */ public $array_options=array(); /** - * @var int[] Array of linked objects ids. Loaded by ->fetchObjectLinked + * @var int[][] Array of linked objects ids. Loaded by ->fetchObjectLinked */ public $linkedObjectsIds; /** @@ -187,7 +188,7 @@ abstract class CommonObject * @var string * @see getFullAddress() */ - public $country; + public $country; /** * @var int * @see getFullAddress(), country @@ -1315,14 +1316,15 @@ abstract class CommonObject } /** - * Load object from specific field - * - * @param string $table Table element or element line - * @param string $field Field selected - * @param string $key Import key - * @return int <0 if KO, >0 if OK - */ - function fetchObjectFrom($table,$field,$key) + * Load object from specific field + * + * @param string $table Table element or element line + * @param string $field Field selected + * @param string $key Import key + * @param string $element Element name + * @return int <0 if KO, >0 if OK + */ + function fetchObjectFrom($table, $field, $key, $element = null) { global $conf; @@ -1330,7 +1332,11 @@ abstract class CommonObject $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table; $sql.= " WHERE ".$field." = '".$key."'"; - $sql.= " AND entity = ".$conf->entity; + if (! empty($element)) { + $sql.= " AND entity IN (".getEntity($element).")"; + } else { + $sql.= " AND entity = ".$conf->entity; + } dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG); $resql = $this->db->query($sql); @@ -1382,6 +1388,7 @@ abstract class CommonObject * @param User|string $fuser Update the user of last update field with this user. If not provided, current user is used except if value is 'none' * @param string $trigkey Trigger key to run (in most cases something like 'XXX_MODIFY') * @return int <0 if KO, >0 if OK + * @see updateExtraField */ function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='') { @@ -1831,29 +1838,57 @@ abstract class CommonObject * Change the shipping method * * @param int $shipping_method_id Id of shipping method + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @param User $userused Object user + * * @return int 1 if OK, 0 if KO */ - function setShippingMethod($shipping_method_id) + function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null) { + global $user; + + if (empty($userused)) $userused=$user; + + $error = 0; + if (! $this->table_element) { dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR); return -1; } + + $this->db->begin(); + if ($shipping_method_id<0) $shipping_method_id='NULL'; dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')'); $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; $sql.= " SET fk_shipping_method = ".$shipping_method_id; $sql.= " WHERE rowid=".$this->id; - - if ($this->db->query($sql)) { - $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id; - return 1; - } else { + $resql = $this->db->query($sql); + if (! $resql) { dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG); - $this->error=$this->db->error(); - return 0; - } + $this->error = $this->db->lasterror(); + $error++; + } else { + if (!$notrigger) + { + // Call trigger + $this->context=array('shippingmethodupdate'=>1); + $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused); + if ($result < 0) $error++; + // End call trigger + } + } + if ($error) + { + $this->db->rollback(); + return -1; + } else { + $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id; + $this->db->commit(); + return 1; + } + } @@ -1929,14 +1964,24 @@ abstract class CommonObject * Change the bank account * * @param int $fk_account Id of bank account + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @param User $userused Object user * @return int 1 if OK, 0 if KO */ - function setBankAccount($fk_account) + function setBankAccount($fk_account, $notrigger=false, $userused=null) { + global $user; + + if (empty($userused)) $userused=$user; + + $error = 0; + if (! $this->table_element) { dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR); return -1; } + $this->db->begin(); + if ($fk_account<0) $fk_account='NULL'; dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')'); @@ -1944,15 +1989,37 @@ abstract class CommonObject $sql.= " SET fk_account = ".$fk_account; $sql.= " WHERE rowid=".$this->id; - if ($this->db->query($sql)) { - $this->fk_account = ($fk_account=='NULL')?null:$fk_account; - return 1; - } else { - dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error()); - $this->error=$this->db->error(); - return 0; - } - } + $resql = $this->db->query($sql); + if (! $resql) + { + dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error()); + $this->error = $this->db->lasterror(); + $error++; + } + else + { + if (!$notrigger) + { + // Call trigger + $this->context=array('bankaccountupdate'=>1); + $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused); + if ($result < 0) $error++; + // End call trigger + } + } + if ($error) + { + $this->db->rollback(); + return -1; + } + else + { + $this->fk_account = ($fk_account=='NULL')?null:$fk_account; + $this->db->commit(); + return 1; + } + } + // TODO: Move line related operations to CommonObjectLine? @@ -4433,7 +4500,7 @@ abstract class CommonObject * @param array $optionsArray Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters. * @return int <0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded */ - function fetch_optionals($rowid=null,$optionsArray=null) + function fetch_optionals($rowid=null, $optionsArray=null) { if (empty($rowid)) $rowid=$this->id; @@ -4548,8 +4615,9 @@ abstract class CommonObject * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY) * @param User $userused Object user * @return int -1=error, O=did nothing, 1=OK + * @see updateExtraField, setValueFrom */ - function insertExtraFields($trigger='',$userused=null) + function insertExtraFields($trigger='', $userused=null) { global $conf,$langs,$user; @@ -4578,16 +4646,30 @@ abstract class CommonObject foreach($new_array_options as $key => $value) { - $attributeKey = substr($key,8); // Remove 'options_' prefix - $attributeType = $extrafields->attribute_type[$attributeKey]; - $attributeLabel = $extrafields->attribute_label[$attributeKey]; - $attributeParam = $extrafields->attribute_param[$attributeKey]; + $attributeKey = substr($key,8); // Remove 'options_' prefix + $attributeType = $extrafields->attribute_type[$attributeKey]; + $attributeLabel = $extrafields->attribute_label[$attributeKey]; + $attributeParam = $extrafields->attribute_param[$attributeKey]; + $attributeRequired = $extrafields->attribute_required[$attributeKey]; + + if ($attributeRequired) + { + $mandatorypb=false; + if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true; + if ($this->array_options[$key] === '') $mandatorypb=true; + if ($mandatorypb) + { + $this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel); + return -1; + } + } + switch ($attributeType) { case 'int': if (!is_numeric($value) && $value!='') { - $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel); + $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel); return -1; } elseif ($value=='') @@ -4611,23 +4693,27 @@ abstract class CommonObject $new_array_options[$key] = $this->db->idate($this->array_options[$key]); break; case 'link': - $param_list=array_keys($attributeParam ['options']); + $param_list=array_keys($attributeParam['options']); // 0 : ObjectName // 1 : classPath $InfoFieldList = explode(":", $param_list[0]); dol_include_once($InfoFieldList[1]); if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) { - $object = new $InfoFieldList[0]($this->db); - if ($value) + if ($value == '-1') // -1 is key for no defined in combo list of objects { + $new_array_options[$key]=''; + } + elseif ($value) + { + $object = new $InfoFieldList[0]($this->db); if (is_numeric($value)) $res=$object->fetch($value); else $res=$object->fetch('',$value); if ($res > 0) $new_array_options[$key]=$object->id; else { - $this->error="Ref '".$value."' for object '".$object->element."' not found"; + $this->error="Id/Ref '".$value."' for object '".$object->element."' not found"; $this->db->rollback(); return -1; } @@ -4640,6 +4726,7 @@ abstract class CommonObject break; } } + $this->db->begin(); $table_element = $this->table_element; @@ -4684,16 +4771,14 @@ abstract class CommonObject $this->error=$this->db->lasterror(); $error++; } - else + + if (! $error && $trigger) { - if ($trigger) - { - // Call trigger - $this->context=array('extrafieldaddupdate'=>1); - $result=$this->call_trigger($trigger, $userused); - if ($result < 0) $error++; - // End call trigger - } + // Call trigger + $this->context=array('extrafieldaddupdate'=>1); + $result=$this->call_trigger($trigger, $userused); + if ($result < 0) $error++; + // End call trigger } if ($error) @@ -4712,15 +4797,19 @@ abstract class CommonObject /** * Update an exta field value for the current object. - * Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) - * This function delte record with all extrafields and insert them again from the array $this->array_options. + * Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) * - * @param string $key Key of the extrafield - * @return int -1=error, O=did nothing, 1=OK + * @param string $key Key of the extrafield + * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY) + * @param User $userused Object user + * @return int -1=error, O=did nothing, 1=OK + * @see setValueFrom */ - function updateExtraField($key) + function updateExtraField($key, $trigger, $userused) { - global $conf,$langs; + global $conf,$langs,$user; + + if (empty($userused)) $userused=$user; $error=0; @@ -4772,9 +4861,9 @@ abstract class CommonObject // 1 : classPath $InfoFieldList = explode(":", $param_list[0]); dol_include_once($InfoFieldList[1]); - $object = new $InfoFieldList[0]($this->db); if ($value) { + $object = new $InfoFieldList[0]($this->db); $object->fetch(0,$value); $this->array_options["options_".$key]=$object->id; } @@ -4787,7 +4876,21 @@ abstract class CommonObject $resql = $this->db->query($sql); if (! $resql) { + $error++; $this->error=$this->db->lasterror(); + } + + if (! $error && $trigger) + { + // Call trigger + $this->context=array('extrafieldupdate'=>1); + $result=$this->call_trigger($trigger, $userused); + if ($result < 0) $error++; + // End call trigger + } + + if ($error) + { $this->db->rollback(); return -1; } @@ -5891,7 +5994,7 @@ abstract class CommonObject * @param int $dest_id New thirdparty id (the thirdparty that will received element of the other) * @param string[] $tables Tables that need to be changed * @param int $ignoreerrors Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old thirdparty may already exists on new one) - * @return bool + * @return bool True if success, False if error */ public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0) { @@ -6296,12 +6399,14 @@ abstract class CommonObject $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); } + // Create extrafields if (! $error) { $result=$this->insertExtraFields(); if ($result < 0) $error++; } + // Triggers if (! $error && ! $notrigger) { // Call triggers @@ -6363,13 +6468,13 @@ abstract class CommonObject /** * Update object into database * - * @param User $user User that modifies - * @param bool $notrigger false=launch triggers after, true=disable triggers - * @return int <0 if KO, >0 if OK + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK */ public function updateCommon(User $user, $notrigger = false) { - global $langs; + global $conf, $langs; $error = 0; @@ -6417,7 +6522,22 @@ abstract class CommonObject } } - if (! $error && ! $notrigger) { + // Update extrafield + if (! $error) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + + // Triggers + if (! $error && ! $notrigger) + { // Call triggers $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user); if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail @@ -6456,6 +6576,19 @@ abstract class CommonObject } } + if (! $error) + { + $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields"; + $sql.= " WHERE fk_object=" . $this->id; + + $resql = $this->db->query($sql); + if (! $resql) + { + $this->errors[] = $this->db->lasterror(); + $error++; + } + } + if (! $error) { $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id; diff --git a/htdocs/core/class/commonobject.class.php.orig b/htdocs/core/class/commonobject.class.php.orig new file mode 100644 index 00000000000..c5e2115c6cd --- /dev/null +++ b/htdocs/core/class/commonobject.class.php.orig @@ -0,0 +1,6652 @@ + + * Copyright (C) 2005-2013 Regis Houssin + * Copyright (C) 2010-2013 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2010-2015 Juanjo Menent + * Copyright (C) 2012-2013 Christophe Battarel + * Copyright (C) 2011-2014 Philippe Grand + * Copyright (C) 2012-2015 Marcos García + * Copyright (C) 2012-2015 Raphaël Doursenaud + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2015 Alexandre Spangaro + * Copyright (C) 2016 Bahfir abbes + * Copyright (C) 2017 ATM Consulting + * Copyright (C) 2017 Nicolas ZABOURI +<<<<<<< HEAD + * Copyright (C) 2017 Rui Strecht +======= + * Copyright (C) 2018 Frederic France +>>>>>>> develop + * + * 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/core/class/commonobject.class.php + * \ingroup core + * \brief File of parent class of all other business classes (invoices, contracts, proposals, orders, ...) + */ + + +/** + * Parent class of all other business classes (invoices, contracts, proposals, orders, ...) + */ +abstract class CommonObject +{ + /** + * @var DoliDb Database handler (result of a new DoliDB) + */ + public $db; + /** + * @var int The object identifier + */ + public $id; + /** + * @var string Error string + * @see errors + */ + public $error; + /** + * @var string[] Array of error strings + */ + public $errors=array(); + /** + * @var string + */ + public $element; + /** + * @var string + */ + public $table_element; + /** + * @var + */ + public $table_element_line; + /** + * @var string Key value used to track if data is coming from import wizard + */ + public $import_key; + /** + * @var mixed Contains data to manage extrafields + */ + public $array_options=array(); + /** + * @var int[][] Array of linked objects ids. Loaded by ->fetchObjectLinked + */ + public $linkedObjectsIds; + /** + * @var mixed Array of linked objects. Loaded by ->fetchObjectLinked + */ + public $linkedObjects; + /** + * @var Object To store a cloned copy of object before to edit it and keep track of old properties + */ + public $oldcopy; + + /** + * @var string Column name of the ref field. + */ + protected $table_ref_field = ''; + + + + // Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them. + + /** + * @var array Can be used to pass information when only object is provided to method + */ + public $context=array(); + + /** + * @var string Contains canvas name if record is an alternative canvas record + */ + public $canvas; + + /** + * @var Project The related project + * @see fetch_projet() + */ + public $project; + /** + * @var int The related project ID + * @see setProject(), project + */ + public $fk_project; + /** + * @deprecated + * @see project + */ + public $projet; + + /** + * @var Contact a related contact + * @see fetch_contact() + */ + public $contact; + /** + * @var int The related contact ID + * @see fetch_contact() + */ + public $contact_id; + + /** + * @var Societe A related thirdparty + * @see fetch_thirdparty() + */ + public $thirdparty; + + /** + * @var User A related user + * @see fetch_user() + */ + public $user; + + /** + * @var string The type of originating object ('commande', 'facture', ...) + * @see fetch_origin() + */ + public $origin; + /** + * @var int The id of originating object + * @see fetch_origin() + */ + public $origin_id; + + /** + * @var string The object's reference + */ + public $ref; + /** + * @var string The object's previous reference + */ + public $ref_previous; + /** + * @var string The object's next reference + */ + public $ref_next; + /** + * @var string An external reference for the object + */ + public $ref_ext; + + /** + * @var int The object's status + * @see setStatut() + */ + public $statut; + + /** + * @var string + * @see getFullAddress() + */ + public $country; + /** + * @var int + * @see getFullAddress(), country + */ + public $country_id; + /** + * @var string + * @see getFullAddress(), isInEEC(), country + */ + public $country_code; + /** + * @var string + * @see getFullAddress() + */ + public $state; + /** + * @var int + * @see getFullAddress(), state + */ + public $state_id; + /** + * @var string + * @see getFullAddress(), state + */ + public $state_code; + /** + * @var string + * @see getFullAddress(), region + */ + public $region; + /** + * @var string + * @see getFullAddress(), region + */ + public $region_code; + + /** + * @var int + * @see fetch_barcode() + */ + public $barcode_type; + /** + * @var string + * @see fetch_barcode(), barcode_type + */ + public $barcode_type_code; + /** + * @var string + * @see fetch_barcode(), barcode_type + */ + public $barcode_type_label; + /** + * @var string + * @see fetch_barcode(), barcode_type + */ + public $barcode_type_coder; + + /** + * @var int Payment method ID (cheque, cash, ...) + * @see setPaymentMethods() + */ + public $mode_reglement_id; + + /** + * @var int Payment terms ID + * @see setPaymentTerms() + */ + public $cond_reglement_id; + /** + * @var int Payment terms ID + * @deprecated Kept for compatibility + * @see cond_reglement_id; + */ + public $cond_reglement; + + /** + * @var int Delivery address ID + * @deprecated + * @see setDeliveryAddress() + */ + public $fk_delivery_address; + + /** + * @var int Shipping method ID + * @see setShippingMethod() + */ + public $shipping_method_id; + + /** + * @var string + * @see SetDocModel() + */ + public $modelpdf; + + /** + * @var int Bank account ID + * @see SetBankAccount() + */ + public $fk_account; + + /** + * @var string Public note + * @see update_note() + */ + public $note_public; + /** + * @var string Private note + * @see update_note() + */ + public $note_private; + /** + * @deprecated + * @see note_public + */ + public $note; + + /** + * @var float Total amount before taxes + * @see update_price() + */ + public $total_ht; + /** + * @var float Total VAT amount + * @see update_price() + */ + public $total_tva; + /** + * @var float Total local tax 1 amount + * @see update_price() + */ + public $total_localtax1; + /** + * @var float Total local tax 2 amount + * @see update_price() + */ + public $total_localtax2; + /** + * @var float Total amount with taxes + * @see update_price() + */ + public $total_ttc; + + /** + * @var CommonObjectLine[] + */ + public $lines; + + /** + * @var mixed Contains comments + * @see fetchComments() + */ + public $comments=array(); + + /** + * @var int + * @see setIncoterms() + */ + public $fk_incoterms; + /** + * @var string + * @see SetIncoterms() + */ + public $libelle_incoterms; + /** + * @var string + * @see display_incoterms() + */ + public $location_incoterms; + + public $name; + public $lastname; + public $firstname; + public $civility_id; + + + // No constructor as it is an abstract class + + /** + * Check an object id/ref exists + * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch + * + * @param string $element String of element ('product', 'facture', ...) + * @param int $id Id of object + * @param string $ref Ref of object to check + * @param string $ref_ext Ref ext of object to check + * @return int <0 if KO, 0 if OK but not found, >0 if OK and exists + */ + static function isExistingObject($element, $id, $ref='', $ref_ext='') + { + global $db,$conf; + + $sql = "SELECT rowid, ref, ref_ext"; + $sql.= " FROM ".MAIN_DB_PREFIX.$element; + $sql.= " WHERE entity IN (".getEntity($element).")" ; + + if ($id > 0) $sql.= " AND rowid = ".$db->escape($id); + else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'"; + else if ($ref_ext) $sql.= " AND ref_ext = '".$db->escape($ref_ext)."'"; + else { + $error='ErrorWrongParameters'; + dol_print_error(get_class()."::isExistingObject ".$error, LOG_ERR); + return -1; + } + if ($ref || $ref_ext) $sql.= " AND entity = ".$conf->entity; + + dol_syslog(get_class()."::isExistingObject", LOG_DEBUG); + $resql = $db->query($sql); + if ($resql) + { + $num=$db->num_rows($resql); + if ($num > 0) return 1; + else return 0; + } + return -1; + } + + /** + * Method to output saved errors + * + * @return string String with errors + */ + function errorsToString() + { + return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):''); + } + + /** + * Return full name (civility+' '+name+' '+lastname) + * + * @param Translate $langs Language object for translation of civility (used only if option is 1) + * @param int $option 0=No option, 1=Add civility + * @param int $nameorder -1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname, 2=Firstname + * @param int $maxlen Maximum length + * @return string String with full name + */ + function getFullName($langs,$option=0,$nameorder=-1,$maxlen=0) + { + //print "lastname=".$this->lastname." name=".$this->name." nom=".$this->nom."
\n"; + $lastname=$this->lastname; + $firstname=$this->firstname; + if (empty($lastname)) $lastname=(isset($this->lastname)?$this->lastname:(isset($this->name)?$this->name:(isset($this->nom)?$this->nom:(isset($this->societe)?$this->societe:(isset($this->company)?$this->company:''))))); + + $ret=''; + if ($option && $this->civility_id) + { + if ($langs->transnoentitiesnoconv("Civility".$this->civility_id)!="Civility".$this->civility_id) $ret.=$langs->transnoentitiesnoconv("Civility".$this->civility_id).' '; + else $ret.=$this->civility_id.' '; + } + + $ret.=dolGetFirstLastname($firstname, $lastname, $nameorder); + + return dol_trunc($ret,$maxlen); + } + + /** + * Return full address of contact + * + * @param int $withcountry 1=Add country into address string + * @param string $sep Separator to use to build string + * @param int $withregion 1=Add region into address string + * @return string Full address string + */ + function getFullAddress($withcountry=0,$sep="\n",$withregion=0) + { + if ($withcountry && $this->country_id && (empty($this->country_code) || empty($this->country))) + { + require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php'; + $tmparray=getCountry($this->country_id,'all'); + $this->country_code=$tmparray['code']; + $this->country =$tmparray['label']; + } + + if ($withregion && $this->state_id && (empty($this->state_code) || empty($this->state) || empty($this->region) || empty($this->region_cpde))) + { + require_once DOL_DOCUMENT_ROOT .'/core/lib/company.lib.php'; + $tmparray=getState($this->state_id,'all',0,1); + $this->state_code =$tmparray['code']; + $this->state =$tmparray['label']; + $this->region_code =$tmparray['region_code']; + $this->region =$tmparray['region']; + } + + return dol_format_address($this, $withcountry, $sep); + } + + + /** + * Return full address for banner + * + * @param string $htmlkey HTML id to make banner content unique + * @param Object $object Object (thirdparty, thirdparty of contact for contact, null for a member) + * @return string Full address string + */ + function getBannerAddress($htmlkey, $object) + { + global $conf, $langs; + + $countriesusingstate=array('AU','US','IN','GB','ES','UK','TR'); // See also option MAIN_FORCE_STATE_INTO_ADDRESS + + $contactid=0; + $thirdpartyid=0; + if ($this->element == 'societe') + { + $thirdpartyid=$this->id; + } + if ($this->element == 'contact') + { + $contactid=$this->id; + $thirdpartyid=$object->fk_soc; + } + if ($this->element == 'user') + { + $contactid=$this->contact_id; + $thirdpartyid=$object->fk_soc; + } + + $out=''; + + $outdone=0; + $coords = $this->getFullAddress(1,', ',$conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT); + if ($coords) + { + if (! empty($conf->use_javascript_ajax)) + { + $namecoords = $this->getFullName($langs,1).'
'.$coords; + // hideonsmatphone because copyToClipboard call jquery dialog that does not work with jmobile + $out.=''; + $out.=img_picto($langs->trans("Address"), 'object_address.png'); + $out.=' '; + } + $out.=dol_print_address($coords, 'address_'.$htmlkey.'_'.$this->id, $this->element, $this->id, 1, ', '); $outdone++; + $outdone++; + } + + if (! in_array($this->country_code,$countriesusingstate) && empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS) // If MAIN_FORCE_STATE_INTO_ADDRESS is on, state is already returned previously with getFullAddress + && empty($conf->global->SOCIETE_DISABLE_STATE) && $this->state) + { + if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1 && $this->region) { + $out.=($outdone?' - ':'').$this->region.' - '.$this->state; + } + else { + $out.=($outdone?' - ':'').$this->state; + } + $outdone++; + } + + if (! empty($this->phone) || ! empty($this->phone_pro) || ! empty($this->phone_mobile) || ! empty($this->phone_perso) || ! empty($this->fax) || ! empty($this->office_phone) || ! empty($this->user_mobile) || ! empty($this->office_fax)) $out.=($outdone?'
':''); + if (! empty($this->phone) && empty($this->phone_pro)) { // For objects that store pro phone into ->phone + $out.=dol_print_phone($this->phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','phone',$langs->trans("PhonePro")); $outdone++; + } + if (! empty($this->phone_pro)) { + $out.=dol_print_phone($this->phone_pro,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','phone',$langs->trans("PhonePro")); $outdone++; + } + if (! empty($this->phone_mobile)) { + $out.=dol_print_phone($this->phone_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','mobile',$langs->trans("PhoneMobile")); $outdone++; + } + if (! empty($this->phone_perso)) { + $out.=dol_print_phone($this->phone_perso,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','phone',$langs->trans("PhonePerso")); $outdone++; + } + if (! empty($this->office_phone)) { + $out.=dol_print_phone($this->office_phone,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','phone',$langs->trans("PhonePro")); $outdone++; + } + if (! empty($this->user_mobile)) { + $out.=dol_print_phone($this->user_mobile,$this->country_code,$contactid,$thirdpartyid,'AC_TEL',' ','mobile',$langs->trans("PhoneMobile")); $outdone++; + } + if (! empty($this->fax)) { + $out.=dol_print_phone($this->fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX',' ','fax',$langs->trans("Fax")); $outdone++; + } + if (! empty($this->office_fax)) { + $out.=dol_print_phone($this->office_fax,$this->country_code,$contactid,$thirdpartyid,'AC_FAX',' ','fax',$langs->trans("Fax")); $outdone++; + } + + $out.='
'; + $outdone=0; + if (! empty($this->email)) + { + $out.=dol_print_email($this->email,$this->id,$object->id,'AC_EMAIL',0,0,1); + $outdone++; + } + if (! empty($this->url)) + { + $out.=dol_print_url($this->url,'_goout',0,1); + $outdone++; + } + if (! empty($conf->skype->enabled)) + { + $out.='
'; + if ($this->skype) $out.=dol_print_skype($this->skype,$this->id,$object->id,'AC_SKYPE'); + $outdone++; + } + + $out.=''; + + return $out; + } + + /** + * Return the link of last main doc file for direct public download. + * + * @param string $modulepart Module related to document + * @param int $initsharekey Init the share key if it was not yet defined + * @return string Link or empty string if there is no download link + */ + function getLastMainDocLink($modulepart, $initsharekey=0) + { + global $user, $dolibarr_main_url_root; + + if (empty($this->last_main_doc)) + { + return ''; // No known last doc + } + + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + $ecmfile=new EcmFiles($this->db); + $result = $ecmfile->fetch(0, '', $this->last_main_doc); + if ($result < 0) + { + $this->error = $ecmfile->error; + $this->errors = $ecmfile->errors; + return -1; + } + + if (empty($ecmfile->id)) + { + // Add entry into index + if ($initsharekey) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + // TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first + /* + $ecmfile->filepath = $rel_dir; + $ecmfile->filename = $filename; + $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content + $ecmfile->fullpath_orig = ''; + $ecmfile->gen_or_uploaded = 'generated'; + $ecmfile->description = ''; // indexed content + $ecmfile->keyword = ''; // keyword content + $ecmfile->share = getRandomPassword(true); + $result = $ecmfile->create($user); + if ($result < 0) + { + $this->error = $ecmfile->error; + $this->errors = $ecmfile->errors; + } + */ + } + else return ''; + } + elseif (empty($ecmfile->share)) + { + // Add entry into index + if ($initsharekey) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + $ecmfile->share = getRandomPassword(true); + $ecmfile->update($user); + } + else return ''; + } + + // Define $urlwithroot + $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root)); + $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file + //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current + + $forcedownload=0; + + $paramlink=''; + //if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required. + //if (! empty($ecmfile->entity)) $paramlink.='&entity='.$ecmfile->entity; // For sharing with hash (so public files), entity is not required. + //$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash + if (! empty($ecmfile->share)) $paramlink.=($paramlink?'&':'').'hashp='.$ecmfile->share; // Hash for public share + if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1'; + + $fulllink=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:''); + + // Here $ecmfile->share is defined + return $fulllink; + } + + + /** + * Add a link between element $this->element and a contact + * + * @param int $fk_socpeople Id of thirdparty contact (if source = 'external') or id of user (if souce = 'internal') to link + * @param int $type_contact Type of contact (code or id). Must be id or code found into table llx_c_type_contact. For example: SALESREPFOLL + * @param string $source external=Contact extern (llx_socpeople), internal=Contact intern (llx_user) + * @param int $notrigger Disable all triggers + * @return int <0 if KO, >0 if OK + */ + function add_contact($fk_socpeople, $type_contact, $source='external',$notrigger=0) + { + global $user,$langs; + + + dol_syslog(get_class($this)."::add_contact $fk_socpeople, $type_contact, $source, $notrigger"); + + // Check parameters + if ($fk_socpeople <= 0) + { + $langs->load("errors"); + $this->error=$langs->trans("ErrorWrongValueForParameterX","1"); + dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR); + return -1; + } + if (! $type_contact) + { + $langs->load("errors"); + $this->error=$langs->trans("ErrorWrongValueForParameterX","2"); + dol_syslog(get_class($this)."::add_contact ".$this->error,LOG_ERR); + return -2; + } + + $id_type_contact=0; + if (is_numeric($type_contact)) + { + $id_type_contact=$type_contact; + } + else + { + // On recherche id type_contact + $sql = "SELECT tc.rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc"; + $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'"; + $sql.= " AND tc.source='".$this->db->escape($source)."'"; + $sql.= " AND tc.code='".$this->db->escape($type_contact)."' AND tc.active=1"; + //print $sql; + $resql=$this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + if ($obj) $id_type_contact=$obj->rowid; + } + } + + if ($id_type_contact == 0) + { + $this->error='CODE_NOT_VALID_FOR_THIS_ELEMENT'; + dol_syslog("CODE_NOT_VALID_FOR_THIS_ELEMENT"); + return -3; + } + + $datecreate = dol_now(); + + // Socpeople must have already been added by some a trigger, then we have to check it to avoid DB_ERROR_RECORD_ALREADY_EXISTS error + $TListeContacts=$this->liste_contact(-1, $source); + $already_added=false; + if(!empty($TListeContacts)) { + foreach($TListeContacts as $array_contact) { + if($array_contact['status'] == 4 && $array_contact['id'] == $fk_socpeople && $array_contact['fk_c_type_contact'] == $id_type_contact) { + $already_added=true; + break; + } + } + } + + if(!$already_added) { + + $this->db->begin(); + + // Insertion dans la base + $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_contact"; + $sql.= " (element_id, fk_socpeople, datecreate, statut, fk_c_type_contact) "; + $sql.= " VALUES (".$this->id.", ".$fk_socpeople." , " ; + $sql.= "'".$this->db->idate($datecreate)."'"; + $sql.= ", 4, ". $id_type_contact; + $sql.= ")"; + + $resql=$this->db->query($sql); + if ($resql) + { + if (! $notrigger) + { + $result=$this->call_trigger(strtoupper($this->element).'_ADD_CONTACT', $user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + } + + $this->db->commit(); + return 1; + } + else + { + if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $this->error=$this->db->errno(); + $this->db->rollback(); + echo 'err rollback'; + return -2; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + } else return 0; + } + + /** + * Copy contact from one element to current + * + * @param CommonObject $objFrom Source element + * @param string $source Nature of contact ('internal' or 'external') + * @return int >0 if OK, <0 if KO + */ + function copy_linked_contact($objFrom, $source='internal') + { + $contacts = $objFrom->liste_contact(-1, $source); + foreach($contacts as $contact) + { + if ($this->add_contact($contact['id'], $contact['fk_c_type_contact'], $contact['source']) < 0) + { + $this->error=$this->db->lasterror(); + return -1; + } + } + return 1; + } + + /** + * Update a link to contact line + * + * @param int $rowid Id of line contact-element + * @param int $statut New status of link + * @param int $type_contact_id Id of contact type (not modified if 0) + * @param int $fk_socpeople Id of soc_people to update (not modified if 0) + * @return int <0 if KO, >= 0 if OK + */ + function update_contact($rowid, $statut, $type_contact_id=0, $fk_socpeople=0) + { + // Insertion dans la base + $sql = "UPDATE ".MAIN_DB_PREFIX."element_contact set"; + $sql.= " statut = ".$statut; + if ($type_contact_id) $sql.= ", fk_c_type_contact = '".$type_contact_id ."'"; + if ($fk_socpeople) $sql.= ", fk_socpeople = '".$fk_socpeople ."'"; + $sql.= " where rowid = ".$rowid; + $resql=$this->db->query($sql); + if ($resql) + { + return 0; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } + + /** + * Delete a link to contact line + * + * @param int $rowid Id of contact link line to delete + * @param int $notrigger Disable all triggers + * @return int >0 if OK, <0 if KO + */ + function delete_contact($rowid, $notrigger=0) + { + global $user; + + + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact"; + $sql.= " WHERE rowid =".$rowid; + + dol_syslog(get_class($this)."::delete_contact", LOG_DEBUG); + if ($this->db->query($sql)) + { + if (! $notrigger) + { + $result=$this->call_trigger(strtoupper($this->element).'_DELETE_CONTACT', $user); + if ($result < 0) { $this->db->rollback(); return -1; } + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + /** + * Delete all links between an object $this and all its contacts + * + * @param string $source '' or 'internal' or 'external' + * @param string $code Type of contact (code or id) + * @return int >0 if OK, <0 if KO + */ + function delete_linked_contact($source='',$code='') + { + $temp = array(); + $typeContact = $this->liste_type_contact($source,'',0,0,$code); + + foreach($typeContact as $key => $value) + { + array_push($temp,$key); + } + $listId = implode(",", $temp); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact"; + $sql.= " WHERE element_id = ".$this->id; + if ($listId) + $sql.= " AND fk_c_type_contact IN (".$listId.")"; + + dol_syslog(get_class($this)."::delete_linked_contact", LOG_DEBUG); + if ($this->db->query($sql)) + { + return 1; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } + + /** + * Get array of all contacts for an object + * + * @param int $statut Status of links to get (-1=all) + * @param string $source Source of contact: external or thirdparty (llx_socpeople) or internal (llx_user) + * @param int $list 0:Return array contains all properties, 1:Return array contains just id + * @param string $code Filter on this code of contact type ('SHIPPING', 'BILLING', ...) + * @return array Array of contacts + */ + function liste_contact($statut=-1,$source='external',$list=0,$code='') + { + global $langs; + + $tab=array(); + + $sql = "SELECT ec.rowid, ec.statut as statuslink, ec.fk_socpeople as id, ec.fk_c_type_contact"; // This field contains id of llx_socpeople or id of llx_user + if ($source == 'internal') $sql.=", '-1' as socid, t.statut as statuscontact, t.login, t.photo"; + if ($source == 'external' || $source == 'thirdparty') $sql.=", t.fk_soc as socid, t.statut as statuscontact"; + $sql.= ", t.civility as civility, t.lastname as lastname, t.firstname, t.email"; + $sql.= ", tc.source, tc.element, tc.code, tc.libelle"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact tc"; + $sql.= ", ".MAIN_DB_PREFIX."element_contact ec"; + if ($source == 'internal') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."user t on ec.fk_socpeople = t.rowid"; + if ($source == 'external'|| $source == 'thirdparty') $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."socpeople t on ec.fk_socpeople = t.rowid"; + $sql.= " WHERE ec.element_id =".$this->id; + $sql.= " AND ec.fk_c_type_contact=tc.rowid"; + $sql.= " AND tc.element='".$this->db->escape($this->element)."'"; + if ($code) $sql.= " AND tc.code = '".$this->db->escape($code)."'"; + if ($source == 'internal') $sql.= " AND tc.source = 'internal'"; + if ($source == 'external' || $source == 'thirdparty') $sql.= " AND tc.source = 'external'"; + $sql.= " AND tc.active=1"; + if ($statut >= 0) $sql.= " AND ec.statut = '".$statut."'"; + $sql.=" ORDER BY t.lastname ASC"; + + dol_syslog(get_class($this)."::liste_contact", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $num=$this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + if (! $list) + { + $transkey="TypeContact_".$obj->element."_".$obj->source."_".$obj->code; + $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle); + $tab[$i]=array('source'=>$obj->source,'socid'=>$obj->socid,'id'=>$obj->id, + 'nom'=>$obj->lastname, // For backward compatibility + 'civility'=>$obj->civility, 'lastname'=>$obj->lastname, 'firstname'=>$obj->firstname, 'email'=>$obj->email, 'login'=>$obj->login, 'photo'=>$obj->photo, 'statuscontact'=>$obj->statuscontact, + 'rowid'=>$obj->rowid, 'code'=>$obj->code, 'libelle'=>$libelle_type, 'status'=>$obj->statuslink, 'fk_c_type_contact'=>$obj->fk_c_type_contact); + } + else + { + $tab[$i]=$obj->id; + } + + $i++; + } + + return $tab; + } + else + { + $this->error=$this->db->lasterror(); + dol_print_error($this->db); + return -1; + } + } + + + /** + * Update status of a contact linked to object + * + * @param int $rowid Id of link between object and contact + * @return int <0 if KO, >=0 if OK + */ + function swapContactStatus($rowid) + { + $sql = "SELECT ec.datecreate, ec.statut, ec.fk_socpeople, ec.fk_c_type_contact,"; + $sql.= " tc.code, tc.libelle"; + //$sql.= ", s.fk_soc"; + $sql.= " FROM (".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc)"; + //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as s ON ec.fk_socpeople=s.rowid"; // Si contact de type external, alors il est lie a une societe + $sql.= " WHERE ec.rowid =".$rowid; + $sql.= " AND ec.fk_c_type_contact=tc.rowid"; + $sql.= " AND tc.element = '".$this->db->escape($this->element)."'"; + + dol_syslog(get_class($this)."::swapContactStatus", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + $newstatut = ($obj->statut == 4) ? 5 : 4; + $result = $this->update_contact($rowid, $newstatut); + $this->db->free($resql); + return $result; + } + else + { + $this->error=$this->db->error(); + dol_print_error($this->db); + return -1; + } + + } + + /** + * Return array with list of possible values for type of contacts + * + * @param string $source 'internal', 'external' or 'all' + * @param string $order Sort order by : 'position', 'code', 'rowid'... + * @param int $option 0=Return array id->label, 1=Return array code->label + * @param int $activeonly 0=all status of contact, 1=only the active + * @param string $code Type of contact (Example: 'CUSTOMER', 'SERVICE') + * @return array Array list of type of contacts (id->label if option=0, code->label if option=1) + */ + function liste_type_contact($source='internal', $order='position', $option=0, $activeonly=0, $code='') + { + global $langs; + + if (empty($order)) $order='position'; + if ($order == 'position') $order.=',code'; + + $tab = array(); + $sql = "SELECT DISTINCT tc.rowid, tc.code, tc.libelle, tc.position"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_type_contact as tc"; + $sql.= " WHERE tc.element='".$this->db->escape($this->element)."'"; + if ($activeonly == 1) $sql.= " AND tc.active=1"; // only the active types + if (! empty($source) && $source != 'all') $sql.= " AND tc.source='".$this->db->escape($source)."'"; + if (! empty($code)) $sql.= " AND tc.code='".$this->db->escape($code)."'"; + $sql.= $this->db->order($order,'ASC'); + + //print "sql=".$sql; + $resql=$this->db->query($sql); + if ($resql) + { + $num=$this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + $transkey="TypeContact_".$this->element."_".$source."_".$obj->code; + $libelle_type=($langs->trans($transkey)!=$transkey ? $langs->trans($transkey) : $obj->libelle); + if (empty($option)) $tab[$obj->rowid]=$libelle_type; + else $tab[$obj->code]=$libelle_type; + $i++; + } + return $tab; + } + else + { + $this->error=$this->db->lasterror(); + //dol_print_error($this->db); + return null; + } + } + + /** + * Return id of contacts for a source and a contact code. + * Example: contact client de facturation ('external', 'BILLING') + * Example: contact client de livraison ('external', 'SHIPPING') + * Example: contact interne suivi paiement ('internal', 'SALESREPFOLL') + * + * @param string $source 'external' or 'internal' + * @param string $code 'BILLING', 'SHIPPING', 'SALESREPFOLL', ... + * @param int $status limited to a certain status + * @return array List of id for such contacts + */ + function getIdContact($source,$code,$status=0) + { + global $conf; + + $result=array(); + $i=0; + //cas particulier pour les expeditions + if($this->element=='shipping' && $this->origin_id != 0) { + $id=$this->origin_id; + $element='commande'; + } else { + $id=$this->id; + $element=$this->element; + } + + $sql = "SELECT ec.fk_socpeople"; + $sql.= " FROM ".MAIN_DB_PREFIX."element_contact as ec,"; + if ($source == 'internal') $sql.= " ".MAIN_DB_PREFIX."user as c,"; + if ($source == 'external') $sql.= " ".MAIN_DB_PREFIX."socpeople as c,"; + $sql.= " ".MAIN_DB_PREFIX."c_type_contact as tc"; + $sql.= " WHERE ec.element_id = ".$id; + $sql.= " AND ec.fk_socpeople = c.rowid"; + if ($source == 'internal') $sql.= " AND c.entity IN (0,".$conf->entity.")"; + if ($source == 'external') $sql.= " AND c.entity IN (".getEntity('societe').")"; + $sql.= " AND ec.fk_c_type_contact = tc.rowid"; + $sql.= " AND tc.element = '".$element."'"; + $sql.= " AND tc.source = '".$source."'"; + $sql.= " AND tc.code = '".$code."'"; + $sql.= " AND tc.active = 1"; + if ($status) $sql.= " AND ec.statut = ".$status; + + dol_syslog(get_class($this)."::getIdContact", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $result[$i]=$obj->fk_socpeople; + $i++; + } + } + else + { + $this->error=$this->db->error(); + return null; + } + + return $result; + } + + /** + * Load object contact with id=$this->contactid into $this->contact + * + * @param int $contactid Id du contact. Use this->contactid if empty. + * @return int <0 if KO, >0 if OK + */ + function fetch_contact($contactid=null) + { + if (empty($contactid)) $contactid=$this->contactid; + + if (empty($contactid)) return 0; + + require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; + $contact = new Contact($this->db); + $result=$contact->fetch($contactid); + $this->contact = $contact; + return $result; + } + + /** + * Load the third party of object, from id $this->socid or $this->fk_soc, into this->thirdparty + * + * @param int $force_thirdparty_id Force thirdparty id + * @return int <0 if KO, >0 if OK + */ + function fetch_thirdparty($force_thirdparty_id=0) + { + global $conf; + + if (empty($this->socid) && empty($this->fk_soc) && empty($this->fk_thirdparty) && empty($force_thirdparty_id)) + return 0; + + require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; + + $idtofetch = isset($this->socid) ? $this->socid : (isset($this->fk_soc) ? $this->fk_soc : $this->fk_thirdparty); + if ($force_thirdparty_id) + $idtofetch = $force_thirdparty_id; + + if ($idtofetch) { + $thirdparty = new Societe($this->db); + $result = $thirdparty->fetch($idtofetch); + $this->thirdparty = $thirdparty; + + // Use first price level if level not defined for third party + if (!empty($conf->global->PRODUIT_MULTIPRICES) && empty($this->thirdparty->price_level)) { + $this->thirdparty->price_level = 1; + } + + return $result; + } else + return -1; + } + + + /** + * Looks for an object with ref matching the wildcard provided + * It does only work when $this->table_ref_field is set + * + * @param string $ref Wildcard + * @return int >1 = OK, 0 = Not found or table_ref_field not defined, <0 = KO + */ + public function fetchOneLike($ref) + { + if (!$this->table_ref_field) { + return 0; + } + + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE '.$this->table_ref_field.' LIKE "'.$this->db->escape($ref).'" LIMIT 1'; + + $query = $this->db->query($sql); + + if (!$this->db->num_rows($query)) { + return 0; + } + + $result = $this->db->fetch_object($query); + + return $this->fetch($result->rowid); + } + + /** + * Load data for barcode into properties ->barcode_type* + * Properties ->barcode_type that is id of barcode. Type is used to find other properties, but + * if it is not defined, ->element must be defined to know default barcode type. + * + * @return int <0 if KO, 0 if can't guess type of barcode (ISBN, EAN13...), >0 if OK (all barcode properties loaded) + */ + function fetch_barcode() + { + global $conf; + + dol_syslog(get_class($this).'::fetch_barcode this->element='.$this->element.' this->barcode_type='.$this->barcode_type); + + $idtype=$this->barcode_type; + if (empty($idtype) && $idtype != '0') // If type of barcode no set, we try to guess. If set to '0' it means we forced to have type remain not defined + { + if ($this->element == 'product') $idtype = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE; + else if ($this->element == 'societe') $idtype = $conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY; + else dol_syslog('Call fetch_barcode with barcode_type not defined and cant be guessed', LOG_WARNING); + } + + if ($idtype > 0) + { + if (empty($this->barcode_type) || empty($this->barcode_type_code) || empty($this->barcode_type_label) || empty($this->barcode_type_coder)) // If data not already loaded + { + $sql = "SELECT rowid, code, libelle as label, coder"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_barcode_type"; + $sql.= " WHERE rowid = ".$idtype; + dol_syslog(get_class($this).'::fetch_barcode', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + $this->barcode_type = $obj->rowid; + $this->barcode_type_code = $obj->code; + $this->barcode_type_label = $obj->label; + $this->barcode_type_coder = $obj->coder; + return 1; + } + else + { + dol_print_error($this->db); + return -1; + } + } + } + return 0; + } + + /** + * Charge le projet d'id $this->fk_project dans this->projet + * + * @return int <0 if KO, >=0 if OK + */ + function fetch_projet() + { + include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + + if (empty($this->fk_project) && ! empty($this->fk_projet)) $this->fk_project = $this->fk_projet; // For backward compatibility + if (empty($this->fk_project)) return 0; + + $project = new Project($this->db); + $result = $project->fetch($this->fk_project); + + $this->projet = $project; // deprecated + $this->project = $project; + return $result; + } + + /** + * Charge le user d'id userid dans this->user + * + * @param int $userid Id du contact + * @return int <0 if KO, >0 if OK + */ + function fetch_user($userid) + { + $user = new User($this->db); + $result=$user->fetch($userid); + $this->user = $user; + return $result; + } + + /** + * Read linked origin object + * + * @return void + */ + function fetch_origin() + { + if ($this->origin == 'shipping') $this->origin = 'expedition'; + if ($this->origin == 'delivery') $this->origin = 'livraison'; + + $origin = $this->origin; + + $classname = ucfirst($origin); + $this->$origin = new $classname($this->db); + $this->$origin->fetch($this->origin_id); + } + + /** + * Load object from specific field + * + * @param string $table Table element or element line + * @param string $field Field selected + * @param string $key Import key + * @param string $element Element name + * @return int <0 if KO, >0 if OK + */ + function fetchObjectFrom($table, $field, $key, $element = null) + { + global $conf; + + $result=false; + + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$table; + $sql.= " WHERE ".$field." = '".$key."'"; + if (! empty($element)) { + $sql.= " AND entity IN (".getEntity($element).")"; + } else { + $sql.= " AND entity = ".$conf->entity; + } + + dol_syslog(get_class($this).'::fetchObjectFrom', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + $result = $this->fetch($row[0]); + } + + return $result; + } + + /** + * Getter generic. Load value from a specific field + * + * @param string $table Table of element or element line + * @param int $id Element id + * @param string $field Field selected + * @return int <0 if KO, >0 if OK + */ + function getValueFrom($table, $id, $field) + { + $result=false; + if (!empty($id) && !empty($field) && !empty($table)) { + $sql = "SELECT ".$field." FROM ".MAIN_DB_PREFIX.$table; + $sql.= " WHERE rowid = ".$id; + + dol_syslog(get_class($this).'::getValueFrom', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + $result = $row[0]; + } + } + return $result; + } + + /** + * Setter generic. Update a specific field into database. + * Warning: Trigger is run only if param trigkey is provided. + * + * @param string $field Field to update + * @param mixed $value New value + * @param string $table To force other table element or element line (should not be used) + * @param int $id To force other object id (should not be used) + * @param string $format Data format ('text', 'date'). 'text' is used if not defined + * @param string $id_field To force rowid field name. 'rowid' is used if not defined + * @param User|string $fuser Update the user of last update field with this user. If not provided, current user is used except if value is 'none' + * @param string $trigkey Trigger key to run (in most cases something like 'XXX_MODIFY') + * @return int <0 if KO, >0 if OK + * @see updateExtraField + */ + function setValueFrom($field, $value, $table='', $id=null, $format='', $id_field='', $fuser=null, $trigkey='') + { + global $user,$langs,$conf; + + if (empty($table)) $table=$this->table_element; + if (empty($id)) $id=$this->id; + if (empty($format)) $format='text'; + if (empty($id_field)) $id_field='rowid'; + + $error=0; + + $this->db->begin(); + + // Special case + if ($table == 'product' && $field == 'note_private') $field='note'; + + $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET "; + if ($format == 'text') $sql.= $field." = '".$this->db->escape($value)."'"; + else if ($format == 'int') $sql.= $field." = ".$this->db->escape($value); + else if ($format == 'date') $sql.= $field." = ".($value ? "'".$this->db->idate($value)."'" : "null"); + if (! empty($fuser) && is_object($fuser)) $sql.=", fk_user_modif = ".$fuser->id; + elseif (empty($fuser) || $fuser != 'none') $sql.=", fk_user_modif = ".$user->id; + $sql.= " WHERE ".$id_field." = ".$id; + + dol_syslog(get_class($this)."::".__FUNCTION__."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + if ($trigkey) + { + $result=$this->call_trigger($trigkey, (! empty($fuser) && is_object($fuser)) ? $fuser : $user); // This may set this->errors + if ($result < 0) $error++; + } + + if (! $error) + { + if (property_exists($this, $field)) $this->$field = $value; + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + /** + * Load properties id_previous and id_next by comparing $fieldid with $this->ref + * + * @param string $filter Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')" + * @param string $fieldid Name of field to use for the select MAX and MIN + * @param int $nodbprefix Do not include DB prefix to forge table name + * @return int <0 if KO, >0 if OK + */ + function load_previous_next_ref($filter, $fieldid, $nodbprefix=0) + { + global $user; + + if (! $this->table_element) + { + dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined"); + return -1; + } + if ($fieldid == 'none') return 1; + + // Security on socid + $socid = 0; + if ($user->societe_id > 0) $socid = $user->societe_id; + + // this->ismultientitymanaged contains + // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + $alias = 's'; + if ($this->element == 'societe') $alias = 'te'; + + $sql = "SELECT MAX(te.".$fieldid.")"; + $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te"; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity + else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to socid + else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid + if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc"; + $sql.= " WHERE te.".$fieldid." < '".$this->db->escape($this->ref)."'"; // ->ref must always be defined (set to id if field does not exists) + if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id; + if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)'; + if (! empty($filter)) + { + if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND "; // For backward compatibility + $sql.=$filter; + } + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity + else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN ('.getEntity($this->element).')'; + if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid; + if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)'; + if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid; + //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."
"; + + $result = $this->db->query($sql); + if (! $result) + { + $this->error=$this->db->lasterror(); + return -1; + } + $row = $this->db->fetch_row($result); + $this->ref_previous = $row[0]; + + + $sql = "SELECT MIN(te.".$fieldid.")"; + $sql.= " FROM ".(empty($nodbprefix)?MAIN_DB_PREFIX:'').$this->table_element." as te"; + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to entity + else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe as s"; // If we need to link to societe to limit select to socid + else if ($this->restrictiononfksoc == 2 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON te.fk_soc = s.rowid"; // If we need to link to societe to limit select to socid + if ($this->restrictiononfksoc && !$user->rights->societe->client->voir && !$socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON ".$alias.".rowid = sc.fk_soc"; + $sql.= " WHERE te.".$fieldid." > '".$this->db->escape($this->ref)."'"; // ->ref must always be defined (set to id if field does not exists) + if ($this->restrictiononfksoc == 1 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND sc.fk_user = " .$user->id; + if ($this->restrictiononfksoc == 2 && !$user->rights->societe->client->voir && !$socid) $sql.= " AND (sc.fk_user = " .$user->id.' OR te.fk_soc IS NULL)'; + if (! empty($filter)) + { + if (! preg_match('/^\s*AND/i', $filter)) $sql.=" AND "; // For backward compatibility + $sql.=$filter; + } + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 2) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to entity + else if ($this->restrictiononfksoc == 1 && $this->element != 'societe' && !$user->rights->societe->client->voir && !$socid) $sql.= ' AND te.fk_soc = s.rowid'; // If we need to link to societe to limit select to socid + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql.= ' AND te.entity IN ('.getEntity($this->element).')'; + if ($this->restrictiononfksoc == 1 && $socid && $this->element != 'societe') $sql.= ' AND te.fk_soc = ' . $socid; + if ($this->restrictiononfksoc == 2 && $socid && $this->element != 'societe') $sql.= ' AND (te.fk_soc = ' . $socid.' OR te.fk_soc IS NULL)'; + if ($this->restrictiononfksoc && $socid && $this->element == 'societe') $sql.= ' AND te.rowid = ' . $socid; + //print 'socid='.$socid.' restrictiononfksoc='.$this->restrictiononfksoc.' ismultientitymanaged = '.$this->ismultientitymanaged.' filter = '.$filter.' -> '.$sql."
"; + // Rem: Bug in some mysql version: SELECT MIN(rowid) FROM llx_socpeople WHERE rowid > 1 when one row in database with rowid=1, returns 1 instead of null + + $result = $this->db->query($sql); + if (! $result) + { + $this->error=$this->db->lasterror(); + return -2; + } + $row = $this->db->fetch_row($result); + $this->ref_next = $row[0]; + + return 1; + } + + + /** + * Return list of id of contacts of project + * + * @param string $source Source of contact: external (llx_socpeople) or internal (llx_user) or thirdparty (llx_societe) + * @return array Array of id of contacts (if source=external or internal) + * Array of id of third parties with at least one contact on project (if source=thirdparty) + */ + function getListContactId($source='external') + { + $contactAlreadySelected = array(); + $tab = $this->liste_contact(-1,$source); + $num=count($tab); + $i = 0; + while ($i < $num) + { + if ($source == 'thirdparty') $contactAlreadySelected[$i] = $tab[$i]['socid']; + else $contactAlreadySelected[$i] = $tab[$i]['id']; + $i++; + } + return $contactAlreadySelected; + } + + + /** + * Link element with a project + * + * @param int $projectid Project id to link element to + * @return int <0 if KO, >0 if OK + */ + function setProject($projectid) + { + if (! $this->table_element) + { + dol_syslog(get_class($this)."::setProject was called on objet with property table_element not defined",LOG_ERR); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + if ($this->table_element == 'actioncomm') + { + if ($projectid) $sql.= ' SET fk_project = '.$projectid; + else $sql.= ' SET fk_project = NULL'; + $sql.= ' WHERE id = '.$this->id; + } + else + { + if ($projectid) $sql.= ' SET fk_projet = '.$projectid; + else $sql.= ' SET fk_projet = NULL'; + $sql.= ' WHERE rowid = '.$this->id; + } + + dol_syslog(get_class($this)."::setProject", LOG_DEBUG); + if ($this->db->query($sql)) + { + $this->fk_project = $projectid; + return 1; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + /** + * Change the payments methods + * + * @param int $id Id of new payment method + * @return int >0 if OK, <0 if KO + */ + function setPaymentMethods($id) + { + dol_syslog(get_class($this).'::setPaymentMethods('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + // TODO uniformize field name + $fieldname = 'fk_mode_reglement'; + if ($this->element == 'societe') $fieldname = 'mode_reglement'; + if (get_class($this) == 'Fournisseur') $fieldname = 'mode_reglement_supplier'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = '.$id; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->mode_reglement_id = $id; + // for supplier + if (get_class($this) == 'Fournisseur') $this->mode_reglement_supplier_id = $id; + return 1; + } + else + { + dol_syslog(get_class($this).'::setPaymentMethods Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setPaymentMethods, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + + /** + * Change the multicurrency code + * + * @param string $code multicurrency code + * @return int >0 if OK, <0 if KO + */ + function setMulticurrencyCode($code) + { + dol_syslog(get_class($this).'::setMulticurrencyCode('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + $fieldname = 'multicurrency_code'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname." = '".$this->db->escape($code)."'"; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->multicurrency_code = $code; + + list($fk_multicurrency, $rate) = MultiCurrency::getIdAndTxFromCode($this->db, $code); + if ($rate) $this->setMulticurrencyRate($rate); + + return 1; + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyCode Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyCode, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + + /** + * Change the multicurrency rate + * + * @param double $rate multicurrency rate + * @param int $mode mode 1 : amounts in company currency will be recalculated, mode 2 : amounts in foreign currency + * @return int >0 if OK, <0 if KO + */ + function setMulticurrencyRate($rate, $mode=1) + { + dol_syslog(get_class($this).'::setMulticurrencyRate('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + $fieldname = 'multicurrency_tx'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = '.$rate; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->multicurrency_tx = $rate; + + // Update line price + if (!empty($this->lines)) + { + foreach ($this->lines as &$line) + { + if($mode == 1) { + $line->subprice = 0; + } + + switch ($this->element) { + case 'propal': + $this->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + break; + case 'commande': + $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + break; + case 'facture': + $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->date_start, $line->date_end, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice); + break; + case 'supplier_proposal': + $this->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, ($line->description?$line->description:$line->desc), 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, $line->skip_update_total, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->array_options, $line->ref_fourn, $line->multicurrency_subprice); + break; + case 'order_supplier': + $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, false, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + break; + case 'invoice_supplier': + $this->updateline($line->id, ($line->description?$line->description:$line->desc), $line->subprice, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->qty, 0, 'HT', $line->info_bits, $line->product_type, $line->remise_percent, false, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + break; + default: + dol_syslog(get_class($this).'::setMulticurrencyRate no updateline defined', LOG_DEBUG); + break; + } + + } + } + + return 1; + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyRate Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setMulticurrencyRate, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + + /** + * Change the payments terms + * + * @param int $id Id of new payment terms + * @return int >0 if OK, <0 if KO + */ + function setPaymentTerms($id) + { + dol_syslog(get_class($this).'::setPaymentTerms('.$id.')'); + if ($this->statut >= 0 || $this->element == 'societe') + { + // TODO uniformize field name + $fieldname = 'fk_cond_reglement'; + if ($this->element == 'societe') $fieldname = 'cond_reglement'; + if (get_class($this) == 'Fournisseur') $fieldname = 'cond_reglement_supplier'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql .= ' SET '.$fieldname.' = '.$id; + $sql .= ' WHERE rowid='.$this->id; + + if ($this->db->query($sql)) + { + $this->cond_reglement_id = $id; + // for supplier + if (get_class($this) == 'Fournisseur') $this->cond_reglement_supplier_id = $id; + $this->cond_reglement = $id; // for compatibility + return 1; + } + else + { + dol_syslog(get_class($this).'::setPaymentTerms Erreur '.$sql.' - '.$this->db->error()); + $this->error=$this->db->error(); + return -1; + } + } + else + { + dol_syslog(get_class($this).'::setPaymentTerms, status of the object is incompatible'); + $this->error='Status of the object is incompatible '.$this->statut; + return -2; + } + } + + /** + * Define delivery address + * @deprecated + * + * @param int $id Address id + * @return int <0 si ko, >0 si ok + */ + function setDeliveryAddress($id) + { + $fieldname = 'fk_delivery_address'; + if ($this->element == 'delivery' || $this->element == 'shipping') $fieldname = 'fk_address'; + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET ".$fieldname." = ".$id; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + if ($this->db->query($sql)) + { + $this->fk_delivery_address = $id; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this).'::setDeliveryAddress Erreur '.$sql.' - '.$this->error); + return -1; + } + } + + + /** + * Change the shipping method + * + * @param int $shipping_method_id Id of shipping method + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @param User $userused Object user + * + * @return int 1 if OK, 0 if KO + */ + function setShippingMethod($shipping_method_id, $notrigger=false, $userused=null) + { + global $user; + + if (empty($userused)) $userused=$user; + + $error = 0; + + if (! $this->table_element) { + dol_syslog(get_class($this)."::setShippingMethod was called on objet with property table_element not defined",LOG_ERR); + return -1; + } + + $this->db->begin(); + + if ($shipping_method_id<0) $shipping_method_id='NULL'; + dol_syslog(get_class($this).'::setShippingMethod('.$shipping_method_id.')'); + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET fk_shipping_method = ".$shipping_method_id; + $sql.= " WHERE rowid=".$this->id; + $resql = $this->db->query($sql); + if (! $resql) { + dol_syslog(get_class($this).'::setShippingMethod Error ', LOG_DEBUG); + $this->error = $this->db->lasterror(); + $error++; + } else { + if (!$notrigger) + { + // Call trigger + $this->context=array('shippingmethodupdate'=>1); + $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused); + if ($result < 0) $error++; + // End call trigger + } + } + if ($error) + { + $this->db->rollback(); + return -1; + } else { + $this->shipping_method_id = ($shipping_method_id=='NULL')?null:$shipping_method_id; + $this->db->commit(); + return 1; + } + + } + + + /** + * Change the warehouse + * + * @param int $warehouse_id Id of warehouse + * @return int 1 if OK, 0 if KO + */ + function setWarehouse($warehouse_id) + { + if (! $this->table_element) { + dol_syslog(get_class($this)."::setWarehouse was called on objet with property table_element not defined",LOG_ERR); + return -1; + } + if ($warehouse_id<0) $warehouse_id='NULL'; + dol_syslog(get_class($this).'::setWarehouse('.$warehouse_id.')'); + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET fk_warehouse = ".$warehouse_id; + $sql.= " WHERE rowid=".$this->id; + + if ($this->db->query($sql)) { + $this->warehouse_id = ($warehouse_id=='NULL')?null:$warehouse_id; + return 1; + } else { + dol_syslog(get_class($this).'::setWarehouse Error ', LOG_DEBUG); + $this->error=$this->db->error(); + return 0; + } + } + + + /** + * Set last model used by doc generator + * + * @param User $user User object that make change + * @param string $modelpdf Modele name + * @return int <0 if KO, >0 if OK + */ + function setDocModel($user, $modelpdf) + { + if (! $this->table_element) + { + dol_syslog(get_class($this)."::setDocModel was called on objet with property table_element not defined",LOG_ERR); + return -1; + } + + $newmodelpdf=dol_trunc($modelpdf,255); + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET model_pdf = '".$this->db->escape($newmodelpdf)."'"; + $sql.= " WHERE rowid = ".$this->id; + // if ($this->element == 'facture') $sql.= " AND fk_statut < 2"; + // if ($this->element == 'propal') $sql.= " AND fk_statut = 0"; + + dol_syslog(get_class($this)."::setDocModel", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->modelpdf=$modelpdf; + return 1; + } + else + { + dol_print_error($this->db); + return 0; + } + } + + + /** + * Change the bank account + * + * @param int $fk_account Id of bank account + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @param User $userused Object user + * @return int 1 if OK, 0 if KO + */ + function setBankAccount($fk_account, $notrigger=false, $userused=null) + { + global $user; + + if (empty($userused)) $userused=$user; + + $error = 0; + + if (! $this->table_element) { + dol_syslog(get_class($this)."::setBankAccount was called on objet with property table_element not defined",LOG_ERR); + return -1; + } + $this->db->begin(); + + if ($fk_account<0) $fk_account='NULL'; + dol_syslog(get_class($this).'::setBankAccount('.$fk_account.')'); + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET fk_account = ".$fk_account; + $sql.= " WHERE rowid=".$this->id; + + $resql = $this->db->query($sql); + if (! $resql) + { + dol_syslog(get_class($this).'::setBankAccount Error '.$sql.' - '.$this->db->error()); + $this->error = $this->db->lasterror(); + $error++; + } + else + { + if (!$notrigger) + { + // Call trigger + $this->context=array('bankaccountupdate'=>1); + $result = $this->call_trigger(strtoupper(get_class($this)) . '_MODIFY', $userused); + if ($result < 0) $error++; + // End call trigger + } + } + if ($error) + { + $this->db->rollback(); + return -1; + } + else + { + $this->fk_account = ($fk_account=='NULL')?null:$fk_account; + $this->db->commit(); + return 1; + } + } + + + // TODO: Move line related operations to CommonObjectLine? + + /** + * Save a new position (field rang) for details lines. + * You can choose to set position for lines with already a position or lines without any position defined. + * + * @param boolean $renum True to renum all already ordered lines, false to renum only not already ordered lines. + * @param string $rowidorder ASC or DESC + * @param boolean $fk_parent_line Table with fk_parent_line field or not + * @return int <0 if KO, >0 if OK + */ + function line_order($renum=false, $rowidorder='ASC', $fk_parent_line=true) + { + if (! $this->table_element_line) + { + dol_syslog(get_class($this)."::line_order was called on objet with property table_element_line not defined",LOG_ERR); + return -1; + } + if (! $this->fk_element) + { + dol_syslog(get_class($this)."::line_order was called on objet with property fk_element not defined",LOG_ERR); + return -1; + } + + // Count number of lines to reorder (according to choice $renum) + $nl=0; + $sql = 'SELECT count(rowid) FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.'='.$this->id; + if (! $renum) $sql.= ' AND rang = 0'; + if ($renum) $sql.= ' AND rang <> 0'; + + dol_syslog(get_class($this)."::line_order", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + $nl = $row[0]; + } + else dol_print_error($this->db); + if ($nl > 0) + { + // The goal of this part is to reorder all lines, with all children lines sharing the same + // counter that parents. + $rows=array(); + + // We first search all lines that are parent lines (for multilevel details lines) + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + if ($fk_parent_line) $sql.= ' AND fk_parent_line IS NULL'; + $sql.= ' ORDER BY rang ASC, rowid '.$rowidorder; + + dol_syslog(get_class($this)."::line_order search all parent lines", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $i=0; + $num = $this->db->num_rows($resql); + while ($i < $num) + { + $row = $this->db->fetch_row($resql); + $rows[] = $row[0]; // Add parent line into array rows + $childrens = $this->getChildrenOfLine($row[0]); + if (! empty($childrens)) + { + foreach($childrens as $child) + { + array_push($rows, $child); + } + } + $i++; + } + + // Now we set a new number for each lines (parent and children with children included into parent tree) + if (! empty($rows)) + { + foreach($rows as $key => $row) + { + $this->updateRangOfLine($row, ($key+1)); + } + } + } + else + { + dol_print_error($this->db); + } + } + return 1; + } + + /** + * Get children of line + * + * @param int $id Id of parent line + * @return array Array with list of children lines id + */ + function getChildrenOfLine($id) + { + $rows=array(); + + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + $sql.= ' AND fk_parent_line = '.$id; + $sql.= ' ORDER BY rang ASC'; + + dol_syslog(get_class($this)."::getChildrenOfLine search children lines for line ".$id."", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $i=0; + $num = $this->db->num_rows($resql); + while ($i < $num) + { + $row = $this->db->fetch_row($resql); + $rows[$i] = $row[0]; + $i++; + } + } + + return $rows; + } + + /** + * Update a line to have a lower rank + * + * @param int $rowid Id of line + * @param boolean $fk_parent_line Table with fk_parent_line field or not + * @return void + */ + function line_up($rowid, $fk_parent_line=true) + { + $this->line_order(false, 'ASC', $fk_parent_line); + + // Get rang of line + $rang = $this->getRangOfLine($rowid); + + // Update position of line + $this->updateLineUp($rowid, $rang); + } + + /** + * Update a line to have a higher rank + * + * @param int $rowid Id of line + * @param boolean $fk_parent_line Table with fk_parent_line field or not + * @return void + */ + function line_down($rowid, $fk_parent_line=true) + { + $this->line_order(false, 'ASC', $fk_parent_line); + + // Get rang of line + $rang = $this->getRangOfLine($rowid); + + // Get max value for rang + $max = $this->line_max(); + + // Update position of line + $this->updateLineDown($rowid, $rang, $max); + } + + /** + * Update position of line (rang) + * + * @param int $rowid Id of line + * @param int $rang Position + * @return void + */ + function updateRangOfLine($rowid,$rang) + { + $fieldposition = 'rang'; + if ($this->table_element_line == 'ecm_files') $fieldposition = 'position'; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET '.$fieldposition.' = '.$rang; + $sql.= ' WHERE rowid = '.$rowid; + + dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG); + if (! $this->db->query($sql)) + { + dol_print_error($this->db); + } + } + + /** + * Update position of line with ajax (rang) + * + * @param array $rows Array of rows + * @return void + */ + function line_ajaxorder($rows) + { + $num = count($rows); + for ($i = 0 ; $i < $num ; $i++) + { + $this->updateRangOfLine($rows[$i], ($i+1)); + } + } + + /** + * Update position of line up (rang) + * + * @param int $rowid Id of line + * @param int $rang Position + * @return void + */ + function updateLineUp($rowid,$rang) + { + if ($rang > 1 ) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang ; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + $sql.= ' AND rang = '.($rang - 1); + if ($this->db->query($sql) ) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang - 1); + $sql.= ' WHERE rowid = '.$rowid; + if (! $this->db->query($sql) ) + { + dol_print_error($this->db); + } + } + else + { + dol_print_error($this->db); + } + } + } + + /** + * Update position of line down (rang) + * + * @param int $rowid Id of line + * @param int $rang Position + * @param int $max Max + * @return void + */ + function updateLineDown($rowid,$rang,$max) + { + if ($rang < $max) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.$rang; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + $sql.= ' AND rang = '.($rang+1); + if ($this->db->query($sql) ) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element_line.' SET rang = '.($rang+1); + $sql.= ' WHERE rowid = '.$rowid; + if (! $this->db->query($sql) ) + { + dol_print_error($this->db); + } + } + else + { + dol_print_error($this->db); + } + } + } + + /** + * Get position of line (rang) + * + * @param int $rowid Id of line + * @return int Value of rang in table of lines + */ + function getRangOfLine($rowid) + { + $sql = 'SELECT rang FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE rowid ='.$rowid; + + dol_syslog(get_class($this)."::getRangOfLine", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + return $row[0]; + } + } + + /** + * Get rowid of the line relative to its position + * + * @param int $rang Rang value + * @return int Rowid of the line + */ + function getIdOfLine($rang) + { + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + $sql.= ' AND rang = '.$rang; + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + return $row[0]; + } + } + + /** + * Get max value used for position of line (rang) + * + * @param int $fk_parent_line Parent line id + * @return int Max value of rang in table of lines + */ + function line_max($fk_parent_line=0) + { + // Search the last rang with fk_parent_line + if ($fk_parent_line) + { + $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + $sql.= ' AND fk_parent_line = '.$fk_parent_line; + + dol_syslog(get_class($this)."::line_max", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + if (! empty($row[0])) + { + return $row[0]; + } + else + { + return $this->getRangOfLine($fk_parent_line); + } + } + } + // If not, search the last rang of element + else + { + $sql = 'SELECT max(rang) FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + + dol_syslog(get_class($this)."::line_max", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + return $row[0]; + } + } + } + + /** + * Update external ref of element + * + * @param string $ref_ext Update field ref_ext + * @return int <0 if KO, >0 if OK + */ + function update_ref_ext($ref_ext) + { + if (! $this->table_element) + { + dol_syslog(get_class($this)."::update_ref_ext was called on objet with property table_element not defined", LOG_ERR); + return -1; + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET ref_ext = '".$this->db->escape($ref_ext)."'"; + $sql.= " WHERE ".(isset($this->table_rowid)?$this->table_rowid:'rowid')." = ". $this->id; + + dol_syslog(get_class($this)."::update_ref_ext", LOG_DEBUG); + if ($this->db->query($sql)) + { + $this->ref_ext = $ref_ext; + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Update note of element + * + * @param string $note New value for note + * @param string $suffix '', '_public' or '_private' + * @return int <0 if KO, >0 if OK + */ + function update_note($note,$suffix='') + { + global $user; + + if (! $this->table_element) + { + dol_syslog(get_class($this)."::update_note was called on objet with property table_element not defined", LOG_ERR); + return -1; + } + if (! in_array($suffix,array('','_public','_private'))) + { + dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR); + return -2; + } + // Special cas + //var_dump($this->table_element);exit; + if ($this->table_element == 'product') $suffix=''; + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET note".$suffix." = ".(!empty($note)?("'".$this->db->escape($note)."'"):"NULL"); + $sql.= " ,".(in_array($this->table_element, array('actioncomm', 'adherent', 'advtargetemailing', 'cronjob', 'establishment'))?"fk_user_mod":"fk_user_modif")." = ".$user->id; + $sql.= " WHERE rowid =". $this->id; + + dol_syslog(get_class($this)."::update_note", LOG_DEBUG); + if ($this->db->query($sql)) + { + if ($suffix == '_public') $this->note_public = $note; + else if ($suffix == '_private') $this->note_private = $note; + else + { + $this->note = $note; // deprecated + $this->note_private = $note; + } + return 1; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } + + /** + * Update public note (kept for backward compatibility) + * + * @param string $note New value for note + * @return int <0 if KO, >0 if OK + * @deprecated + * @see update_note() + */ + function update_note_public($note) + { + return $this->update_note($note,'_public'); + } + + /** + * Update total_ht, total_ttc, total_vat, total_localtax1, total_localtax2 for an object (sum of lines). + * Must be called at end of methods addline or updateline. + * + * @param int $exclspec >0 = Exclude special product (product_type=9) + * @param string $roundingadjust 'none'=Do nothing, 'auto'=Use default method (MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND if defined, or '0'), '0'=Force mode total of rounding, '1'=Force mode rounding of total + * @param int $nodatabaseupdate 1=Do not update database. Update only properties of object. + * @param Societe $seller If roundingadjust is '0' or '1' or maybe 'auto', it means we recalculate total for lines before calculating total for object and for this, we need seller object. + * @return int <0 if KO, >0 if OK + */ + function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller=null) + { + global $conf; + + // Some external module want no update price after a trigger because they have another method to calculate the total (ex: with an extrafield) + $MODULE = ""; + if ($this->element == 'propal') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_PROPOSAL"; + elseif ($this->element == 'order') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_ORDER"; + elseif ($this->element == 'facture') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_INVOICE"; + elseif ($this->element == 'facture_fourn') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_INVOICE"; + elseif ($this->element == 'order_supplier') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_ORDER"; + elseif ($this->element == 'supplier_proposal') + $MODULE = "MODULE_DISALLOW_UPDATE_PRICE_SUPPLIER_PROPOSAL"; + + if (! empty($MODULE)) { + if (! empty($conf->global->$MODULE)) { + $modsactivated = explode(',', $conf->global->$MODULE); + foreach ($modsactivated as $mod) { + if ($conf->$mod->enabled) + return 1; // update was disabled by specific setup + } + } + } + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + if ($roundingadjust == '-1') $roundingadjust='auto'; // For backward compatibility + + $forcedroundingmode=$roundingadjust; + if ($forcedroundingmode == 'auto' && isset($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)) $forcedroundingmode=$conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND; + elseif ($forcedroundingmode == 'auto') $forcedroundingmode='0'; + + $error=0; + + $multicurrency_tx = !empty($this->multicurrency_tx) ? $this->multicurrency_tx : 1; + + // Define constants to find lines to sum + $fieldtva='total_tva'; + $fieldlocaltax1='total_localtax1'; + $fieldlocaltax2='total_localtax2'; + $fieldup='subprice'; + if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') + { + $fieldtva='tva'; + $fieldup='pu_ht'; + } + if ($this->element == 'expensereport') + { + $fieldup='value_unit'; + } + + $sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,'; + $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type'; + if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent'; + $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; + if ($exclspec) + { + $product_field='product_type'; + if ($this->table_element_line == 'contratdet') $product_field=''; // contratdet table has no product_type field + if ($product_field) $sql.= ' AND '.$product_field.' <> 9'; + } + $sql.= ' ORDER by rowid'; // We want to be sure to always use same order of line to not change lines differently when option MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND is used + + dol_syslog(get_class($this)."::update_price", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $this->total_ht = 0; + $this->total_tva = 0; + $this->total_localtax1 = 0; + $this->total_localtax2 = 0; + $this->total_ttc = 0; + $total_ht_by_vats = array(); + $total_tva_by_vats = array(); + $total_ttc_by_vats = array(); + $this->multicurrency_total_ht = 0; + $this->multicurrency_total_tva = 0; + $this->multicurrency_total_ttc = 0; + + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + // Note: There is no check on detail line and no check on total, if $forcedroundingmode = 'none' + if ($forcedroundingmode == '0') // Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto' + { + $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx); + $tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx); + $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1); + if ($diff) + { + $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid; + dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix); + $resqlfix=$this->db->query($sqlfix); + if (! $resqlfix) dol_print_error($this->db,'Failed to update line'); + $obj->total_tva = $tmpcal[1]; + $obj->total_ttc = $tmpcal[2]; + // + } + } + + $this->total_ht += $obj->total_ht; // The field visible at end of line detail + $this->total_tva += $obj->total_tva; + $this->total_localtax1 += $obj->total_localtax1; + $this->total_localtax2 += $obj->total_localtax2; + $this->total_ttc += $obj->total_ttc; + $this->multicurrency_total_ht += $obj->multicurrency_total_ht; // The field visible at end of line detail + $this->multicurrency_total_tva += $obj->multicurrency_total_tva; + $this->multicurrency_total_ttc += $obj->multicurrency_total_ttc; + + if (! isset($total_ht_by_vats[$obj->vatrate])) $total_ht_by_vats[$obj->vatrate]=0; + if (! isset($total_tva_by_vats[$obj->vatrate])) $total_tva_by_vats[$obj->vatrate]=0; + if (! isset($total_ttc_by_vats[$obj->vatrate])) $total_ttc_by_vats[$obj->vatrate]=0; + $total_ht_by_vats[$obj->vatrate] += $obj->total_ht; + $total_tva_by_vats[$obj->vatrate] += $obj->total_tva; + $total_ttc_by_vats[$obj->vatrate] += $obj->total_ttc; + + if ($forcedroundingmode == '1') // Check if we need adjustement onto line for vat. TODO This works on the company currency but not on multicurrency + { + $tmpvat=price2num($total_ht_by_vats[$obj->vatrate] * $obj->vatrate / 100, 'MT', 1); + $diff=price2num($total_tva_by_vats[$obj->vatrate]-$tmpvat, 'MT', 1); + //print 'Line '.$i.' rowid='.$obj->rowid.' vat_rate='.$obj->vatrate.' total_ht='.$obj->total_ht.' total_tva='.$obj->total_tva.' total_ttc='.$obj->total_ttc.' total_ht_by_vats='.$total_ht_by_vats[$obj->vatrate].' total_tva_by_vats='.$total_tva_by_vats[$obj->vatrate].' (new calculation = '.$tmpvat.') total_ttc_by_vats='.$total_ttc_by_vats[$obj->vatrate].($diff?" => DIFF":"")."
\n"; + if ($diff) + { + if (abs($diff) > 0.1) { dol_syslog('A rounding difference was detected into TOTAL but is too high to be corrected', LOG_WARNING); exit; } + $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".($obj->total_tva - $diff).", total_ttc = ".($obj->total_ttc - $diff)." WHERE rowid = ".$obj->rowid; + dol_syslog('We found a difference of '.$diff.' for line rowid = '.$obj->rowid.". We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix); + $resqlfix=$this->db->query($sqlfix); + if (! $resqlfix) dol_print_error($this->db,'Failed to update line'); + $this->total_tva -= $diff; + $this->total_ttc -= $diff; + $total_tva_by_vats[$obj->vatrate] -= $diff; + $total_ttc_by_vats[$obj->vatrate] -= $diff; + + } + } + + $i++; + } + + // Add revenue stamp to total + $this->total_ttc += isset($this->revenuestamp)?$this->revenuestamp:0; + $this->multicurrency_total_ttc += isset($this->revenuestamp)?($this->revenuestamp * $multicurrency_tx):0; + + // Situations totals + if ($this->situation_cycle_ref && $this->situation_counter > 1 && method_exists($this, 'get_prev_sits')) + { + $prev_sits = $this->get_prev_sits(); + + foreach ($prev_sits as $sit) { // $sit is an object Facture loaded with a fetch. + $this->total_ht -= $sit->total_ht; + $this->total_tva -= $sit->total_tva; + $this->total_localtax1 -= $sit->total_localtax1; + $this->total_localtax2 -= $sit->total_localtax2; + $this->total_ttc -= $sit->total_ttc; + $this->multicurrency_total_ht -= $sit->multicurrency_total_ht; + $this->multicurrency_total_tva -= $sit->multicurrency_total_tva; + $this->multicurrency_total_ttc -= $sit->multicurrency_total_ttc; + } + } + + $this->db->free($resql); + + // Now update global field total_ht, total_ttc and tva + $fieldht='total_ht'; + $fieldtva='tva'; + $fieldlocaltax1='localtax1'; + $fieldlocaltax2='localtax2'; + $fieldttc='total_ttc'; + // Specific code for backward compatibility with old field names + if ($this->element == 'facture' || $this->element == 'facturerec') $fieldht='total'; + if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva'; + if ($this->element == 'propal') $fieldttc='total'; + if ($this->element == 'expensereport') $fieldtva='total_tva'; + if ($this->element == 'supplier_proposal') $fieldttc='total'; + + if (empty($nodatabaseupdate)) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET'; + $sql .= " ".$fieldht."='".price2num($this->total_ht)."',"; + $sql .= " ".$fieldtva."='".price2num($this->total_tva)."',"; + $sql .= " ".$fieldlocaltax1."='".price2num($this->total_localtax1)."',"; + $sql .= " ".$fieldlocaltax2."='".price2num($this->total_localtax2)."',"; + $sql .= " ".$fieldttc."='".price2num($this->total_ttc)."'"; + $sql .= ", multicurrency_total_ht='".price2num($this->multicurrency_total_ht, 'MT', 1)."'"; + $sql .= ", multicurrency_total_tva='".price2num($this->multicurrency_total_tva, 'MT', 1)."'"; + $sql .= ", multicurrency_total_ttc='".price2num($this->multicurrency_total_ttc, 'MT', 1)."'"; + $sql .= ' WHERE rowid = '.$this->id; + + //print "xx".$sql; + dol_syslog(get_class($this)."::update_price", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) + { + $error++; + $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); + } + } + + if (! $error) + { + return 1; + } + else + { + return -1; + } + } + else + { + dol_print_error($this->db,'Bad request in update_price'); + return -1; + } + } + + /** + * Add objects linked in llx_element_element. + * + * @param string $origin Linked element type + * @param int $origin_id Linked element id + * @return int <=0 if KO, >0 if OK + * @see fetchObjectLinked, updateObjectLinked, deleteObjectLinked + */ + function add_object_linked($origin=null, $origin_id=null) + { + $origin = (! empty($origin) ? $origin : $this->origin); + $origin_id = (! empty($origin_id) ? $origin_id : $this->origin_id); + + // Special case + if ($origin == 'order') $origin='commande'; + if ($origin == 'invoice') $origin='facture'; + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element ("; + $sql.= "fk_source"; + $sql.= ", sourcetype"; + $sql.= ", fk_target"; + $sql.= ", targettype"; + $sql.= ") VALUES ("; + $sql.= $origin_id; + $sql.= ", '".$this->db->escape($origin)."'"; + $sql.= ", ".$this->id; + $sql.= ", '".$this->db->escape($this->element)."'"; + $sql.= ")"; + + dol_syslog(get_class($this)."::add_object_linked", LOG_DEBUG); + if ($this->db->query($sql)) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return 0; + } + } + + /** + * Fetch array of objects linked to current object. Links are loaded into this->linkedObjects array and this->linkedObjectsIds + * Possible usage for parameters: + * - all parameters empty -> we look all link to current object (current object can be source or target) + * - source id+type -> will get target list linked to source + * - target id+type -> will get source list linked to target + * - source id+type + target type -> will get target list of the type + * - target id+type + target source -> will get source list of the type + * + * @param int $sourceid Object source id (if not defined, id of object) + * @param string $sourcetype Object source type (if not defined, element name of object) + * @param int $targetid Object target id (if not defined, id of object) + * @param string $targettype Object target type (if not defined, elemennt name of object) + * @param string $clause 'OR' or 'AND' clause used when both source id and target id are provided + * @param int $alsosametype 0=Return only links to object that differs from source. 1=Include also link to objects of same type. + * @return void + * @see add_object_linked, updateObjectLinked, deleteObjectLinked + */ + function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1) + { + global $conf; + + $this->linkedObjectsIds=array(); + $this->linkedObjects=array(); + + $justsource=false; + $justtarget=false; + $withtargettype=false; + $withsourcetype=false; + + if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid)) + { + $justsource=true; // the source (id and type) is a search criteria + if (! empty($targettype)) $withtargettype=true; + } + if (! empty($targetid) && ! empty($targettype) && empty($sourceid)) + { + $justtarget=true; // the target (id and type) is a search criteria + if (! empty($sourcetype)) $withsourcetype=true; + } + + $sourceid = (! empty($sourceid) ? $sourceid : $this->id); + $targetid = (! empty($targetid) ? $targetid : $this->id); + $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element); + $targettype = (! empty($targettype) ? $targettype : $this->element); + + /*if (empty($sourceid) && empty($targetid)) + { + dol_syslog('Bad usage of function. No source nor target id defined (nor as parameter nor as object id)', LOG_ERR); + return -1; + }*/ + + // Links between objects are stored in table element_element + $sql = 'SELECT rowid, fk_source, sourcetype, fk_target, targettype'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element'; + $sql.= " WHERE "; + if ($justsource || $justtarget) + { + if ($justsource) + { + $sql.= "fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."'"; + if ($withtargettype) $sql.= " AND targettype = '".$targettype."'"; + } + else if ($justtarget) + { + $sql.= "fk_target = ".$targetid." AND targettype = '".$targettype."'"; + if ($withsourcetype) $sql.= " AND sourcetype = '".$sourcetype."'"; + } + } + else + { + $sql.= "(fk_source = ".$sourceid." AND sourcetype = '".$sourcetype."')"; + $sql.= " ".$clause." (fk_target = ".$targetid." AND targettype = '".$targettype."')"; + } + $sql .= ' ORDER BY sourcetype'; + //print $sql; + + dol_syslog(get_class($this)."::fetchObjectLink", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + if ($justsource || $justtarget) + { + if ($justsource) + { + $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target; + } + else if ($justtarget) + { + $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source; + } + } + else + { + if ($obj->fk_source == $sourceid && $obj->sourcetype == $sourcetype) + { + $this->linkedObjectsIds[$obj->targettype][$obj->rowid]=$obj->fk_target; + } + if ($obj->fk_target == $targetid && $obj->targettype == $targettype) + { + $this->linkedObjectsIds[$obj->sourcetype][$obj->rowid]=$obj->fk_source; + } + } + $i++; + } + + if (! empty($this->linkedObjectsIds)) + { + foreach($this->linkedObjectsIds as $objecttype => $objectids) // $objecttype is a module name ('facture', 'mymodule', ...) or a module name with a suffix ('project_task', 'mymodule_myobj', ...) + { + // Parse element/subelement (ex: project_task, cabinetmed_consultation, ...) + $module = $element = $subelement = $objecttype; + if ($objecttype != 'supplier_proposal' && $objecttype != 'order_supplier' && $objecttype != 'invoice_supplier' + && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs)) + { + $module = $element = $regs[1]; + $subelement = $regs[2]; + } + + $classpath = $element.'/class'; + // To work with non standard classpath or module name + if ($objecttype == 'facture') { + $classpath = 'compta/facture/class'; + } + else if ($objecttype == 'facturerec') { + $classpath = 'compta/facture/class'; $module = 'facture'; + } + else if ($objecttype == 'propal') { + $classpath = 'comm/propal/class'; + } + else if ($objecttype == 'supplier_proposal') { + $classpath = 'supplier_proposal/class'; + } + else if ($objecttype == 'shipping') { + $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon'; + } + else if ($objecttype == 'delivery') { + $classpath = 'livraison/class'; $subelement = 'livraison'; $module = 'livraison_bon'; + } + else if ($objecttype == 'invoice_supplier' || $objecttype == 'order_supplier') { + $classpath = 'fourn/class'; $module = 'fournisseur'; + } + else if ($objecttype == 'fichinter') { + $classpath = 'fichinter/class'; $subelement = 'fichinter'; $module = 'ficheinter'; + } + else if ($objecttype == 'subscription') { + $classpath = 'adherents/class'; $module = 'adherent'; + } + + // Set classfile + $classfile = strtolower($subelement); $classname = ucfirst($subelement); + + if ($objecttype == 'order') { + $classfile = 'commande'; $classname = 'Commande'; + } + else if ($objecttype == 'invoice_supplier') { + $classfile = 'fournisseur.facture'; $classname = 'FactureFournisseur'; + } + else if ($objecttype == 'order_supplier') { + $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur'; + } + else if ($objecttype == 'supplier_proposal') { + $classfile = 'supplier_proposal'; $classname = 'SupplierProposal'; + } + else if ($objecttype == 'facturerec') { + $classfile = 'facture-rec'; $classname = 'FactureRec'; + } + else if ($objecttype == 'subscription') { + $classfile = 'subscription'; $classname = 'Subscription'; + } + + // Here $module, $classfile and $classname are set + if ($conf->$module->enabled && (($element != $this->element) || $alsosametype)) + { + dol_include_once('/'.$classpath.'/'.$classfile.'.class.php'); + //print '/'.$classpath.'/'.$classfile.'.class.php '.class_exists($classname); + if (class_exists($classname)) + { + foreach($objectids as $i => $objectid) // $i is rowid into llx_element_element + { + $object = new $classname($this->db); + $ret = $object->fetch($objectid); + if ($ret >= 0) + { + $this->linkedObjects[$objecttype][$i] = $object; + } + } + } + } + } + } + } + else + { + dol_print_error($this->db); + } + } + + /** + * Update object linked of a current object + * + * @param int $sourceid Object source id + * @param string $sourcetype Object source type + * @param int $targetid Object target id + * @param string $targettype Object target type + * @return int >0 if OK, <0 if KO + * @see add_object_linked, fetObjectLinked, deleteObjectLinked + */ + function updateObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='') + { + $updatesource=false; + $updatetarget=false; + + if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $updatesource=true; + else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $updatetarget=true; + + $sql = "UPDATE ".MAIN_DB_PREFIX."element_element SET "; + if ($updatesource) + { + $sql.= "fk_source = ".$sourceid; + $sql.= ", sourcetype = '".$this->db->escape($sourcetype)."'"; + $sql.= " WHERE fk_target = ".$this->id; + $sql.= " AND targettype = '".$this->db->escape($this->element)."'"; + } + else if ($updatetarget) + { + $sql.= "fk_target = ".$targetid; + $sql.= ", targettype = '".$this->db->escape($targettype)."'"; + $sql.= " WHERE fk_source = ".$this->id; + $sql.= " AND sourcetype = '".$this->db->escape($this->element)."'"; + } + + dol_syslog(get_class($this)."::updateObjectLinked", LOG_DEBUG); + if ($this->db->query($sql)) + { + return 1; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } + + /** + * Delete all links between an object $this + * + * @param int $sourceid Object source id + * @param string $sourcetype Object source type + * @param int $targetid Object target id + * @param string $targettype Object target type + * @param int $rowid Row id of line to delete. If defined, other parameters are not used. + * @return int >0 if OK, <0 if KO + * @see add_object_linked, updateObjectLinked, fetchObjectLinked + */ + function deleteObjectLinked($sourceid=null, $sourcetype='', $targetid=null, $targettype='', $rowid='') + { + $deletesource=false; + $deletetarget=false; + + if (! empty($sourceid) && ! empty($sourcetype) && empty($targetid) && empty($targettype)) $deletesource=true; + else if (empty($sourceid) && empty($sourcetype) && ! empty($targetid) && ! empty($targettype)) $deletetarget=true; + + $sourceid = (! empty($sourceid) ? $sourceid : $this->id); + $sourcetype = (! empty($sourcetype) ? $sourcetype : $this->element); + $targetid = (! empty($targetid) ? $targetid : $this->id); + $targettype = (! empty($targettype) ? $targettype : $this->element); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_element"; + $sql.= " WHERE"; + if ($rowid > 0) + { + $sql.=" rowid = ".$rowid; + } + else + { + if ($deletesource) + { + $sql.= " fk_source = ".$sourceid." AND sourcetype = '".$this->db->escape($sourcetype)."'"; + $sql.= " AND fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."'"; + } + else if ($deletetarget) + { + $sql.= " fk_target = ".$targetid." AND targettype = '".$this->db->escape($targettype)."'"; + $sql.= " AND fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."'"; + } + else + { + $sql.= " (fk_source = ".$this->id." AND sourcetype = '".$this->db->escape($this->element)."')"; + $sql.= " OR"; + $sql.= " (fk_target = ".$this->id." AND targettype = '".$this->db->escape($this->element)."')"; + } + } + + dol_syslog(get_class($this)."::deleteObjectLinked", LOG_DEBUG); + if ($this->db->query($sql)) + { + return 1; + } + else + { + $this->error=$this->db->lasterror(); + $this->errors[]=$this->error; + return -1; + } + } + + /** + * Set status of an object + * + * @param int $status Status to set + * @param int $elementId Id of element to force (use this->id by default) + * @param string $elementType Type of element to force (use this->table_element by default) + * @return int <0 if KO, >0 if OK + */ + function setStatut($status,$elementId=null,$elementType='') + { + global $user,$langs,$conf; + + $savElementId=$elementId; // To be used later to know if we were using the method using the id of this or not. + + $elementId = (!empty($elementId)?$elementId:$this->id); + $elementTable = (!empty($elementType)?$elementType:$this->table_element); + + $this->db->begin(); + + $fieldstatus="fk_statut"; + if ($elementTable == 'mailing') $fieldstatus="statut"; + if ($elementTable == 'user') $fieldstatus="statut"; + if ($elementTable == 'expensereport') $fieldstatus="fk_statut"; + if ($elementTable == 'commande_fournisseur_dispatch') $fieldstatus="status"; + + $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable; + $sql.= " SET ".$fieldstatus." = ".$status; + // If status = 1 = validated, update also fk_user_valid + if ($status == 1 && $elementTable == 'expensereport') $sql.=", fk_user_valid = ".$user->id; + $sql.= " WHERE rowid=".$elementId; + + dol_syslog(get_class($this)."::setStatut", LOG_DEBUG); + if ($this->db->query($sql)) + { + $error = 0; + + $trigkey=''; + if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN'; // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class + if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class + if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE'; // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class + if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE'; + if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED'; + if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED'; + + if ($trigkey) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers($trigkey,$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + + if (! $error) + { + $this->db->commit(); + + if (empty($savElementId)) // If the element we update was $this (so $elementId is null) + { + $this->statut = $status; + $this->status = $status; + } + + return 1; + } + else + { + $this->db->rollback(); + dol_syslog(get_class($this)."::setStatus ".$this->error,LOG_ERR); + return -1; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + + /** + * Load type of canvas of an object if it exists + * + * @param int $id Record id + * @param string $ref Record ref + * @return int <0 if KO, 0 if nothing done, >0 if OK + */ + function getCanvas($id=0,$ref='') + { + global $conf; + + if (empty($id) && empty($ref)) return 0; + if (! empty($conf->global->MAIN_DISABLE_CANVAS)) return 0; // To increase speed. Not enabled by default. + + // Clean parameters + $ref = trim($ref); + + $sql = "SELECT rowid, canvas"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " WHERE entity IN (".getEntity($this->element).")"; + if (! empty($id)) $sql.= " AND rowid = ".$id; + if (! empty($ref)) $sql.= " AND ref = '".$this->db->escape($ref)."'"; + + $resql = $this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + if ($obj) + { + $this->canvas = $obj->canvas; + return 1; + } + else return 0; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + + /** + * Get special code of a line + * + * @param int $lineid Id of line + * @return int Special code + */ + function getSpecialCode($lineid) + { + $sql = 'SELECT special_code FROM '.MAIN_DB_PREFIX.$this->table_element_line; + $sql.= ' WHERE rowid = '.$lineid; + $resql = $this->db->query($sql); + if ($resql) + { + $row = $this->db->fetch_row($resql); + return $row[0]; + } + } + + /** + * Function to check if an object is used by others. + * Check is done into this->childtables. There is no check into llx_element_element. + * + * @param int $id Force id of object + * @return int <0 if KO, 0 if not used, >0 if already used + */ + function isObjectUsed($id=0) + { + global $langs; + + if (empty($id)) $id=$this->id; + + // Check parameters + if (! isset($this->childtables) || ! is_array($this->childtables) || count($this->childtables) == 0) + { + dol_print_error('Called isObjectUsed on a class with property this->childtables not defined'); + return -1; + } + + $arraytoscan = $this->childtables; + // For backward compatibility, we check if array is old format array('table1', 'table2', ...) + $tmparray=array_keys($this->childtables); + if (is_numeric($tmparray[0])) + { + $arraytoscan = array_flip($this->childtables); + } + + // Test if child exists + $haschild=0; + foreach($arraytoscan as $table => $elementname) + { + //print $id.'-'.$table.'-'.$elementname.'
'; + // Check if third party can be deleted + $sql = "SELECT COUNT(*) as nb from ".MAIN_DB_PREFIX.$table; + $sql.= " WHERE ".$this->fk_element." = ".$id; + $resql=$this->db->query($sql); + if ($resql) + { + $obj=$this->db->fetch_object($resql); + if ($obj->nb > 0) + { + $langs->load("errors"); + //print 'Found into table '.$table.', type '.$langs->transnoentitiesnoconv($elementname).', haschild='.$haschild; + $haschild += $obj->nb; + $this->errors[]=$langs->trans("ErrorRecordHasAtLeastOneChildOfType", $langs->transnoentitiesnoconv($elementname)); + break; // We found at least one, we stop here + } + } + else + { + $this->errors[]=$this->db->lasterror(); + return -1; + } + } + if ($haschild > 0) + { + $this->errors[]="ErrorRecordHasChildren"; + return $haschild; + } + else return 0; + } + + /** + * Function to say how many lines object contains + * + * @param int $predefined -1=All, 0=Count free product/service only, 1=Count predefined product/service only, 2=Count predefined product, 3=Count predefined service + * @return int <0 if KO, 0 if no predefined products, nb of lines with predefined products if found + */ + function hasProductsOrServices($predefined=-1) + { + $nb=0; + + foreach($this->lines as $key => $val) + { + $qualified=0; + if ($predefined == -1) $qualified=1; + if ($predefined == 1 && $val->fk_product > 0) $qualified=1; + if ($predefined == 0 && $val->fk_product <= 0) $qualified=1; + if ($predefined == 2 && $val->fk_product > 0 && $val->product_type==0) $qualified=1; + if ($predefined == 3 && $val->fk_product > 0 && $val->product_type==1) $qualified=1; + if ($qualified) $nb++; + } + dol_syslog(get_class($this).'::hasProductsOrServices we found '.$nb.' qualified lines of products/servcies'); + return $nb; + } + + /** + * Function that returns the total amount HT of discounts applied for all lines. + * + * @return float + */ + function getTotalDiscount() + { + $total_discount=0.00; + + $sql = "SELECT subprice as pu_ht, qty, remise_percent, total_ht"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element."det"; + $sql.= " WHERE ".$this->fk_element." = ".$this->id; + + dol_syslog(get_class($this).'::getTotalDiscount', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num=$this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + $pu_ht = $obj->pu_ht; + $qty= $obj->qty; + $total_ht = $obj->total_ht; + + $total_discount_line = floatval(price2num(($pu_ht * $qty) - $total_ht, 'MT')); + $total_discount += $total_discount_line; + + $i++; + } + } + + //print $total_discount; exit; + return price2num($total_discount); + } + + + /** + * Return into unit=0, the calculated total of weight and volume of all lines * qty + * Calculate by adding weight and volume of each product line, so properties ->volume/volume_units/weight/weight_units must be loaded on line. + * + * @return array array('weight'=>...,'volume'=>...) + */ + function getTotalWeightVolume() + { + $totalWeight = 0; + $totalVolume = 0; + // defined for shipment only + $totalOrdered = ''; + // defined for shipment only + $totalToShip = ''; + + foreach ($this->lines as $line) + { + if (isset($line->qty_asked)) + { + if (empty($totalOrdered)) $totalOrdered=0; // Avoid warning because $totalOrdered is '' + $totalOrdered+=$line->qty_asked; // defined for shipment only + } + if (isset($line->qty_shipped)) + { + if (empty($totalToShip)) $totalToShip=0; // Avoid warning because $totalToShip is '' + $totalToShip+=$line->qty_shipped; // defined for shipment only + } + + // Define qty, weight, volume, weight_units, volume_units + if ($this->element == 'shipping') { + // for shipments + $qty = $line->qty_shipped ? $line->qty_shipped : 0; + } + else { + $qty = $line->qty ? $line->qty : 0; + } + + $weight = $line->weight ? $line->weight : 0; + $volume = $line->volume ? $line->volume : 0; + + $weight_units=$line->weight_units; + $volume_units=$line->volume_units; + + $weightUnit=0; + $volumeUnit=0; + if (! empty($weight_units)) $weightUnit = $weight_units; + if (! empty($volume_units)) $volumeUnit = $volume_units; + + if (empty($totalWeight)) $totalWeight=0; // Avoid warning because $totalWeight is '' + if (empty($totalVolume)) $totalVolume=0; // Avoid warning because $totalVolume is '' + + //var_dump($line->volume_units); + if ($weight_units < 50) // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch) + { + $trueWeightUnit=pow(10, $weightUnit); + $totalWeight += $weight * $qty * $trueWeightUnit; + } + else { + if ($weight_units == 99) { + // conversion 1 Pound = 0.45359237 KG + $trueWeightUnit = 0.45359237; + $totalWeight += $weight * $qty * $trueWeightUnit; + } elseif ($weight_units == 98) { + // conversion 1 Ounce = 0.0283495 KG + $trueWeightUnit = 0.0283495; + $totalWeight += $weight * $qty * $trueWeightUnit; + } + else + $totalWeight += $weight * $qty; // This may be wrong if we mix different units + } + if ($volume_units < 50) // >50 means a standard unit (power of 10 of official unit), > 50 means an exotic unit (like inch) + { + //print $line->volume."x".$line->volume_units."x".($line->volume_units < 50)."x".$volumeUnit; + $trueVolumeUnit=pow(10, $volumeUnit); + //print $line->volume; + $totalVolume += $volume * $qty * $trueVolumeUnit; + } + else + { + $totalVolume += $volume * $qty; // This may be wrong if we mix different units + } + } + + return array('weight'=>$totalWeight, 'volume'=>$totalVolume, 'ordered'=>$totalOrdered, 'toship'=>$totalToShip); + } + + + /** + * Set extra parameters + * + * @return int <0 if KO, >0 if OK + */ + function setExtraParameters() + { + $this->db->begin(); + + $extraparams = (! empty($this->extraparams) ? json_encode($this->extraparams) : null); + + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET extraparams = ".(! empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null"); + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::setExtraParameters", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + else + { + $this->db->commit(); + return 1; + } + } + + + /** + * Return incoterms informations + * TODO Use a cache for label get + * + * @return string incoterms info + */ + function display_incoterms() + { + $out = ''; + $this->libelle_incoterms = ''; + if (!empty($this->fk_incoterms)) + { + $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms; + $result = $this->db->query($sql); + if ($result) + { + $res = $this->db->fetch_object($result); + $out .= $res->code; + } + } + + $out .= (($res->code && $this->location_incoterms)?' - ':'').$this->location_incoterms; + + return $out; + } + + /** + * Return incoterms informations for pdf display + * + * @return string incoterms info + */ + function getIncotermsForPDF() + { + $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms; + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + if ($num > 0) + { + $res = $this->db->fetch_object($resql); + return 'Incoterm : '.$res->code.' - '.$this->location_incoterms; + } + else + { + return ''; + } + } + else + { + $this->errors[] = $this->db->lasterror(); + return false; + } + } + + /** + * Define incoterms values of current object + * + * @param int $id_incoterm Id of incoterm to set or '' to remove + * @param string $location location of incoterm + * @return int <0 if KO, >0 if OK + */ + function setIncoterms($id_incoterm, $location) + { + if ($this->id && $this->table_element) + { + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql.= " SET fk_incoterms = ".($id_incoterm > 0 ? $id_incoterm : "null"); + $sql.= ", location_incoterms = ".($id_incoterm > 0 ? "'".$this->db->escape($location)."'" : "null"); + $sql.= " WHERE rowid = " . $this->id; + dol_syslog(get_class($this).'::setIncoterms', LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->fk_incoterms = $id_incoterm; + $this->location_incoterms = $location; + + $sql = 'SELECT libelle FROM '.MAIN_DB_PREFIX.'c_incoterms WHERE rowid = '.(int) $this->fk_incoterms; + $res = $this->db->query($sql); + if ($res) + { + $obj = $this->db->fetch_object($res); + $this->libelle_incoterms = $obj->libelle; + } + return 1; + } + else + { + $this->errors[] = $this->db->lasterror(); + return -1; + } + } + else return -1; + } + + + /** + * Return if a country is inside the EEC (European Economic Community) + * @deprecated + * + * @return boolean true = country inside EEC, false = country outside EEC + */ + function isInEEC() + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + return isInEEC($this); + } + + + // -------------------- + // TODO: All functions here must be redesigned and moved as they are not business functions but output functions + // -------------------- + + /* This is to show add lines */ + + /** + * Show add free and predefined products/services form + * + * @param int $dateSelector 1=Show also date range input fields + * @param Societe $seller Object thirdparty who sell + * @param Societe $buyer Object thirdparty who buy + * @return void + */ + function formAddObjectLine($dateSelector,$seller,$buyer) + { + global $conf,$user,$langs,$object,$hookmanager; + global $form,$bcnd,$var; + + //Line extrafield + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafieldsline = new ExtraFields($this->db); + $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line); + + // Output template part (modules that overwrite templates must declare this into descriptor) + // Use global variables + $dateSelector + $seller and $buyer + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $tpl = dol_buildpath($reldir.'/objectline_create.tpl.php'); + if (empty($conf->file->strict_mode)) { + $res=@include $tpl; + } else { + $res=include $tpl; // for debug + } + if ($res) break; + } + } + + + + /* This is to show array of line of details */ + + + /** + * Return HTML table for object lines + * TODO Move this into an output class file (htmlline.class.php) + * If lines are into a template, title must also be into a template + * But for the moment we don't know if it'st possible as we keep a method available on overloaded objects. + * + * @param string $action Action code + * @param string $seller Object of seller third party + * @param string $buyer Object of buyer third party + * @param int $selected Object line selected + * @param int $dateSelector 1=Show also date range input fields + * @return void + */ + function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0) + { + global $conf, $hookmanager, $langs, $user; + // TODO We should not use global var for this ! + global $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $disableremove, $outputalsopricetotalwithtax; + + // Define usemargins + $usemargins=0; + if (! empty($conf->margin->enabled) && ! empty($this->element) && in_array($this->element,array('facture','propal','commande'))) $usemargins=1; + + $num = count($this->lines); + + //Line extrafield + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafieldsline = new ExtraFields($this->db); + $extralabelslines=$extrafieldsline->fetch_name_optionals_label($this->table_element_line); + + $parameters = array('num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline); + $reshook = $hookmanager->executeHooks('printObjectLineTitle', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + print '
'; + + if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) print ''; + + // Description + print ''; + + if ($this->element == 'supplier_proposal' || $this->element == 'order_supplier' || $this->element == 'invoice_supplier') + { + print ''; + } + + // VAT + print ''; + + // Price HT + print ''; + + // Multicurrency + if (!empty($conf->multicurrency->enabled)) print ''; + + if ($inputalsopricewithtax) print ''; + + // Qty + print ''; + + if($conf->global->PRODUCT_USE_UNITS) + { + print ''; + } + + // Reduction short + print ''; + + if ($this->situation_cycle_ref) { + print ''; + } + + if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id)) + { + if (!empty($user->rights->margins->creer)) + { + if ($conf->global->MARGIN_TYPE == "1") + print ''; + else + print ''; + } + + if (! empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous) + print ''; + if (! empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous) + print ''; + } + + // Total HT + print ''; + + // Multicurrency + if (!empty($conf->multicurrency->enabled)) print ''; + + if ($outputalsopricetotalwithtax) print ''; + + print ''; // No width to allow autodim + + print ''; + + print ''; + + print "\n"; + } + + $var = true; + $i = 0; + + foreach ($this->lines as $line) + { + //Line extrafield + $line->fetch_optionals($line->id,$extralabelslines); + + + + //if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) + if (is_object($hookmanager)) // Old code is commented on preceding line. + { + if (empty($line->fk_parent_line)) + { + $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline); + $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + } + else + { + $parameters = array('line'=>$line,'var'=>$var,'num'=>$num,'i'=>$i,'dateSelector'=>$dateSelector,'seller'=>$seller,'buyer'=>$buyer,'selected'=>$selected, 'extrafieldsline'=>$extrafieldsline, 'fk_parent_line'=>$line->fk_parent_line); + $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + } + } + if (empty($reshook)) + { + $this->printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected,$extrafieldsline); + } + + $i++; + } + } + + /** + * Return HTML content of a detail line + * TODO Move this into an output class file (htmlline.class.php) + * + * @param string $action GET/POST action + * @param CommonObjectLine $line Selected object line to output + * @param string $var Is it a an odd line (true) + * @param int $num Number of line (0) + * @param int $i I + * @param int $dateSelector 1=Show also date range input fields + * @param string $seller Object of seller third party + * @param string $buyer Object of buyer third party + * @param int $selected Object line selected + * @param int $extrafieldsline Object of extrafield line attribute + * @return void + */ + function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0) + { + global $conf,$langs,$user,$object,$hookmanager; + global $form,$bc,$bcdd; + global $object_rights, $disableedit, $disablemove; // TODO We should not use global var for this ! + + $object_rights = $this->getRights(); + + $element=$this->element; + + $text=''; $description=''; $type=0; + + // Show product and description + $type=(! empty($line->product_type)?$line->product_type:$line->fk_product_type); + // Try to enhance type detection using date_start and date_end for free lines where type was not saved. + if (! empty($line->date_start)) $type=1; // deprecated + if (! empty($line->date_end)) $type=1; // deprecated + + // Ligne en mode visu + if ($action != 'editline' || $selected != $line->id) + { + // Product + if ($line->fk_product > 0) + { + $product_static = new Product($this->db); + $product_static->fetch($line->fk_product); + + $product_static->ref = $line->ref; //can change ref in hook + $product_static->label = $line->label; //can change label in hook + $text=$product_static->getNomUrl(1); + + // Define output language and label + if (! empty($conf->global->MAIN_MULTILANGS)) + { + if (! is_object($this->thirdparty)) + { + dol_print_error('','Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before'); + return; + } + + $prod = new Product($this->db); + $prod->fetch($line->fk_product); + + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); + if (! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && empty($newlang)) $newlang=$this->thirdparty->default_lang; // For language to language of customer + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $line->product_label; + } + else + { + $label = $line->product_label; + } + + $text.= ' - '.(! empty($line->label)?$line->label:$label); + $description.=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($line->description)); // Description is what to show on popup. We shown nothing if already into desc. + } + + $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU'); + + // Output template part (modules that overwrite templates must declare this into descriptor) + // Use global variables + $dateSelector + $seller and $buyer + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $tpl = dol_buildpath($reldir.'/objectline_view.tpl.php'); + if (empty($conf->file->strict_mode)) { + $res=@include $tpl; + } else { + $res=include $tpl; // for debug + } + if ($res) break; + } + } + + // Ligne en mode update + if ($this->statut == 0 && $action == 'editline' && $selected == $line->id) + { + $label = (! empty($line->label) ? $line->label : (($line->fk_product > 0) ? $line->product_label : '')); + $placeholder=' placeholder="'.$langs->trans("Label").'"'; + + $line->pu_ttc = price2num($line->subprice * (1 + ($line->tva_tx/100)), 'MU'); + + // Output template part (modules that overwrite templates must declare this into descriptor) + // Use global variables + $dateSelector + $seller and $buyer + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $tpl = dol_buildpath($reldir.'/objectline_edit.tpl.php'); + if (empty($conf->file->strict_mode)) { + $res=@include $tpl; + } else { + $res=include $tpl; // for debug + } + if ($res) break; + } + } + } + + + /* This is to show array of line of details of source object */ + + + /** + * Return HTML table table of source object lines + * TODO Move this and previous function into output html class file (htmlline.class.php). + * If lines are into a template, title must also be into a template + * But for the moment we don't know if it's possible, so we keep the method available on overloaded objects. + * + * @param string $restrictlist ''=All lines, 'services'=Restrict to services only + * @return void + */ + function printOriginLinesList($restrictlist='') + { + global $langs, $hookmanager, $conf; + + print ''; + print ''; + print ''; + print ''; + print ''; + if (!empty($conf->multicurrency->enabled)) print ''; + print ''; + if($conf->global->PRODUCT_USE_UNITS) + { + print ''; + } + print ''; + + $var = true; + $i = 0; + + foreach ($this->lines as $line) + { + if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) + { + if (empty($line->fk_parent_line)) + { + $parameters=array('line'=>$line,'var'=>$var,'i'=>$i); + $action=''; + $hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + } + } + else + { + $this->printOriginLine($line, $var, $restrictlist); + } + + $i++; + } + } + + /** + * Return HTML with a line of table array of source object lines + * TODO Move this and previous function into output html class file (htmlline.class.php). + * If lines are into a template, title must also be into a template + * But for the moment we don't know if it's possible as we keep a method available on overloaded objects. + * + * @param CommonObjectLine $line Line + * @param string $var Var + * @param string $restrictlist ''=All lines, 'services'=Restrict to services only (strike line if not) + * @return void + */ + function printOriginLine($line, $var, $restrictlist='') + { + global $langs, $conf; + + //var_dump($line); + if (!empty($line->date_start)) + { + $date_start=$line->date_start; + } + else + { + $date_start=$line->date_debut_prevue; + if ($line->date_debut_reel) $date_start=$line->date_debut_reel; + } + if (!empty($line->date_end)) + { + $date_end=$line->date_end; + } + else + { + $date_end=$line->date_fin_prevue; + if ($line->date_fin_reel) $date_end=$line->date_fin_reel; + } + + $this->tpl['label'] = ''; + if (! empty($line->fk_parent_line)) $this->tpl['label'].= img_picto('', 'rightarrow'); + + if (($line->info_bits & 2) == 2) // TODO Not sure this is used for source object + { + $discount=new DiscountAbsolute($this->db); + $discount->fk_soc = $this->socid; + $this->tpl['label'].= $discount->getNomUrl(0,'discount'); + } + else if (! empty($line->fk_product)) + { + $productstatic = new Product($this->db); + $productstatic->id = $line->fk_product; + $productstatic->ref = $line->ref; + $productstatic->type = $line->fk_product_type; + $this->tpl['label'].= $productstatic->getNomUrl(1); + $this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label); + // Dates + if ($line->product_type == 1 && ($date_start || $date_end)) + { + $this->tpl['label'].= get_date_range($date_start,$date_end); + } + } + else + { + $this->tpl['label'].= ($line->product_type == -1 ? ' ' : ($line->product_type == 1 ? img_object($langs->trans(''),'service') : img_object($langs->trans(''),'product'))); + if (!empty($line->desc)) { + $this->tpl['label'].=$line->desc; + }else { + $this->tpl['label'].= ($line->label ? ' '.$line->label : ''); + } + // Dates + if ($line->product_type == 1 && ($date_start || $date_end)) + { + $this->tpl['label'].= get_date_range($date_start,$date_end); + } + } + + if (! empty($line->desc)) + { + if ($line->desc == '(CREDIT_NOTE)') // TODO Not sure this is used for source object + { + $discount=new DiscountAbsolute($this->db); + $discount->fetch($line->fk_remise_except); + $this->tpl['description'] = $langs->transnoentities("DiscountFromCreditNote",$discount->getNomUrl(0)); + } + elseif ($line->desc == '(DEPOSIT)') // TODO Not sure this is used for source object + { + $discount=new DiscountAbsolute($this->db); + $discount->fetch($line->fk_remise_except); + $this->tpl['description'] = $langs->transnoentities("DiscountFromDeposit",$discount->getNomUrl(0)); + } + elseif ($line->desc == '(EXCESS RECEIVED)') + { + $discount=new DiscountAbsolute($this->db); + $discount->fetch($line->fk_remise_except); + $this->tpl['description'] = $langs->transnoentities("DiscountFromExcessReceived",$discount->getNomUrl(0)); + } + else + { + $this->tpl['description'] = dol_trunc($line->desc,60); + } + } + else + { + $this->tpl['description'] = ' '; + } + + // VAT Rate + $this->tpl['vat_rate'] = vatrate($line->tva_tx, true); + $this->tpl['vat_rate'] .= (($line->info_bits & 1) == 1) ? '*' : ''; + if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')'; + + $this->tpl['price'] = price($line->subprice); + $this->tpl['multicurrency_price'] = price($line->multicurrency_subprice); + $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : ' '; + if ($conf->global->PRODUCT_USE_UNITS) $this->tpl['unit'] = $langs->transnoentities($line->getLabelOfUnit('long')); + $this->tpl['remise_percent'] = (($line->info_bits & 2) != 2) ? vatrate($line->remise_percent, true) : ' '; + + // Is the line strike or not + $this->tpl['strike']=0; + if ($restrictlist == 'services' && $line->product_type != Product::TYPE_SERVICE) $this->tpl['strike']=1; + + // Output template part (modules that overwrite templates must declare this into descriptor) + // Use global variables + $dateSelector + $seller and $buyer + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $tpl = dol_buildpath($reldir.'/originproductline.tpl.php'); + if (empty($conf->file->strict_mode)) { + $res=@include $tpl; + } else { + $res=include $tpl; // for debug + } + if ($res) break; + } + } + + + /** + * Add resources to the current object : add entry into llx_element_resources + * Need $this->element & $this->id + * + * @param int $resource_id Resource id + * @param string $resource_type 'resource' + * @param int $busy Busy or not + * @param int $mandatory Mandatory or not + * @return int <=0 if KO, >0 if OK + */ + function add_element_resource($resource_id, $resource_type, $busy=0, $mandatory=0) + { + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_resources ("; + $sql.= "resource_id"; + $sql.= ", resource_type"; + $sql.= ", element_id"; + $sql.= ", element_type"; + $sql.= ", busy"; + $sql.= ", mandatory"; + $sql.= ") VALUES ("; + $sql.= $resource_id; + $sql.= ", '".$this->db->escape($resource_type)."'"; + $sql.= ", '".$this->db->escape($this->id)."'"; + $sql.= ", '".$this->db->escape($this->element)."'"; + $sql.= ", '".$this->db->escape($busy)."'"; + $sql.= ", '".$this->db->escape($mandatory)."'"; + $sql.= ")"; + + dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG); + if ($this->db->query($sql)) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return 0; + } + } + + /** + * Delete a link to resource line + * + * @param int $rowid Id of resource line to delete + * @param int $element element name (for trigger) TODO: use $this->element into commonobject class + * @param int $notrigger Disable all triggers + * @return int >0 if OK, <0 if KO + */ + function delete_resource($rowid, $element, $notrigger=0) + { + global $user; + + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources"; + $sql.= " WHERE rowid=".$rowid; + + dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG); + + $resql=$this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + else + { + if (! $notrigger) + { + $result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user); + if ($result < 0) { $this->db->rollback(); return -1; } + } + $this->db->commit(); + return 1; + } + } + + + /** + * Overwrite magic function to solve problem of cloning object that are kept as references + * + * @return void + */ + function __clone() + { + // Force a copy of this->lines, otherwise it will point to same object. + if (isset($this->lines) && is_array($this->lines)) + { + $nboflines=count($this->lines); + for($i=0; $i < $nboflines; $i++) + { + $this->lines[$i] = clone $this->lines[$i]; + } + } + } + + /** + * Common function for all objects extending CommonObject for generating documents + * + * @param string $modelspath Relative folder where generators are placed + * @param string $modele Generator to use. Caller must set it to obj->modelpdf or GETPOST('modelpdf') for example. + * @param Translate $outputlangs Output language to use + * @param int $hidedetails 1 to hide details. 0 by default + * @param int $hidedesc 1 to hide product description. 0 by default + * @param int $hideref 1 to hide product reference. 0 by default + * @param null|array $moreparams Array to provide more information + * @return int >0 if OK, <0 if KO + */ + protected function commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null) + { + global $conf, $langs, $user; + + $srctemplatepath=''; + + // Increase limit for PDF build + $err=error_reporting(); + error_reporting(0); + @set_time_limit(120); + error_reporting($err); + + // If selected model is a filename template (then $modele="modelname" or "modelname:filename") + $tmp=explode(':',$modele,2); + if (! empty($tmp[1])) + { + $modele=$tmp[0]; + $srctemplatepath=$tmp[1]; + } + + // Search template files + $file=''; $classname=''; $filefound=0; + $dirmodels=array('/'); + if (is_array($conf->modules_parts['models'])) $dirmodels=array_merge($dirmodels,$conf->modules_parts['models']); + foreach($dirmodels as $reldir) + { + foreach(array('doc','pdf') as $prefix) + { + if (in_array(get_class($this), array('Adherent'))) $file = $prefix."_".$modele.".class.php"; // Member module use prefix_module.class.php + else $file = $prefix."_".$modele.".modules.php"; + + // On verifie l'emplacement du modele + $file=dol_buildpath($reldir.$modelspath.$file,0); + if (file_exists($file)) + { + $filefound=1; + $classname=$prefix.'_'.$modele; + break; + } + } + if ($filefound) break; + } + + // If generator was found + if ($filefound) + { + global $db; // Required to solve a conception default in commonstickergenerator.class.php making an include of code using $db + + require_once $file; + + $obj = new $classname($this->db); + + // If generator is ODT, we must have srctemplatepath defined, if not we set it. + if ($obj->type == 'odt' && empty($srctemplatepath)) + { + $varfortemplatedir=$obj->scandir; + if ($varfortemplatedir && ! empty($conf->global->$varfortemplatedir)) + { + $dirtoscan=$conf->global->$varfortemplatedir; + + $listoffiles=array(); + + // Now we add first model found in directories scanned + $listofdir=explode(',',$dirtoscan); + foreach($listofdir as $key => $tmpdir) + { + $tmpdir=trim($tmpdir); + $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir); + if (! $tmpdir) { unset($listofdir[$key]); continue; } + if (is_dir($tmpdir)) + { + $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.od(s|t)$','','name',SORT_ASC,0); + if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles); + } + } + + if (count($listoffiles)) + { + foreach($listoffiles as $record) + { + $srctemplatepath=$record['fullname']; + break; + } + } + } + + if (empty($srctemplatepath)) + { + $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotDefined'; + return -1; + } + } + + if ($obj->type == 'odt' && ! empty($srctemplatepath)) + { + if (! dol_is_file($srctemplatepath)) + { + $this->error='ErrorGenerationAskedForOdtTemplateWithSrcFileNotFound'; + return -1; + } + } + + // We save charset_output to restore it because write_file can change it if needed for + // output format that does not support UTF8. + $sav_charset_output=$outputlangs->charset_output; + + if (in_array(get_class($this), array('Adherent'))) + { + $arrayofrecords = array(); // The write_file of templates of adherent class need this var + $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, $moreparams); + } + else + { + $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams); + } + // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index. + + if ($resultwritefile > 0) + { + $outputlangs->charset_output=$sav_charset_output; + + // We delete old preview + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + dol_delete_preview($this); + + // Index file in database + if (! empty($obj->result['fullpath'])) + { + $destfull = $obj->result['fullpath']; + $upload_dir = dirname($destfull); + $destfile = basename($destfull); + $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir); + + if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir + { + $filename = basename($destfile); + $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); + $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); + + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + $ecmfile=new EcmFiles($this->db); + $result = $ecmfile->fetch(0, '', ($rel_dir?$rel_dir.'/':'').$filename); + + // Set the public "share" key + $setsharekey = false; + if ($this->element == 'propal') + { + $useonlinesignature = $conf->global->MAIN_FEATURES_LEVEL; // Replace this with 1 when feature to make online signature is ok + if ($useonlinesignature) $setsharekey=true; + if (! empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true; + } + if ($this->element == 'commande' && ! empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true; + if ($this->element == 'facture' && ! empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD)) $setsharekey=true; + if ($setsharekey) + { + if (empty($ecmfile->share)) // Because object not found or share not set yet + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + $ecmfile->share = getRandomPassword(true); + } + } + + if ($result > 0) + { + $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content + $ecmfile->fullpath_orig = ''; + $ecmfile->gen_or_uploaded = 'generated'; + $ecmfile->description = ''; // indexed content + $ecmfile->keyword = ''; // keyword content + $result = $ecmfile->update($user); + if ($result < 0) + { + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } + } + else + { + $ecmfile->entity = $conf->entity; + $ecmfile->filepath = $rel_dir; + $ecmfile->filename = $filename; + $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content + $ecmfile->fullpath_orig = ''; + $ecmfile->gen_or_uploaded = 'generated'; + $ecmfile->description = ''; // indexed content + $ecmfile->keyword = ''; // keyword content + $result = $ecmfile->create($user); + if ($result < 0) + { + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } + } + + /*$this->result['fullname']=$destfull; + $this->result['filepath']=$ecmfile->filepath; + $this->result['filename']=$ecmfile->filename;*/ + //var_dump($obj->update_main_doc_field);exit; + + // Update the last_main_doc field into main object (if documenent generator has property ->update_main_doc_field set) + $update_main_doc_field=0; + if (! empty($obj->update_main_doc_field)) $update_main_doc_field=1; + if ($update_main_doc_field && ! empty($this->table_element)) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element." SET last_main_doc = '".($ecmfile->filepath.'/'.$ecmfile->filename)."'"; + $sql.= ' WHERE rowid = '.$this->id; + $resql = $this->db->query($sql); + if (! $resql) dol_print_error($this->db); + } + } + } + else + { + dol_syslog('Method ->write_file was called on object '.get_class($obj).' and return a success but the return array ->result["fullpath"] was not set.', LOG_WARNING); + } + + // Success in building document. We build meta file. + dol_meta_create($this); + + return 1; + } + else + { + $outputlangs->charset_output=$sav_charset_output; + dol_print_error($this->db, "Error generating document for ".__CLASS__.". Error: ".$obj->error, $obj->errors); + return -1; + } + + } + else + { + $this->error=$langs->trans("Error")." ".$langs->trans("ErrorFileDoesNotExists",$file); + dol_print_error('',$this->error); + return -1; + } + } + + /** + * Build thumb + * + * @param string $file Path file in UTF8 to original file to create thumbs from. + * @return void + */ + function addThumbs($file) + { + global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini, $quality; + + require_once DOL_DOCUMENT_ROOT .'/core/lib/images.lib.php'; // This define also $maxwidthsmall, $quality, ... + + $file_osencoded=dol_osencode($file); + if (file_exists($file_osencoded)) + { + // Create small thumbs for company (Ratio is near 16/9) + // Used on logon for example + vignette($file_osencoded, $maxwidthsmall, $maxheightsmall, '_small', $quality); + + // Create mini thumbs for company (Ratio is near 16/9) + // Used on menu or for setup page for example + vignette($file_osencoded, $maxwidthmini, $maxheightmini, '_mini', $quality); + } + } + + + /* Functions common to commonobject and commonobjectline */ + + /* For default values */ + + /** + * Return the default value to use for a field when showing the create form of object. + * Return values in this order: + * 1) If parameter is available into POST, we return it first. + * 2) If not but an alternate value was provided as parameter of function, we return it. + * 3) If not but a constant $conf->global->OBJECTELEMENT_FIELDNAME is set, we return it (It is better to use the dedicated table). + * 4) Return value found into database (TODO No yet implemented) + * + * @param string $fieldname Name of field + * @param string $alternatevalue Alternate value to use + * @return string|string[] Default value (can be an array if the GETPOST return an array) + **/ + function getDefaultCreateValueFor($fieldname, $alternatevalue=null) + { + global $conf, $_POST; + + // If param here has been posted, we use this value first. + if (isset($_POST[$fieldname])) return GETPOST($fieldname, 2); + + if (isset($alternatevalue)) return $alternatevalue; + + $newelement=$this->element; + if ($newelement == 'facture') $newelement='invoice'; + if ($newelement == 'commande') $newelement='order'; + if (empty($newelement)) + { + dol_syslog("Ask a default value using common method getDefaultCreateValueForField on an object with no property ->element defined. Return empty string.", LOG_WARNING); + return ''; + } + + $keyforfieldname=strtoupper($newelement.'_DEFAULT_'.$fieldname); + //var_dump($keyforfieldname); + if (isset($conf->global->$keyforfieldname)) return $conf->global->$keyforfieldname; + + // TODO Ad here a scan into table llx_overwrite_default with a filter on $this->element and $fieldname + + } + + + /* For triggers */ + + + /** + * Call trigger based on this instance. + * Some context information may also be provided into array property this->context. + * NB: Error from trigger are stacked in interface->errors + * NB2: If return code of triggers are < 0, action calling trigger should cancel all transaction. + * + * @param string $trigger_name trigger's name to execute + * @param User $user Object user + * @return int Result of run_triggers + */ + function call_trigger($trigger_name, $user) + { + global $langs,$conf; + + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers($trigger_name,$this,$user,$langs,$conf); + + if ($result < 0) + { + if (!empty($this->errors)) + { + $this->errors=array_unique(array_merge($this->errors,$interface->errors)); // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice. + } + else + { + $this->errors=$interface->errors; + } + } + return $result; + } + + + /* Functions for extrafields */ + + + /** + * Function to get extra fields of an object into $this->array_options + * This method is in most cases called by method fetch of objects but you can call it separately. + * + * @param int $rowid Id of line. Use the id of object if not defined. Deprecated. Function must be called without parameters. + * @param array $optionsArray Array resulting of call of extrafields->fetch_name_optionals_label(). Deprecated. Function must be called without parameters. + * @return int <0 if error, 0 if no values of extrafield to find nor found, 1 if an attribute is found and value loaded + */ + function fetch_optionals($rowid=null, $optionsArray=null) + { + if (empty($rowid)) $rowid=$this->id; + + // To avoid SQL errors. Probably not the better solution though + if (!$this->table_element) { + return 0; + } + + if (! is_array($optionsArray)) + { + // If $extrafields is not a known object, we initialize it. Best practice is to have $extrafields defined into card.php or list.php page. + // TODO Use of existing extrafield is not yet ready (must mutualize code that use extrafields in form first) + // global $extrafields; + //if (! is_object($extrafields)) + //{ + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + //} + + // Load array of extrafields for elementype = $this->table_element + if (empty($extrafields->attributes[$this->table_element]['loaded'])) + { + $extrafields->fetch_name_optionals_label($this->table_element); + } + $optionsArray = $extrafields->attributes[$this->table_element]['label']; + } + + $table_element = $this->table_element; + if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility + + // Request to get complementary values + if (is_array($optionsArray) && count($optionsArray) > 0) + { + $sql = "SELECT rowid"; + foreach ($optionsArray as $name => $label) + { + if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate') + { + $sql.= ", ".$name; + } + } + $sql.= " FROM ".MAIN_DB_PREFIX.$table_element."_extrafields"; + $sql.= " WHERE fk_object = ".$rowid; + + dol_syslog(get_class($this)."::fetch_optionals get extrafields data for ".$this->table_element, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $numrows=$this->db->num_rows($resql); + if ($numrows) + { + $tab = $this->db->fetch_array($resql); + + foreach ($tab as $key => $value) + { + // Test fetch_array ! is_int($key) because fetch_array result is a mix table with Key as alpha and Key as int (depend db engine) + if ($key != 'rowid' && $key != 'tms' && $key != 'fk_member' && ! is_int($key)) + { + // we can add this attribute to object + $this->array_options["options_".$key]=$value; + } + } + } + + $this->db->free($resql); + + if ($numrows) return $numrows; + else return 0; + } + else + { + dol_print_error($this->db); + return -1; + } + } + return 0; + } + + /** + * Delete all extra fields values for the current object. + * + * @return int <0 if KO, >0 if OK + */ + function deleteExtraFields() + { + $this->db->begin(); + + $table_element = $this->table_element; + if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility + + $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id; + dol_syslog(get_class($this)."::deleteExtraFields delete", LOG_DEBUG); + $resql=$this->db->query($sql_del); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + else + { + $this->db->commit(); + return 1; + } + } + + /** + * Add/Update all extra fields values for the current object. + * Data to describe values to insert/update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) + * This function delete record with all extrafields and insert them again from the array $this->array_options. + * + * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY) + * @param User $userused Object user + * @return int -1=error, O=did nothing, 1=OK + * @see updateExtraField, setValueFrom + */ + function insertExtraFields($trigger='', $userused=null) + { + global $conf,$langs,$user; + + if (empty($userused)) $userused=$user; + + $error=0; + + if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0; // For avoid conflicts if trigger used + + if (! empty($this->array_options)) + { + // Check parameters + $langs->load('admin'); + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element); + + //Eliminate copied source object extra_fields that do not exist in target object + $new_array_options=array(); + foreach ($this->array_options as $key => $value) { + if (in_array(substr($key,8), array_keys($target_extrafields))) // We remove the 'options_' from $key for test + $new_array_options[$key] = $value; + elseif (in_array($key, array_keys($target_extrafields))) // We test on $key that does not contains the 'options_' prefix + $new_array_options['options_'.$key] = $value; + } + + foreach($new_array_options as $key => $value) + { + $attributeKey = substr($key,8); // Remove 'options_' prefix + $attributeType = $extrafields->attribute_type[$attributeKey]; + $attributeLabel = $extrafields->attribute_label[$attributeKey]; + $attributeParam = $extrafields->attribute_param[$attributeKey]; + $attributeRequired = $extrafields->attribute_required[$attributeKey]; + + if ($attributeRequired) + { + $mandatorypb=false; + if ($attributeType == 'link' && $this->array_options[$key] == '-1') $mandatorypb=true; + if ($this->array_options[$key] === '') $mandatorypb=true; + if ($mandatorypb) + { + $this->errors[]=$langs->trans('ErrorFieldRequired', $attributeLabel); + return -1; + } + } + + switch ($attributeType) + { + case 'int': + if (!is_numeric($value) && $value!='') + { + $this->errors[]=$langs->trans("ExtraFieldHasWrongValue", $attributeLabel); + return -1; + } + elseif ($value=='') + { + $new_array_options[$key] = null; + } + break; + /*case 'select': // Not required, we chosed value='0' for undefined values + if ($value=='-1') + { + $this->array_options[$key] = null; + } + break;*/ + case 'price': + $new_array_options[$key] = price2num($this->array_options[$key]); + break; + case 'date': + $new_array_options[$key] = $this->db->idate($this->array_options[$key]); + break; + case 'datetime': + $new_array_options[$key] = $this->db->idate($this->array_options[$key]); + break; + case 'link': + $param_list=array_keys($attributeParam['options']); + // 0 : ObjectName + // 1 : classPath + $InfoFieldList = explode(":", $param_list[0]); + dol_include_once($InfoFieldList[1]); + if ($InfoFieldList[0] && class_exists($InfoFieldList[0])) + { + if ($value == '-1') // -1 is key for no defined in combo list of objects + { + $new_array_options[$key]=''; + } + elseif ($value) + { + $object = new $InfoFieldList[0]($this->db); + if (is_numeric($value)) $res=$object->fetch($value); + else $res=$object->fetch('',$value); + + if ($res > 0) $new_array_options[$key]=$object->id; + else + { + $this->error="Id/Ref '".$value."' for object '".$object->element."' not found"; + $this->db->rollback(); + return -1; + } + } + } + else + { + dol_syslog('Error bad setup of extrafield', LOG_WARNING); + } + break; + } + } + + $this->db->begin(); + + $table_element = $this->table_element; + if ($table_element == 'categorie') $table_element = 'categories'; // For compatibility + + $sql_del = "DELETE FROM ".MAIN_DB_PREFIX.$table_element."_extrafields WHERE fk_object = ".$this->id; + dol_syslog(get_class($this)."::insertExtraFields delete", LOG_DEBUG); + $this->db->query($sql_del); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX.$table_element."_extrafields (fk_object"; + foreach($new_array_options as $key => $value) + { + $attributeKey = substr($key,8); // Remove 'options_' prefix + // Add field of attribut + if ($extrafields->attribute_type[$attributeKey] != 'separate') // Only for other type of separate + $sql.=",".$attributeKey; + } + $sql .= ") VALUES (".$this->id; + + foreach($new_array_options as $key => $value) + { + $attributeKey = substr($key,8); // Remove 'options_' prefix + // Add field o fattribut + if($extrafields->attribute_type[$attributeKey] != 'separate') // Only for other type of separate) + { + if ($new_array_options[$key] != '') + { + $sql.=",'".$this->db->escape($new_array_options[$key])."'"; + } + else + { + $sql.=",null"; + } + } + } + $sql.=")"; + + dol_syslog(get_class($this)."::insertExtraFields insert", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $error++; + } + + if (! $error && $trigger) + { + // Call trigger + $this->context=array('extrafieldaddupdate'=>1); + $result=$this->call_trigger($trigger, $userused); + if ($result < 0) $error++; + // End call trigger + } + + if ($error) + { + $this->db->rollback(); + return -1; + } + else + { + $this->db->commit(); + return 1; + } + } + else return 0; + } + + /** + * Update an exta field value for the current object. + * Data to describe values to update are stored into $this->array_options=array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) + * + * @param string $key Key of the extrafield + * @param string $trigger If defined, call also the trigger (for example COMPANY_MODIFY) + * @param User $userused Object user + * @return int -1=error, O=did nothing, 1=OK + * @see setValueFrom + */ + function updateExtraField($key, $trigger, $userused) + { + global $conf,$langs,$user; + + if (empty($userused)) $userused=$user; + + $error=0; + + if (! empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return 0; // For avoid conflicts if trigger used + + if (! empty($this->array_options) && isset($this->array_options["options_".$key])) + { + // Check parameters + $langs->load('admin'); + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $target_extrafields=$extrafields->fetch_name_optionals_label($this->table_element); + + $value=$this->array_options["options_".$key]; + $attributeType = $extrafields->attribute_type[$key]; + $attributeLabel = $extrafields->attribute_label[$key]; + $attributeParam = $extrafields->attribute_param[$key]; + switch ($attributeType) + { + case 'int': + if (!is_numeric($value) && $value!='') + { + $this->errors[]=$langs->trans("ExtraFieldHasWrongValue",$attributeLabel); + return -1; + } + elseif ($value=='') + { + $this->array_options["options_".$key] = null; + } + break; + /*case 'select': // Not required, we chosed value='0' for undefined values + if ($value=='-1') + { + $this->array_options[$key] = null; + } + break;*/ + case 'price': + $this->array_options["options_".$key] = price2num($this->array_options["options_".$key]); + break; + case 'date': + $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]); + break; + case 'datetime': + $this->array_options["options_".$key]=$this->db->idate($this->array_options["options_".$key]); + break; + case 'link': + $param_list=array_keys($attributeParam ['options']); + // 0 : ObjectName + // 1 : classPath + $InfoFieldList = explode(":", $param_list[0]); + dol_include_once($InfoFieldList[1]); + if ($value) + { + $object = new $InfoFieldList[0]($this->db); + $object->fetch(0,$value); + $this->array_options["options_".$key]=$object->id; + } + break; + } + + $this->db->begin(); + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element."_extrafields SET ".$key."='".$this->db->escape($this->array_options["options_".$key])."'"; + $sql .= " WHERE fk_object = ".$this->id; + $resql = $this->db->query($sql); + if (! $resql) + { + $error++; + $this->error=$this->db->lasterror(); + } + + if (! $error && $trigger) + { + // Call trigger + $this->context=array('extrafieldupdate'=>1); + $result=$this->call_trigger($trigger, $userused); + if ($result < 0) $error++; + // End call trigger + } + + if ($error) + { + $this->db->rollback(); + return -1; + } + else + { + $this->db->commit(); + return 1; + } + } + else return 0; + } + + + /** + * Return HTML string to put an input field into a page + * Code very similar with showInputField of extra fields + * + * @param array $val Array of properties for field to show + * @param string $key Key of attribute + * @param string $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value) + * @param string $moreparam To add more parametes on html input tag + * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names) + * @param string|int $showsize Value for css to define size. May also be a numeric. + * @return string + */ + function showInputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0) + { + global $conf,$langs,$form; + + if (! is_object($form)) + { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; + $form=new Form($this->db); + } + + $objectid = $this->id; + + $label= $val['label']; + $type = $val['type']; + $size = $val['css']; + + // Convert var to be able to share same code than showInputField of extrafields + if (preg_match('/varchar\((\d+)\)/', $type, $reg)) + { + $type = 'varchar'; // convert varchar(xx) int varchar + $size = $reg[1]; + } + elseif (preg_match('/varchar/', $type)) $type = 'varchar'; // convert varchar(xx) int varchar + if (is_array($val['arrayofkeyval'])) $type='select'; + if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link'; + + //$elementtype=$this->attribute_elementtype[$key]; // seems to not be used + $default=$val['default']; + $computed=$val['computed']; + $unique=$val['unique']; + $required=$val['required']; + $param=$val['param']; + if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval']; + if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) + { + $type='link'; + $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]); + } + $langfile=$val['langfile']; + $list=$val['list']; + $hidden=(abs($val['visible'])!=1 ? 1 : 0); + $help=$val['help']; + + if ($computed) + { + if (! preg_match('/^search_/', $keyprefix)) return ''.$langs->trans("AutomaticallyCalculated").''; + else return ''; + } + + // Use in priorit showsize from parameters, then $val['css'] then autodefine + if (empty($showsize) && ! empty($val['css'])) + { + $showsize = $val['css']; + } + if (empty($showsize)) + { + if ($type == 'date') + { + //$showsize=10; + $showsize = 'minwidth100imp'; + } + elseif ($type == 'datetime') + { + //$showsize=19; + $showsize = 'minwidth200imp'; + } + elseif (in_array($type,array('int','double','price'))) + { + //$showsize=10; + $showsize = 'maxwidth75'; + } + elseif ($type == 'url') + { + $showsize='minwidth400'; + } + elseif ($type == 'boolean') + { + $showsize=''; + } + else + { + if (round($size) < 12) + { + $showsize = 'minwidth100'; + } + else if (round($size) <= 48) + { + $showsize = 'minwidth200'; + } + else + { + //$showsize=48; + $showsize = 'minwidth400'; + } + } + } + //var_dump($showsize.' '.$size); + + if (in_array($type,array('date','datetime'))) + { + $tmp=explode(',',$size); + $newsize=$tmp[0]; + + $showtime = in_array($type,array('datetime')) ? 1 : 0; + + // Do not show current date when field not required (see select_date() method) + if (!$required && $value == '') $value = '-1'; + + // TODO Must also support $moreparam + $out = $form->select_date($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, ($keyprefix != 'search_' ? 1 : 0), 1, 0, 1); + } + elseif (in_array($type,array('int','integer'))) + { + $tmp=explode(',',$size); + $newsize=$tmp[0]; + $out=''; + } + elseif (preg_match('/varchar/', $type)) + { + $out=''; + } + elseif (in_array($type, array('mail', 'phone', 'url'))) + { + $out=''; + } + elseif ($type == 'text') + { + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,0,ROWS_5,'90%'); + $out=$doleditor->Create(1); + } + elseif ($type == 'html') + { + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($keyprefix.$key.$keysuffix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%'); + $out=$doleditor->Create(1); + } + elseif ($type == 'boolean') + { + $checked=''; + if (!empty($value)) { + $checked=' checked value="1" '; + } else { + $checked=' value="1" '; + } + $out=''; + } + elseif ($type == 'price') + { + if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format. + $value=price($value); + } + $out=' '.$langs->getCurrencySymbol($conf->currency); + } + elseif ($type == 'double') + { + if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format. + $value=price($value); + } + $out=' '; + } + elseif ($type == 'select') + { + $out = ''; + if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) + { + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; + $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0); + } + + $out.=''; + } + elseif ($type == 'sellist') + { + $out = ''; + if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2)) + { + include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; + $out.= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0); + } + + $out.=''; + } + elseif ($type == 'checkbox') + { + $value_arr=explode(',',$value); + $out=$form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options'])?null:$param['options']), $value_arr, '', 0, '', 0, '100%'); + } + elseif ($type == 'radio') + { + $out=''; + foreach ($param['options'] as $keyopt => $val) + { + $out.=''.$val.'
'; + } + } + elseif ($type == 'chkbxlst') + { + if (is_array($value)) { + $value_arr = $value; + } + else { + $value_arr = explode(',', $value); + } + + if (is_array($param['options'])) { + $param_list = array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + // 0 : tableName + // 1 : label field name + // 2 : key fields name (if differ of rowid) + // 3 : key field parent (for dependent lists) + // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value + $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid'); + + if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) { + list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]); + $keyList .= ', ' . $parentField; + } + if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) { + if (strpos($InfoFieldList[4], 'extra.') !== false) { + $keyList = 'main.' . $InfoFieldList[2] . ' as rowid'; + } else { + $keyList = $InfoFieldList[2] . ' as rowid'; + } + } + + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $keyList .= ', '; + $keyList .= implode(', ', $fields_label); + } + + $sqlwhere = ''; + $sql = 'SELECT ' . $keyList; + $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0]; + if (! empty($InfoFieldList[4])) { + + // can use SELECT request + if (strpos($InfoFieldList[4], '$SEL$')!==false) { + $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]); + } + + // current object id can be use into filter + if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) { + $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]); + } else { + $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]); + } + + // We have to join on extrafield table + if (strpos($InfoFieldList[4], 'extra') !== false) { + $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra'; + $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4]; + } else { + $sqlwhere .= ' WHERE ' . $InfoFieldList[4]; + } + } else { + $sqlwhere .= ' WHERE 1=1'; + } + // Some tables may have field, some other not. For the moment we disable it. + if (in_array($InfoFieldList[0], array ('tablewithentity'))) + { + $sqlwhere .= ' AND entity = ' . $conf->entity; + } + // $sql.=preg_replace('/^ AND /','',$sqlwhere); + // print $sql; + + $sql .= $sqlwhere; + dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + + $data=array(); + + while ( $i < $num ) { + $labeltoshow = ''; + $obj = $this->db->fetch_object($resql); + + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $notrans = true; + foreach ( $fields_label as $field_toshow ) { + $labeltoshow .= $obj->$field_toshow . ' '; + } + } else { + $labeltoshow = $obj->{$InfoFieldList[1]}; + } + $labeltoshow = dol_trunc($labeltoshow, 45); + + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + foreach ( $fields_label as $field_toshow ) { + $translabel = $langs->trans($obj->$field_toshow); + if ($translabel != $obj->$field_toshow) { + $labeltoshow = dol_trunc($translabel, 18) . ' '; + } else { + $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' '; + } + } + + $data[$obj->rowid]=$labeltoshow; + + } else { + if (! $notrans) { + $translabel = $langs->trans($obj->{$InfoFieldList[1]}); + if ($translabel != $obj->{$InfoFieldList[1]}) { + $labeltoshow = dol_trunc($translabel, 18); + } else { + $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18); + } + } + if (empty($labeltoshow)) + $labeltoshow = '(not defined)'; + + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + $data[$obj->rowid]=$labeltoshow; + } + + if (! empty($InfoFieldList[3])) { + $parent = $parentName . ':' . $obj->{$parentField}; + } + + $data[$obj->rowid]=$labeltoshow; + } + + $i ++; + } + $this->db->free($resql); + + $out=$form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%'); + + } else { + print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.
'; + } + } + $out .= ''; + } + elseif ($type == 'link') + { + $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' + $showempty=(($val['notnull'] == 1 && $val['default'] != '')?0:1); + $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty); + } + elseif ($type == 'password') + { + // If prefix is 'search_', field is used as a filter, we use a common text field. + $out=''; + } + if (!empty($hidden)) { + $out=''; + } + /* Add comments + if ($type == 'date') $out.=' (YYYY-MM-DD)'; + elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)'; + */ + return $out; + } + + + /** + * Return HTML string to show a field into a page + * Code very similar with showOutputField of extra fields + * + * @param array $val Array of properties of field to show + * @param string $key Key of attribute + * @param string $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value) + * @param string $moreparam To add more parametes on html input tag + * @param string $keysuffix Prefix string to add into name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Suffix string to add into name and id of field (can be used to avoid duplicate names) + * @param mixed $showsize Value for css to define size. May also be a numeric. + * @return string + */ + function showOutputField($val, $key, $value, $moreparam='', $keysuffix='', $keyprefix='', $showsize=0) + { + global $conf,$langs,$form; + + if (! is_object($form)) + { + require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; + $form=new Form($this->db); + } + + $objectid = $this->id; + $label = $val['label']; + $type = $val['type']; + $size = $val['css']; + + // Convert var to be able to share same code than showOutputField of extrafields + if (preg_match('/varchar\((\d+)\)/', $type, $reg)) + { + $type = 'varchar'; // convert varchar(xx) int varchar + $size = $reg[1]; + } + elseif (preg_match('/varchar/', $type)) $type = 'varchar'; // convert varchar(xx) int varchar + if (is_array($val['arrayofkeyval'])) $type='select'; + if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) $type='link'; + + //$elementtype=$this->attribute_elementtype[$key]; // seems to not be used + $default=$val['default']; + $computed=$val['computed']; + $unique=$val['unique']; + $required=$val['required']; + $param=$val['param']; + if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval']; + if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) + { + $type='link'; + $param['options']=array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]); + } + $langfile=$val['langfile']; + $list=$val['list']; + $help=$val['help']; + $hidden=(($val['visible'] == 0) ? 1 : 0); // If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) + + if ($hidden) return ''; + + // If field is a computed field, value must become result of compute + if ($computed) + { + // Make the eval of compute string + //var_dump($computed); + $value = dol_eval($computed, 1, 0); + } + + if (empty($showsize)) + { + if ($type == 'date') + { + //$showsize=10; + $showsize = 'minwidth100imp'; + } + elseif ($type == 'datetime') + { + //$showsize=19; + $showsize = 'minwidth200imp'; + } + elseif (in_array($type,array('int','double','price'))) + { + //$showsize=10; + $showsize = 'maxwidth75'; + } + elseif ($type == 'url') + { + $showsize='minwidth400'; + } + elseif ($type == 'boolean') + { + $showsize=''; + } + else + { + if (round($size) < 12) + { + $showsize = 'minwidth100'; + } + else if (round($size) <= 48) + { + $showsize = 'minwidth200'; + } + else + { + //$showsize=48; + $showsize = 'minwidth400'; + } + } + } + + // Format output value differently according to properties of field + if ($key == 'ref' && method_exists($this, 'getNomUrl')) $value=$this->getNomUrl(1, '', 0, '', 1); + elseif ($key == 'status' && method_exists($this, 'getLibStatut')) $value=$this->getLibStatut(3); + elseif ($type == 'date') + { + $value=dol_print_date($value,'day'); + } + elseif ($type == 'datetime') + { + $value=dol_print_date($value,'dayhour'); + } + elseif ($type == 'double') + { + if (!empty($value)) { + $value=price($value); + } + } + elseif ($type == 'boolean') + { + $checked=''; + if (!empty($value)) { + $checked=' checked '; + } + $value=''; + } + elseif ($type == 'mail') + { + $value=dol_print_email($value,0,0,0,64,1,1); + } + elseif ($type == 'url') + { + $value=dol_print_url($value,'_blank',32,1); + } + elseif ($type == 'phone') + { + $value=dol_print_phone($value, '', 0, 0, '', ' ', 1); + } + elseif ($type == 'price') + { + $value=price($value,0,$langs,0,0,-1,$conf->currency); + } + elseif ($type == 'select') + { + $value=$param['options'][$value]; + } + elseif ($type == 'sellist') + { + $param_list=array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + + $selectkey="rowid"; + $keyList='rowid'; + + if (count($InfoFieldList)>=3) + { + $selectkey = $InfoFieldList[2]; + $keyList=$InfoFieldList[2].' as rowid'; + } + + $fields_label = explode('|',$InfoFieldList[1]); + if(is_array($fields_label)) { + $keyList .=', '; + $keyList .= implode(', ', $fields_label); + } + + $sql = 'SELECT '.$keyList; + $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0]; + if (strpos($InfoFieldList[4], 'extra')!==false) + { + $sql.= ' as main'; + } + if ($selectkey=='rowid' && empty($value)) { + $sql.= " WHERE ".$selectkey."=0"; + } elseif ($selectkey=='rowid') { + $sql.= " WHERE ".$selectkey."=".$this->db->escape($value); + }else { + $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'"; + } + + //$sql.= ' AND entity = '.$conf->entity; + + dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $value=''; // value was used, so now we reste it to use it to build final output + + $obj = $this->db->fetch_object($resql); + + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|',$InfoFieldList[1]); + + if(is_array($fields_label) && count($fields_label)>1) + { + foreach ($fields_label as $field_toshow) + { + $translabel=''; + if (!empty($obj->$field_toshow)) { + $translabel=$langs->trans($obj->$field_toshow); + } + if ($translabel!=$field_toshow) { + $value.=dol_trunc($translabel,18).' '; + }else { + $value.=$obj->$field_toshow.' '; + } + } + } + else + { + $translabel=''; + if (!empty($obj->{$InfoFieldList[1]})) { + $translabel=$langs->trans($obj->{$InfoFieldList[1]}); + } + if ($translabel!=$obj->{$InfoFieldList[1]}) { + $value=dol_trunc($translabel,18); + }else { + $value=$obj->{$InfoFieldList[1]}; + } + } + } + else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING); + } + elseif ($type == 'radio') + { + $value=$param['options'][$value]; + } + elseif ($type == 'checkbox') + { + $value_arr=explode(',',$value); + $value=''; + if (is_array($value_arr)) + { + foreach ($value_arr as $keyval=>$valueval) { + $toprint[]='
  • '.$param['options'][$valueval].'
  • '; + } + } + $value='
      '.implode(' ', $toprint).'
    '; + } + elseif ($type == 'chkbxlst') + { + $value_arr = explode(',', $value); + + $param_list = array_keys($param['options']); + $InfoFieldList = explode(":", $param_list[0]); + + $selectkey = "rowid"; + $keyList = 'rowid'; + + if (count($InfoFieldList) >= 3) { + $selectkey = $InfoFieldList[2]; + $keyList = $InfoFieldList[2] . ' as rowid'; + } + + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($fields_label)) { + $keyList .= ', '; + $keyList .= implode(', ', $fields_label); + } + + $sql = 'SELECT ' . $keyList; + $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0]; + if (strpos($InfoFieldList[4], 'extra') !== false) { + $sql .= ' as main'; + } + // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'"; + // $sql.= ' AND entity = '.$conf->entity; + + dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $value = ''; // value was used, so now we reste it to use it to build final output + $toprint=array(); + while ( $obj = $this->db->fetch_object($resql) ) { + + // Several field into label (eq table:code|libelle:rowid) + $fields_label = explode('|', $InfoFieldList[1]); + if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) { + if (is_array($fields_label) && count($fields_label) > 1) { + foreach ( $fields_label as $field_toshow ) { + $translabel = ''; + if (! empty($obj->$field_toshow)) { + $translabel = $langs->trans($obj->$field_toshow); + } + if ($translabel != $field_toshow) { + $toprint[]='
  • '.dol_trunc($translabel, 18).'
  • '; + } else { + $toprint[]='
  • '.$obj->$field_toshow.'
  • '; + } + } + } else { + $translabel = ''; + if (! empty($obj->{$InfoFieldList[1]})) { + $translabel = $langs->trans($obj->{$InfoFieldList[1]}); + } + if ($translabel != $obj->{$InfoFieldList[1]}) { + $toprint[]='
  • '.dol_trunc($translabel, 18).'
  • '; + } else { + $toprint[]='
  • '.$obj->{$InfoFieldList[1]}.'
  • '; + } + } + } + } + $value='
      '.implode(' ', $toprint).'
    '; + + } else { + dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING); + } + } + elseif ($type == 'link') + { + $out=''; + + // only if something to display (perf) + if ($value) + { + $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' + + $InfoFieldList = explode(":", $param_list[0]); + $classname=$InfoFieldList[0]; + $classpath=$InfoFieldList[1]; + if (! empty($classpath)) + { + dol_include_once($InfoFieldList[1]); + if ($classname && class_exists($classname)) + { + $object = new $classname($this->db); + $object->fetch($value); + $value=$object->getNomUrl(3); + } + } + else + { + dol_syslog('Error bad setup of extrafield', LOG_WARNING); + return 'Error bad setup of extrafield'; + } + } + } + elseif ($type == 'text' || $type == 'html') + { + $value=dol_htmlentitiesbr($value); + } + elseif ($type == 'password') + { + $value=preg_replace('/./i','*',$value); + } + + //print $type.'-'.$size; + $out=$value; + + return $out; + } + + + /** + * Function to show lines of extrafields with output datas + * + * @param Extrafields $extrafields Extrafield Object + * @param string $mode Show output (view) or input (edit) for extrafield + * @param array $params Optional parameters + * @param string $keysuffix Suffix string to add after name and id of field (can be used to avoid duplicate names) + * @param string $keyprefix Prefix string to add before name and id of field (can be used to avoid duplicate names) + * + * @return string + */ + function showOptionals($extrafields, $mode='view', $params=null, $keysuffix='', $keyprefix='') + { + global $_POST, $conf, $langs, $action; + + $out = ''; + + if (count($extrafields->attribute_label) > 0) + { + $out .= "\n"; + $out .= ' '; + $out .= "\n"; + + $e = 0; + foreach($extrafields->attribute_label as $key=>$label) + { + if (empty($extrafields->attribute_list[$key])) continue; // 0 = Never visible field + if (($mode == 'create' || $mode == 'edit') && abs($extrafields->attribute_list[$key]) != 1 && abs($extrafields->attribute_list[$key]) != 3) continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list + + // Load language if required + if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]); + + if (is_array($params) && count($params)>0) { + if (array_key_exists('colspan',$params)) { + $colspan=$params['colspan']; + } + }else { + $colspan='3'; + } + + switch($mode) { + case "view": + $value=$this->array_options["options_".$key.$keysuffix]; + break; + case "edit": + $getposttemp = GETPOST($keyprefix.'options_'.$key.$keysuffix, 'none'); // GETPOST can get value from GET, POST or setup of default values. + // GETPOST("options_" . $key) can be 'abc' or array(0=>'abc') + if (is_array($getposttemp) || $getposttemp != '' || GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)) + { + if (is_array($getposttemp)) { + // $getposttemp is an array but following code expects a comma separated string + $value = implode(",", $getposttemp); + } else { + $value = $getposttemp; + } + } else { + $value = $this->array_options["options_" . $key]; // No GET, no POST, no default value, so we take value of object. + } + break; + } + //var_dump($value); + + if ($extrafields->attribute_type[$key] == 'separate') + { + $out .= $extrafields->showSeparator($key); + } + else + { + $csstyle=''; + $class=(!empty($extrafields->attribute_hidden[$key]) ? 'class="hideobject" ' : ''); + if (is_array($params) && count($params)>0) { + if (array_key_exists('style',$params)) { + $csstyle=$params['style']; + } + } + if ( !empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && ($e % 2) == 0) + { + $out .= ''; + $colspan='0'; + } + else + { + $out .= ''; + } + // Convert date into timestamp format (value in memory must be a timestamp) + if (in_array($extrafields->attribute_type[$key],array('date','datetime'))) + { + $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?dol_mktime(GETPOST($keyprefix.'options_'.$key.$keysuffix."hour",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."min",'int',3), 0, GETPOST($keyprefix.'options_'.$key.$keysuffix."month",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."day",'int',3), GETPOST($keyprefix.'options_'.$key.$keysuffix."year",'int',3)):$this->db->jdate($this->array_options['options_'.$key]); + } + // Convert float submited string into real php numeric (value in memory must be a php numeric) + if (in_array($extrafields->attribute_type[$key],array('price','double'))) + { + $value = GETPOSTISSET($keyprefix.'options_'.$key.$keysuffix)?price2num(GETPOST($keyprefix.'options_'.$key.$keysuffix,'int',3)):$this->array_options['options_'.$key]; + } + + $labeltoshow = $langs->trans($label); + + if($extrafields->attribute_required[$key]) + { + $labeltoshow = ''.$labeltoshow.''; + } + $out .= ''; + + $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : ''; + $out .=''; + + if (! empty($conf->global->MAIN_EXTRAFIELDS_USE_TWO_COLUMS) && (($e % 2) == 1)) $out .= ''; + else $out .= ''; + $e++; + } + } + $out .= "\n"; + // Add code to manage list depending on others + if (! empty($conf->use_javascript_ajax)) { + $out .= ' + '."\n"; + $out .= ' '."\n"; + } + } + return $out; + } + + + /** + * Returns the rights used for this class + * @return stdClass + */ + public function getRights() + { + global $user; + + $element = $this->element; + if ($element == 'facturerec') $element='facture'; + + return $user->rights->{$element}; + } + + /** + * Function used to replace a thirdparty id with another one. + * This function is meant to be called from replaceThirdparty with the appropiate tables + * Column name fk_soc MUST be used to identify thirdparties + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id (the thirdparty to delete) + * @param int $dest_id New thirdparty id (the thirdparty that will received element of the other) + * @param string[] $tables Tables that need to be changed + * @param int $ignoreerrors Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old thirdparty may already exists on new one) + * @return bool True if success, False if error + */ + public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0) + { + foreach ($tables as $table) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id; + + if (! $db->query($sql)) + { + if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B. + //$this->errors = $db->lasterror(); + return false; + } + } + + return true; + } + + /** + * Get buy price to use for margin calculation. This function is called when buy price is unknown. + * Set buy price = sell price if ForceBuyingPriceIfNull configured, + * else if calculation MARGIN_TYPE = 'costprice' and costprice is defined, use costprice as buyprice + * else if calculation MARGIN_TYPE = 'pmp' and pmp is calculated, use pmp as buyprice + * else set min buy price as buy price + * + * @param float $unitPrice Product unit price + * @param float $discountPercent Line discount percent + * @param int $fk_product Product id + * @return float <0 if KO, buyprice if OK + */ + public function defineBuyPrice($unitPrice = 0.0, $discountPercent = 0.0, $fk_product = 0) + { + global $conf; + + $buyPrice = 0; + + if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false + { + $buyPrice = $unitPrice * (1 - $discountPercent / 100); + } + else + { + // Get cost price for margin calculation + if (! empty($fk_product)) + { + if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'costprice') + { + require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($result <= 0) + { + $this->errors[] = 'ErrorProductIdDoesNotExists'; + return -1; + } + if ($product->cost_price > 0) + { + $buyPrice = $product->cost_price; + } + else if ($product->pmp > 0) + { + $buyPrice = $product->pmp; + } + } + else if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == 'pmp') + { + require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + $product = new Product($this->db); + $result = $product->fetch($fk_product); + if ($result <= 0) + { + $this->errors[] = 'ErrorProductIdDoesNotExists'; + return -1; + } + if ($product->pmp > 0) + { + $buyPrice = $product->pmp; + } + } + + if (empty($buyPrice) && isset($conf->global->MARGIN_TYPE) && in_array($conf->global->MARGIN_TYPE, array('1','pmp','costprice'))) + { + require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; + $productFournisseur = new ProductFournisseur($this->db); + if (($result = $productFournisseur->find_min_price_product_fournisseur($fk_product)) > 0) + { + $buyPrice = $productFournisseur->fourn_unitprice; + } + else if ($result < 0) + { + $this->errors[] = $productFournisseur->error; + return -2; + } + } + } + } + return $buyPrice; + } + + + + /** + * Function test if type is array + * + * @param array $info content informations of field + * @return bool + */ + protected function isArray($info) + { + if(is_array($info)) + { + if(isset($info['type']) && $info['type']=='array') return true; + else return false; + } + else return false; + } + + /** + * Function test if type is null + * + * @param array $info content informations of field + * @return bool + */ + protected function isNull($info) + { + if(is_array($info)) + { + if(isset($info['type']) && $info['type']=='null') return true; + else return false; + } + else return false; + } + + + /** + * Function test if type is date + * + * @param array $info content informations of field + * @return bool + */ + public function isDate($info) + { + if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true; + else return false; + } + + /** + * Function test if type is integer + * + * @param array $info content informations of field + * @return bool + */ + public function isInt($info) + { + if(is_array($info)) + { + if(isset($info['type']) && ($info['type']=='int' || $info['type']=='integer' )) return true; + else return false; + } + else return false; + } + + /** + * Function test if type is float + * + * @param array $info content informations of field + * @return bool + */ + public function isFloat($info) + { + if(is_array($info)) + { + if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true; + else return false; + } + else return false; + } + + /** + * Function test if type is text + * + * @param array $info content informations of field + * @return bool + */ + public function isText($info) + { + if(is_array($info)) + { + if(isset($info['type']) && $info['type']=='text') return true; + else return false; + } + else return false; + } + + /** + * Function test if is indexed + * + * @param array $info content informations of field + * @return bool + */ + protected function isIndex($info) + { + if(is_array($info)) + { + if(isset($info['index']) && $info['index']==true) return true; + else return false; + } + else return false; + } + + /** + * Function to prepare the values to insert. + * Note $this->${field} are set by the page that make the createCommon or the updateCommon. + * + * @return array + */ + private function set_save_query() + { + global $conf; + + $queryarray=array(); + foreach ($this->fields as $field=>$info) // Loop on definition of fields + { + // Depending on field type ('datetime', ...) + if($this->isDate($info)) + { + if(empty($this->{$field})) + { + $queryarray[$field] = NULL; + } + else + { + $queryarray[$field] = $this->db->idate($this->{$field}); + } + } + else if($this->isArray($info)) + { + $queryarray[$field] = serialize($this->{$field}); + } + else if($this->isInt($info)) + { + if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity; + else + { + $queryarray[$field] = (int) price2num($this->{$field}); + if (empty($queryarray[$field])) $queryarray[$field]=0; // May be reset to null later if property 'notnull' is -1 for this field. + } + } + else if($this->isFloat($info)) + { + $queryarray[$field] = (double) price2num($this->{$field}); + if (empty($queryarray[$field])) $queryarray[$field]=0; + } + else + { + $queryarray[$field] = $this->{$field}; + } + + if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]); + if (! empty($info['notnull']) && $info['notnull'] == -1 && empty($queryarray[$field])) $queryarray[$field] = null; + } + + return $queryarray; + } + + /** + * Function to load data from a SQL pointer into properties of current object $this + * + * @param stdClass $obj Contain data of object from database + */ + private function setVarsFromFetchObj(&$obj) + { + foreach ($this->fields as $field => $info) + { + if($this->isDate($info)) + { + if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0; + else $this->{$field} = strtotime($obj->{$field}); + } + elseif($this->isArray($info)) + { + $this->{$field} = @unserialize($obj->{$field}); + // Hack for data not in UTF8 + if($this->{$field } === FALSE) @unserialize(utf8_decode($obj->{$field})); + } + elseif($this->isInt($info)) + { + if ($field == 'rowid') $this->id = (int) $obj->{$field}; + else $this->{$field} = (int) $obj->{$field}; + } + elseif($this->isFloat($info)) + { + $this->{$field} = (double) $obj->{$field}; + } + elseif($this->isNull($info)) + { + $val = $obj->{$field}; + // zero is not null + $this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val); + } + else + { + $this->{$field} = $obj->{$field}; + } + } + + // If there is no 'ref' field, we force property ->ref to ->id for a better compatibility with common functions. + if (! isset($this->fields['ref']) && isset($this->id)) $this->ref = $this->id; + } + + /** + * Function to concat keys of fields + * + * @return string + */ + private function get_field_list() + { + $keys = array_keys($this->fields); + return implode(',', $keys); + } + + /** + * Add quote to field value if necessary + * + * @param string|int $value Value to protect + * @param array $fieldsentry Properties of field + * @return string + */ + protected function quote($value, $fieldsentry) { + if (is_null($value)) return 'NULL'; + else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value"); + else return "'".$this->db->escape($value)."'"; + } + + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function createCommon(User $user, $notrigger = false) + { + global $langs; + + $error = 0; + + $now=dol_now(); + + $fieldvalues = $this->set_save_query(); + if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now); + if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id; + unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into insert. + + $keys=array(); + $values = array(); + foreach ($fieldvalues as $k => $v) { + $keys[$k] = $k; + $value = $this->fields[$k]; + $values[$k] = $this->quote($v, $value); + } + + // Clean and check mandatory + foreach($keys as $key) + { + // If field is an implicit foreign key field + if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]=''; + if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]=''; + + //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1)); + if ($this->fields[$key]['notnull'] == 1 && ! isset($values[$key])) + { + $error++; + $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']); + } + + // If field is an implicit foreign key field + if (preg_match('/^integer:/i', $this->fields[$key]['type']) && empty($values[$key])) $values[$key]='null'; + if (! empty($this->fields[$key]['foreignkey']) && empty($values[$key])) $values[$key]='null'; + } + + if ($error) return -1; + + $this->db->begin(); + + if (! $error) + { + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element; + $sql.= ' ('.implode( ", ", $keys ).')'; + $sql.= ' VALUES ('.implode( ", ", $values ).')'; + + $res = $this->db->query($sql); + if ($res===false) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + if (! $error) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); + } + + // Create extrafields + if (! $error) + { + $result=$this->insertExtraFields(); + if ($result < 0) $error++; + } + + // Triggers + if (! $error && ! $notrigger) + { + // Call triggers + $result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return $this->id; + } + } + + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetchCommon($id, $ref = null) + { + if (empty($id) && empty($ref)) return false; + + $sql = 'SELECT '.$this->get_field_list(); + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element; + + if(!empty($id)) $sql.= ' WHERE rowid = '.$id; + else $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']); + + $res = $this->db->query($sql); + if ($res) + { + $obj = $this->db->fetch_object($res); + if ($obj) + { + $this->setVarsFromFetchObj($obj); + return $this->id; + } + else + { + return 0; + } + } + else + { + $this->error = $this->db->lasterror(); + $this->errors[] = $this->error; + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function updateCommon(User $user, $notrigger = false) + { + global $conf, $langs; + + $error = 0; + + $now=dol_now(); + + $fieldvalues = $this->set_save_query(); + if (array_key_exists('date_modification', $fieldvalues) && empty($fieldvalues['date_modification'])) $fieldvalues['date_modification']=$this->db->idate($now); + if (array_key_exists('fk_user_modif', $fieldvalues) && ! ($fieldvalues['fk_user_modif'] > 0)) $fieldvalues['fk_user_modif']=$user->id; + unset($fieldvalues['rowid']); // The field 'rowid' is reserved field name for autoincrement field so we don't need it into update. + + $keys=array(); + $values = array(); + foreach ($fieldvalues as $k => $v) { + $keys[$k] = $k; + $value = $this->fields[$k]; + $values[$k] = $this->quote($v, $value); + $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]); + } + + // Clean and check mandatory + foreach($keys as $key) + { + if (preg_match('/^integer:/i', $this->fields[$key]['type']) && $values[$key] == '-1') $values[$key]=''; // This is an implicit foreign key field + if (! empty($this->fields[$key]['foreignkey']) && $values[$key] == '-1') $values[$key]=''; // This is an explicit foreign key field + + //var_dump($key.'-'.$values[$key].'-'.($this->fields[$key]['notnull'] == 1)); + /* + if ($this->fields[$key]['notnull'] == 1 && empty($values[$key])) + { + $error++; + $this->errors[]=$langs->trans("ErrorFieldRequired", $this->fields[$key]['label']); + }*/ + } + + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ; + + $this->db->begin(); + if (! $error) + { + $res = $this->db->query($sql); + if ($res===false) + { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + // Update extrafield + if (! $error) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + + // Triggers + if (! $error && ! $notrigger) + { + // Call triggers + $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user); + if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail + // End call triggers + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return $this->id; + } + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function deleteCommon(User $user, $notrigger = false) + { + $error=0; + + $this->db->begin(); + + if (! $error) { + if (! $notrigger) { + // Call triggers + $result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user); + if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail + // End call triggers + } + } + + if (! $error) + { + $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element."_extrafields"; + $sql.= " WHERE fk_object=" . $this->id; + + $resql = $this->db->query($sql); + if (! $resql) + { + $this->errors[] = $this->db->lasterror(); + $error++; + } + } + + if (! $error) + { + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id; + + $res = $this->db->query($sql); + if($res===false) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1; + } else { + $this->db->commit(); + return 1; + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimenCommon() + { + $this->id = 0; + + // TODO... + } + + /** + * Load comments linked with current task + * @return boolean 1 if ok + */ + public function fetchComments() + { + require_once DOL_DOCUMENT_ROOT.'/core/class/comment.class.php'; + + $comment = new Comment($this->db); + $this->comments = Comment::fetchAllFor($this->element, $this->id); + return 1; + } + + /** + * Return nb comments already posted + * + * @return int + */ + public function getNbComments() + { + return count($this->comments); + } + +} diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index dd8081754d8..a1d051440c3 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -259,9 +259,6 @@ class Conf // Load translation object with current language if (empty($this->global->MAIN_LANG_DEFAULT)) $this->global->MAIN_LANG_DEFAULT="en_US"; - //if (! isset($this->global->MAIN_REPEATCONTACTONEACHTAB)) $this->global->MAIN_REPEATCONTACTONEACHTAB=1; - //if (! isset($this->global->MAIN_REPEATADDRESSONEACHTAB)) $this->global->MAIN_REPEATADDRESSONEACHTAB=1; - $rootfordata = DOL_DATA_ROOT; $rootforuser = DOL_DATA_ROOT; // If multicompany module is enabled, we redefine the root of data diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index 329383160aa..ba7a67be3cb 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -594,7 +594,7 @@ class DolGraph * @param string $fileurl Url path to show image if saved onto disk * @return integer|null */ - function draw($file,$fileurl='') + function draw($file, $fileurl='') { if (empty($file)) { @@ -602,12 +602,17 @@ class DolGraph dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR); return -2; } - if (! is_array($this->data) || count($this->data) < 1) + if (! is_array($this->data)) { $this->error="Call to draw method was made but SetData was not called or called with an empty dataset for parameters"; dol_syslog(get_class($this)."::draw ".$this->error, LOG_ERR); return -1; } + if (count($this->data) < 1) + { + $this->error="Call to draw method was made but SetData was is an empty dataset"; + dol_syslog(get_class($this)."::draw ".$this->error, LOG_WARNING); + } $call = "draw_".$this->_library; call_user_func_array(array($this,$call), array($file,$fileurl)); } @@ -822,7 +827,7 @@ class DolGraph $legends=array(); $nblot=count($this->data[0])-1; // -1 to remove legend - if ($nblot < 0) dol_print_error('', 'Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw'); + if ($nblot < 0) dol_syslog('Bad value for property ->data. Must be set by mydolgraph->SetData before calling mydolgrapgh->draw', LOG_WARNING); $firstlot=0; // Works with line but not with bars //if ($nblot > 2) $firstlot = ($nblot - 2); // We limit nblot to 2 because jflot can't manage more than 2 bars on same x diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index bc37c428bb6..fd3c60a5b85 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -168,7 +168,7 @@ class ExtraFields if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') { // Add declaration of field into table - $result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $notused, $default, $computed, $entity, $langfile, $enabled); + $result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $notused, $default_value, $computed, $entity, $langfile, $enabled); $err2=$this->errno; if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) { @@ -309,7 +309,7 @@ class ExtraFields if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname) && ! is_numeric($attrname)) { - if(is_array($param) && count($param) > 0) + if (is_array($param) && count($param) > 0) { $params = serialize($param); } @@ -627,10 +627,17 @@ class ExtraFields { $this->db->begin(); - if (is_array($param)) + if (is_array($param) && count($param) > 0) { - if (count($param) > 0) $param = $this->db->escape(serialize($param)); - else $param=''; + $params = serialize($param); + } + elseif (strlen($param) > 0) + { + $params = trim($param); + } + else + { + $params=''; } $sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields"; @@ -674,7 +681,7 @@ class ExtraFields $sql.= " ".($langfile?"'".$this->db->escape($langfile)."'":"null").","; $sql.= " ".$pos.","; $sql.= " '".$this->db->escape($alwayseditable)."',"; - $sql.= " '".$this->db->escape($param)."',"; + $sql.= " '".$this->db->escape($params)."',"; $sql.= " ".$list.", "; $sql.= " ".(($default!='')?"'".$this->db->escape($default)."'":"null").","; $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").","; @@ -1344,28 +1351,48 @@ class ExtraFields /** * Return HTML string to put an output field into a page * - * @param string $key Key of attribute - * @param string $value Value to show - * @param string $moreparam To add more parameters on html input tag (only checkbox use html input for output rendering) - * @return string Formated value + * @param string $key Key of attribute + * @param string $value Value to show + * @param string $moreparam To add more parameters on html input tag (only checkbox use html input for output rendering) + * @param string $extrafieldsobjectkey If defined, use the new method to get extrafields data + * @return string Formated value */ - function showOutputField($key,$value,$moreparam='') + function showOutputField($key, $value, $moreparam='', $extrafieldsobjectkey='') { global $conf,$langs; - $elementtype=$this->attribute_elementtype[$key]; // seems not used - $label=$this->attribute_label[$key]; - $type=$this->attribute_type[$key]; - $size=$this->attribute_size[$key]; - $default=$this->attribute_default[$key]; - $computed=$this->attribute_computed[$key]; - $unique=$this->attribute_unique[$key]; - $required=$this->attribute_required[$key]; - $param=$this->attribute_param[$key]; - $perms=$this->attribute_perms[$key]; - $langfile=$this->attribute_langfile[$key]; - $list=$this->attribute_list[$key]; - $hidden=(($list == 0) ? 1 : 0); // If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) + if (! empty($extrafieldsobjectkey)) + { + $elementtype=$this->attributes[$extrafieldsobjectkey]['elementtype'][$key]; // seems not used + $label=$this->attributes[$extrafieldsobjectkey]['label'][$key]; + $type=$this->attributes[$extrafieldsobjectkey]['type'][$key]; + $size=$this->attributes[$extrafieldsobjectkey]['size'][$key]; + $default=$this->attributes[$extrafieldsobjectkey]['default'][$key]; + $computed=$this->attributes[$extrafieldsobjectkey]['computed'][$key]; + $unique=$this->attributes[$extrafieldsobjectkey]['unique'][$key]; + $required=$this->attributes[$extrafieldsobjectkey]['required'][$key]; + $param=$this->attributes[$extrafieldsobjectkey]['param'][$key]; + $perms=$this->attributes[$extrafieldsobjectkey]['perms'][$key]; + $langfile=$this->attributes[$extrafieldsobjectkey]['langfile'][$key]; + $list=$this->attributes[$extrafieldsobjectkey]['list'][$key]; + $hidden=(($list == 0) ? 1 : 0); // If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) + } + else + { + $elementtype=$this->attribute_elementtype[$key]; // seems not used + $label=$this->attribute_label[$key]; + $type=$this->attribute_type[$key]; + $size=$this->attribute_size[$key]; + $default=$this->attribute_default[$key]; + $computed=$this->attribute_computed[$key]; + $unique=$this->attribute_unique[$key]; + $required=$this->attribute_required[$key]; + $param=$this->attribute_param[$key]; + $perms=$this->attribute_perms[$key]; + $langfile=$this->attribute_langfile[$key]; + $list=$this->attribute_list[$key]; + $hidden=(($list == 0) ? 1 : 0); // If zero, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller) + } if ($hidden) return ''; // This is a protection. If field is hidden, we should just not call this method. @@ -1593,8 +1620,9 @@ class ExtraFields elseif ($type == 'link') { $out=''; - // only if something to display (perf) - if ($value) + + // Only if something to display (perf) + if ($value) // If we have -1 here, pb is into sert, not into ouptu { $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' @@ -1641,14 +1669,16 @@ class ExtraFields /** * Return tag to describe alignement to use for this extrafield * - * @param string $key Key of attribute - * @return string Formated value + * @param string $key Key of attribute + * @param string $extrafieldsobjectkey If defined, use the new method to get extrafields data + * @return string Formated value */ - function getAlignFlag($key) + function getAlignFlag($key, $extrafieldsobjectkey='') { global $conf,$langs; - $type=$this->attribute_type[$key]; + if (! empty($extrafieldsobjectkey)) $type=$this->attributes[$extrafieldsobjectkey]['type'][$key]; + else $type=$this->attribute_type[$key]; $align=''; diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index 31833c113b4..1a19e313e08 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -139,6 +139,9 @@ class HookManager 'addMoreMassActions', 'addSearchEntry', 'addStatisticLine', + 'createDictionaryFieldList', + 'editDictionaryFieldlist', + 'getFormMail', 'deleteFile', 'doActions', 'doMassActions', @@ -175,10 +178,9 @@ class HookManager 'formatEvent', 'printObjectLine', 'printObjectSubLine', - 'createDictionaryFieldList', - 'editDictionaryFieldlist', - 'getFormMail', - 'showLinkToObjectBlock' + 'showLinkToObjectBlock', + 'sendMail', + 'sendMailAfter' ) )) $hooktype='addreplace'; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e3f283368f1..cbd2eb5c3b3 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1726,7 +1726,7 @@ class Form * @param int $filtertype Filter on product type (''=nofilter, 0=product, 1=service) * @param int $limit Limit on number of returned lines * @param int $price_level Level of price to show - * @param int $status -1=Return all products, 0=Products not on sell, 1=Products on sell + * @param int $status Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell * @param int $finished 2=all, 1=finished, 0=raw material * @param string $selected_input_value Value of preselected input text (for use with ajax) * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after) @@ -1740,7 +1740,7 @@ class Form * 'warehouseopen' = select products from open warehouses, * 'warehouseclosed' = select products from closed warehouses, * 'warehouseinternal' = select products from warehouses for internal correct/transfer only - * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) + * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) * @return void */ function select_produits($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations = array()) @@ -2390,7 +2390,7 @@ class Form * Return list of suppliers products * * @param int $socid Id societe fournisseur (0 pour aucun filtre) - * @param int $selected Produit pre-selectionne + * @param int $selected Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD') * @param string $htmlname Nom de la zone select * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) * @param string $filtre Pour filtre sql @@ -5275,7 +5275,7 @@ class Form $confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT $fieldstoshow='t.ref'; - if (! empty($objecttmp->fields)) + if (! empty($objecttmp->fields)) // For object that declare it, it is better to use declared fields ( like societe, contact, ...) { $tmpfieldstoshow=''; foreach($objecttmp->fields as $key => $val) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 30719d0da80..94ab828ee39 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -993,7 +993,7 @@ class FormMail extends Form $sql = "SELECT label, topic, joinfiles, content, content_lines, lang"; $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; $sql.= " WHERE (type_template='".$db->escape($type_template)."' OR type_template='all')"; - $sql.= " AND entity IN (".getEntity('c_email_templates', 0).")"; + $sql.= " AND entity IN (".getEntity('c_email_templates').")"; $sql.= " AND (private = 0 OR fk_user = ".$user->id.")"; // Get all public or private owned if ($active >= 0) $sql.=" AND active = ".$active; if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; @@ -1065,7 +1065,7 @@ class FormMail extends Form $sql = "SELECT label, topic, content, lang"; $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; $sql.= " WHERE type_template='".$this->db->escape($type_template)."'"; - $sql.= " AND entity IN (".getEntity('c_email_templates', 0).")"; + $sql.= " AND entity IN (".getEntity('c_email_templates').")"; $sql.= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".$user->id.")"; if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; $sql.= $this->db->order("lang,label","ASC"); @@ -1102,7 +1102,7 @@ class FormMail extends Form $sql = "SELECT rowid, label, topic, content, content_lines, lang, fk_user, private, position"; $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; $sql.= " WHERE type_template IN ('".$this->db->escape($type_template)."', 'all')"; - $sql.= " AND entity IN (".getEntity('c_email_templates', 1).")"; + $sql.= " AND entity IN (".getEntity('c_email_templates').")"; $sql.= " AND (private = 0 OR fk_user = ".$user->id.")"; // See all public templates or templates I own. if ($active >= 0) $sql.=" AND active = ".$active; //if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; // Return all languages diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 0afae8e358f..f4a6d98c671 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -47,7 +47,7 @@ class FormProjets * Output a combo list with projects qualified for a third party / user * * @param int $socid Id third party (-1=all, 0=only projects not linked to a third party, id=projects not linked or linked to third party id) - * @param int $selected Id project preselected + * @param string $selected Id project preselected ('' or id of project) * @param string $htmlname Name of HTML field * @param int $maxlength Maximum length of label * @param int $option_only Return only html options lines without the select tag diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index d40fcadc17c..7554a82a5fd 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -404,13 +404,13 @@ class Notify break; case 'FICHINTER_ADD_CONTACT': $link='/fichinter/card.php?id='.$object->id; - $dir_output = $conf->facture->dir_output; + $dir_output = $conf->ficheinter->dir_output; $object_type = 'ficheinter'; $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionAddedContact",$object->ref); break; case 'FICHINTER_VALIDATE': $link='/fichinter/card.php?id='.$object->id; - $dir_output = $conf->facture->dir_output; + $dir_output = $conf->ficheinter->dir_output; $object_type = 'ficheinter'; $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionValidated",$object->ref); break; @@ -664,8 +664,9 @@ class Notify } dol_syslog("Replace the __SUPERVISOREMAIL__ key into recipient email string with ".$newval); $sendto = preg_replace('/__SUPERVISOREMAIL__/', $newval, $sendto); - $sendto = preg_replace('/^[\s,]+/','',$sendto); // Clean start of string - $sendto = preg_replace('/[\s,]+$/','',$sendto); // Clean end of string + $sendto = preg_replace('/,\s*,/', ',', $sendto); // in some case you can have $sendto like "email, __SUPERVISOREMAIL__ , otheremail" then you have "email, , othermail" and it's not valid + $sendto = preg_replace('/^[\s,]+/', '', $sendto); // Clean start of string + $sendto = preg_replace('/[\s,]+$/', '', $sendto); // Clean end of string } if ($sendto) diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index d62ddd57b82..710798331ac 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -678,7 +678,6 @@ function isInEEC($object) function show_projects($conf, $langs, $db, $object, $backtopage='', $nocreatelink=0, $morehtmlright='') { global $user; - global $bc; $i = -1 ; @@ -806,10 +805,10 @@ function show_projects($conf, $langs, $db, $object, $backtopage='', $nocreatelin */ function show_contacts($conf,$langs,$db,$object,$backtopage='') { - global $user,$conf; - global $bc; + global $user,$conf,$extrafields,$hookmanager; + global $contextpage; - $form= new Form($db); + $form = new Form($db); $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); @@ -820,24 +819,67 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') $search_addressphone = GETPOST("search_addressphone",'alpha'); if (! $sortorder) $sortorder="ASC"; - if (! $sortfield) $sortfield="p.lastname"; + if (! $sortfield) $sortfield="t.lastname"; + if (! empty($conf->clicktodial->enabled)) + { + $user->fetch_clicktodial(); // lecture des infos de clicktodial du user + } + + + $contactstatic = new Contact($db); + + $extralabels=$extrafields->fetch_name_optionals_label($contactstatic->table_element); + + $contactstatic->fields=array( + 'name' =>array('type'=>'varchar(128)', 'label'=>'Name', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1), + 'poste' =>array('type'=>'varchar(128)', 'label'=>'PostOfFunction', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>20), + 'address' =>array('type'=>'varchar(128)', 'label'=>'Address', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>30), + 'statut' =>array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>40, 'arrayofkeyval'=>array(0=>$contactstatic->LibStatut(0,1), 1=>$contactstatic->LibStatut(1,1))), + ); + + // Definition of fields for list + $arrayfields=array( + 't.rowid'=>array('label'=>"TechnicalID", 'checked'=>($conf->global->MAIN_SHOW_TECHNICAL_ID?1:0), 'enabled'=>($conf->global->MAIN_SHOW_TECHNICAL_ID?1:0), 'position'=>1), + 't.name'=>array('label'=>"Name", 'checked'=>1, 'position'=>10), + 't.poste'=>array('label'=>"PostOrFunction", 'checked'=>1, 'position'=>20), + 't.address'=>array('label'=>(empty($conf->dol_optimize_smallscreen) ? $langs->trans("Address").' / '.$langs->trans("Phone").' / '.$langs->trans("Email") : $langs->trans("Address")), 'checked'=>1, 'position'=>30), + 't.statut'=>array('label'=>"Status", 'checked'=>1, 'position'=>40, 'align'=>'center'), + ); + // Extra fields + if (is_array($extrafields->attributes[$contactstatic->table_element]['label']) && count($extrafields->attributes[$contactstatic->table_element]['label'])) + { + foreach($extrafields->attributes[$contactstatic->table_element]['label'] as $key => $val) + { + if (! empty($extrafields->attributes[$contactstatic->table_element]['list'][$key])) $arrayfields["ef.".$key]=array('label'=>$extrafields->attributes[$contactstatic->table_element]['label'][$key], 'checked'=>(($extrafields->attributes[$contactstatic->table_element]['list'][$key]<0)?0:1), 'position'=>$extrafields->attributes[$contactstatic->table_element]['pos'][$key], 'enabled'=>(abs($extrafields->attributes[$contactstatic->table_element]['list'][$key])!=3 && $extrafields->attributes[$contactstatic->table_element]['perms'][$key])); + } + } + + // Initialize array of search criterias + $search=array(); + foreach($contactstatic->fields as $key => $val) + { + if (GETPOST('search_'.$key,'alpha')) $search[$key]=GETPOST('search_'.$key,'alpha'); + } + + + // Purge search criteria if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') ||GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers { $search_status = ''; $search_name = ''; $search_addressphone = ''; $search_array_options=array(); + + foreach($contactstatic->fields as $key => $val) + { + $search[$key]=''; + } + $toselect=''; } - $i=-1; - - $contactstatic = new Contact($db); - - if (! empty($conf->clicktodial->enabled)) - { - $user->fetch_clicktodial(); // lecture des infos de clicktodial - } + $contactstatic->fields = dol_sort_array($contactstatic->fields, 'position'); + $arrayfields = dol_sort_array($arrayfields, 'position'); $buttoncreate=''; if ($user->rights->societe->contact->creer) @@ -853,26 +895,32 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') print load_fiche_titre($title, $buttoncreate,''); print ''; + print ''; print ''; print ''; print ''; print ''; + $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; + $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + //if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1); - print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table - print "\n".'
    '; - $facturestatic->ref=$obj->facnumber; - $facturestatic->id=$obj->rowid; - $facturestatic->total_ht=$obj->total_ht; - $facturestatic->total_tva=$obj->total_tva; - $facturestatic->total_ttc=$obj->total_ttc; - $facturestatic->type=$obj->type; - $facturestatic->statut = $obj->fk_statut; - $facturestatic->date_lim_reglement = $db->jdate($obj->datelimite); print $facturestatic->getNomUrl(1,''); print ''; @@ -858,11 +897,6 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) print '' ; - $societestatic->id=$obj->socid; - $societestatic->name=$obj->name; - $societestatic->client=1; - $societestatic->code_client = $obj->code_client; - $societestatic->code_fournisseur = $obj->code_fournisseur; print $societestatic->getNomUrl(1,'customer',44); print ''.dol_print_date($db->jdate($obj->datelimite),'day').'
    '; $facstatic->ref=$obj->ref; $facstatic->id = $obj->rowid; - $facstatic->total_ht = $obj->total_ht; - $facstatic->total_tva = $obj->total_tva; - $facstatic->total_ttc = $obj->total_ttc; + $facstatic->total_ht = $obj->total_ht; + $facstatic->total_tva = $obj->total_tva; + $facstatic->total_ttc = $obj->total_ttc; + + $societestatic->id=$obj->socid; + $societestatic->name=$obj->name; + $societestatic->email=$obj->email; + $societestatic->client=0; + $societestatic->fournisseur=1; + $societestatic->code_client = $obj->code_client; + $societestatic->code_fournisseur = $obj->code_fournisseur; + $societestatic->code_compta = $obj->code_compta; + $societestatic->code_compta_fournisseur = $obj->code_compta_fournisseur; + + print '
    '; print $facstatic->getNomUrl(1,''); print ''.$societestatic->getNomUrl(1, 'supplier', 44).''.dol_print_date($db->jdate($obj->date_lim_reglement),'day').''.price($obj->total_ht).'
    ".$tva_static->getNomUrl(1)."".dol_trunc($obj->label,40)."'.dol_print_date($db->jdate($obj->dv),'day')."'.dol_print_date($db->jdate($obj->dp),'day')."".dol_trunc($obj->label,40)."'.dol_print_date($db->jdate($obj->datev),'day')."'.dol_print_date($db->jdate($obj->datep),'day')."
     '.$langs->trans('Description').''.$langs->trans("SupplierRef").''.$langs->trans('VAT').''.$langs->trans('PriceUHT').''.$langs->trans('PriceUHTCurrency', $this->multicurrency_code).''.$langs->trans('PriceUTTC').''.$langs->trans('Qty').''.$langs->trans('Unit').''.$langs->trans('ReductionShort').'' . $langs->trans('Progress') . ''.$langs->trans('BuyingPrice').''.$langs->trans('CostPrice').''.$langs->trans('MarginRate').''.$langs->trans('MarkRate').''.$langs->trans('TotalHTShort').''.$langs->trans('TotalHTShortCurrency', $this->multicurrency_code).''.$langs->trans('TotalTTCShort').'
    '.$langs->trans('Ref').''.$langs->trans('Description').''.$langs->trans('VATRate').''.$langs->trans('PriceUHT').''.$langs->trans('PriceUHTCurrency').''.$langs->trans('Qty').''.$langs->trans('Unit').''.$langs->trans('ReductionShort').'
    '.$labeltoshow.''; + + switch($mode) { + case "view": + $out .= $extrafields->showOutputField($key, $value); + break; + case "edit": + $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this->id); + break; + } + + $out .= '
    '."\n"; + print '
    '; // You can use div-table-responsive-no-min if you dont need reserved height for your table + print "\n".'
    '."\n"; $param="socid=".$object->id; if ($search_status != '') $param.='&search_status='.$search_status; if ($search_name != '') $param.='&search_name='.urlencode($search_name); - $sql = "SELECT p.rowid, p.lastname, p.firstname, p.fk_pays as country_id, p.civility, p.poste, p.phone as phone_pro, p.phone_mobile, p.phone_perso, p.fax, p.email, p.skype, p.statut, p.photo,"; - $sql .= " p.civility as civility_id, p.address, p.zip, p.town"; - $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as p"; - $sql .= " WHERE p.fk_soc = ".$object->id; - if ($search_status!='' && $search_status != '-1') $sql .= " AND p.statut = ".$db->escape($search_status); - if ($search_name) $sql .= " AND (p.lastname LIKE '%".$db->escape($search_name)."%' OR p.firstname LIKE '%".$db->escape($search_name)."%')"; - $sql.= " ORDER BY $sortfield $sortorder"; + $sql = "SELECT t.rowid, t.lastname, t.firstname, t.fk_pays as country_id, t.civility, t.poste, t.phone as phone_pro, t.phone_mobile, t.phone_perso, t.fax, t.email, t.skype, t.statut, t.photo,"; + $sql .= " t.civility as civility_id, t.address, t.zip, t.town"; + $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as t"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople_extrafields as ef on (t.rowid = ef.fk_object)"; + $sql .= " WHERE t.fk_soc = ".$object->id; + if ($search_status!='' && $search_status != '-1') $sql .= " AND t.statut = ".$db->escape($search_status); + if ($search_name) $sql .= " AND (t.lastname LIKE '%".$db->escape($search_name)."%' OR t.firstname LIKE '%".$db->escape($search_name)."%')"; + if ($sortfield == "t.name") $sql.=" ORDER BY t.lastname $sortorder, t.firstname $sortorder"; + else $sql.= " ORDER BY $sortfield $sortorder"; dol_syslog('core/lib/company.lib.php :: show_contacts', LOG_DEBUG); $result = $db->query($sql); @@ -880,59 +928,63 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') $num = $db->num_rows($result); - $colspan=9; - - print ''; - - // Photo - Name - print ''; - - // Position - print ''; - - // Address - Phone - Email - print ''; - - // Status - print ''; - - // Add to agenda - if (! empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) - { - $colspan++; - print ''; - } - - // Action - print ''; - - print ""; - - $titlefieldaddress=$langs->trans("Address").' / '.$langs->trans("Phone").' / '.$langs->trans("Email"); - if (! empty($conf->dol_optimize_smallscreen)) $titlefieldaddress=$langs->trans("Address"); - + // Fields title search + // -------------------------------------------------------------------- print ''; - print_liste_field_titre("Name",$_SERVER["PHP_SELF"],"p.lastname","",$param,'',$sortfield,$sortorder); - print_liste_field_titre("Poste",$_SERVER["PHP_SELF"],"p.poste","",$param,'',$sortfield,$sortorder); - print_liste_field_titre($titlefieldaddress,$_SERVER["PHP_SELF"],"","",$param,'',$sortfield,$sortorder); - print_liste_field_titre("Status",$_SERVER["PHP_SELF"],"p.statut","",$param,'align="center"',$sortfield,$sortorder); - // Add to agenda - if (! empty($conf->agenda->enabled) && ! empty($user->rights->agenda->myactions->create)) print_liste_field_titre(''); - // Edit - print_liste_field_titre(''); - print "\n"; + foreach($contactstatic->fields as $key => $val) + { + $align=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap'; + if ($key == 'status' || $key == 'statut') $align.=($align?' ':'').'center'; + if (! empty($arrayfields['t.'.$key]['checked'])) + { + print ''; + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListOption', $parameters, $contactstatic); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + print ''."\n"; + + + // Fields title label + // -------------------------------------------------------------------- + print ''; + foreach($contactstatic->fields as $key => $val) + { + $align=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap'; + if ($key == 'status' || $key == 'statut') $align.=($align?' ':'').'center'; + if (! empty($arrayfields['t.'.$key]['checked'])) print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align?'class="'.$align.'"':''), $sortfield, $sortorder, $align.' ')."\n"; + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; + // Hook fields + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"],'','','','align="center"',$sortfield,$sortorder,'maxwidthsearch ')."\n"; + print ''."\n"; + + $i = -1; if ($num || (GETPOST('button_search') || GETPOST('button_search.x') || GETPOST('button_search_x'))) { - $i=0; + $i = 0; while ($i < $num) { @@ -961,46 +1013,81 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') $contactstatic->country_code = $country_code; $contactstatic->setGenderFromCivility(); + $contactstatic->fetch_optionals(); + + if (is_array($contactstatic->array_options)) + { + foreach($contactstatic->array_options as $key => $val) + { + $obj->$key = $val; + } + } print ''; + // ID + if (! empty($arrayfields['t.rowid']['checked'])) + { + print ''; + } + // Photo - Name - print ''; + if (! empty($arrayfields['t.name']['checked'])) + { + print ''; + } // Job position - print ''; + if (! empty($arrayfields['t.poste']['checked'])) + { + print ''; + } // Address - Phone - Email - print ''; + if (! empty($arrayfields['t.address']['checked'])) + { + print ''; + } // Status - print ''; + if (! empty($arrayfields['t.statut']['checked'])) + { + print ''; + } - // Add to agenda + // Extra fields + $extrafieldsobjectkey='socpeople'; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + + // Actions + print ''; + print '   '; } // Edit if ($user->rights->societe->contact->creer) { - print ''; + print ''; } - else print ''; + + print ''; print "\n"; $i++; @@ -1008,9 +1095,9 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') } else { - print ''; - print ''; - print "\n"; + $colspan=1; + foreach($arrayfields as $key => $val) { if (! empty($val['checked'])) $colspan++; } + print ''; } print "\n
    '; - print ''; - print ''; - print ''; - print $form->selectarray('search_status', array('-1'=>'','0'=>$contactstatic->LibStatut(0,1),'1'=>$contactstatic->LibStatut(1,1)),$search_status); - print ''; - $searchpicto=$form->showFilterButtons(); - print $searchpicto; - print '
    '; + if (in_array($key, array('lastname','name'))) print ''; + elseif (in_array($key, array('statut'))) print $form->selectarray('search_status', array('-1'=>'','0'=>$contactstatic->LibStatut(0,1),'1'=>$contactstatic->LibStatut(1,1)),$search_status); + print ''; + $searchpicto=$form->showFilterButtons(); + print $searchpicto; + print '
    '; + print $contactstatic->id; + print ''; - print $form->showphoto('contact',$contactstatic,0,0,0,'photorefnoborder valignmiddle marginrightonly','small',1,0,1); - print $contactstatic->getNomUrl(0,'',0,'&backtopage='.urlencode($backtopage)); - print ''; + print $form->showphoto('contact',$contactstatic,0,0,0,'photorefnoborder valignmiddle marginrightonly','small',1,0,1); + print $contactstatic->getNomUrl(0,'',0,'&backtopage='.urlencode($backtopage)); + print ''; - if ($obj->poste) print $obj->poste; - print ''; + if ($obj->poste) print $obj->poste; + print ''; - print $contactstatic->getBannerAddress('contact', $object); - print ''; + print $contactstatic->getBannerAddress('contact', $object); + print ''.$contactstatic->getLibStatut(5).''.$contactstatic->getLibStatut(5).''; + + // Add to agenda if (! empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create) { - print ''; print ''; print img_object($langs->trans("Event"),"action"); - print ''; print ''; print img_edit(); - print ' 
    '.$langs->trans("None").'
    '.$langs->trans("None").'
    \n"; print ''; @@ -1033,7 +1120,6 @@ function show_contacts($conf,$langs,$db,$object,$backtopage='') function show_addresses($conf,$langs,$db,$object,$backtopage='') { global $user; - global $bc; require_once DOL_DOCUMENT_ROOT.'/societe/class/address.class.php'; @@ -1125,7 +1211,7 @@ function show_addresses($conf,$langs,$db,$object,$backtopage='') */ function show_actions_todo($conf,$langs,$db,$filterobj,$objcon='',$noprint=0,$actioncode='') { - global $bc,$user,$conf; + global $user,$conf; $out = show_actions_done($conf,$langs,$db,$filterobj,$objcon,1,$actioncode, 'todo'); @@ -1152,7 +1238,7 @@ function show_actions_todo($conf,$langs,$db,$filterobj,$objcon='',$noprint=0,$ac */ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep,a.id', $sortorder='DESC') { - global $bc,$user,$conf; + global $user,$conf; global $form; global $param; @@ -1180,14 +1266,14 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= if (is_object($filterobj) && get_class($filterobj) == 'Adherent') $sql.= ", m.lastname, m.firstname"; if (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') $sql.= ", o.ref"; if (is_object($filterobj) && get_class($filterobj) == 'Product') $sql.= ", o.ref"; - $sql.= " FROM ".MAIN_DB_PREFIX."user as u, ".MAIN_DB_PREFIX."actioncomm as a"; + $sql.= " FROM ".MAIN_DB_PREFIX."actioncomm as a"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id"; if (is_object($filterobj) && get_class($filterobj) == 'Societe') $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid"; if (is_object($filterobj) && get_class($filterobj) == 'Adherent') $sql.= ", ".MAIN_DB_PREFIX."adherent as m"; if (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') $sql.= ", ".MAIN_DB_PREFIX."commande_fournisseur as o"; if (is_object($filterobj) && get_class($filterobj) == 'Product') $sql.= ", ".MAIN_DB_PREFIX."product as o"; - $sql.= " WHERE u.rowid = a.fk_user_action"; - $sql.= " AND a.entity IN (".getEntity('agenda').")"; + $sql.= " WHERE a.entity IN (".getEntity('agenda').")"; if (is_object($filterobj) && get_class($filterobj) == 'Societe' && $filterobj->id) $sql.= " AND a.fk_soc = ".$filterobj->id; if (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) $sql.= " AND a.fk_project = ".$filterobj->id; if (is_object($filterobj) && get_class($filterobj) == 'Adherent') @@ -1230,7 +1316,6 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= if ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))"; if (is_array($filters) && $filters['search_agenda_label']) $sql.= natural_search('a.label', $filters['search_agenda_label']); $sql.= $db->order($sortfield, $sortorder); - dol_syslog("company.lib::show_actions_done", LOG_DEBUG); $resql=$db->query($sql); if ($resql) @@ -1336,7 +1421,6 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= } } - if (! empty($conf->agenda->enabled) || (! empty($conf->mailing->enabled) && ! empty($objcon->email))) { $delay_warning=$conf->global->MAIN_DELAY_ACTIONS_TODO*24*60*60; @@ -1423,7 +1507,6 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint= foreach ($histo as $key=>$value) { - $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo $out.='
    + element == 'contrat') + + $freelines = false; + if (empty($conf->global->MAIN_DISABLE_FREE_LINES)) { - if (empty($conf->product->enabled) && empty($conf->service->enabled) && empty($conf->global->CONTRACT_SUPPORT_PRODUCTS)) $forceall=-1; // With contract, by default, no choice at all, except if CONTRACT_SUPPORT_PRODUCTS is set - else $forceall=0; - } - - // Free line - echo ''; - // Show radio free line - if ($forceall >= 0 && (! empty($conf->product->enabled) || ! empty($conf->service->enabled))) - { - echo ''; - echo ' '; - } - else - { - echo ''; - // Show type selector - if ($forceall >= 0) + $freelines = true; + $forceall=1; // We always force all type for free lines (module product or service means we use predefined product or service) + if ($object->element == 'contrat') { - if (empty($conf->product->enabled) || empty($conf->service->enabled)) echo $langs->trans("Type"); - else echo $langs->trans("FreeLineOfType"); + if (empty($conf->product->enabled) && empty($conf->service->enabled) && empty($conf->global->CONTRACT_SUPPORT_PRODUCTS)) $forceall=-1; // With contract, by default, no choice at all, except if CONTRACT_SUPPORT_PRODUCTS is set + else $forceall=0; + } + + // Free line + echo ''; + // Show radio free line + if ($forceall >= 0 && (! empty($conf->product->enabled) || ! empty($conf->service->enabled))) + { + echo ''; echo ' '; } + else + { + echo ''; + // Show type selector + if ($forceall >= 0) + { + if (empty($conf->product->enabled) || empty($conf->service->enabled)) echo $langs->trans("Type"); + else echo $langs->trans("FreeLineOfType"); + echo ' '; + } + } + + echo $form->select_type_of_lines(isset($_POST["type"])?GETPOST("type",'alpha',2):-1,'type',1,1,$forceall); + + echo ''; } - echo $form->select_type_of_lines(isset($_POST["type"])?GETPOST("type",'alpha',2):-1,'type',1,1,$forceall); - - echo ''; - // Predefined product/service if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) { - if ($forceall >= 0) echo '
    '; + if ($forceall >= 0 && $freelines) echo '
    '; echo ''; echo '
    + $("#prod_entry_mode_predef").click(); + /* When changing predefined product, we reload list of supplier prices required for margin combo */ $("#idprod, #idprodfournprice").change(function() diff --git a/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php b/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php index 25dc957df02..ec0b0cb6941 100644 --- a/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php +++ b/htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php @@ -51,7 +51,7 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers if (empty($conf->blockedlog->enabled)) return 0; // Module not active, we do nothing // Test if event/record is qualified - $listofqualifiedelement = array('facture', 'don', 'payment', 'payment_donation', 'subscription'); + $listofqualifiedelement = array('facture', 'don', 'payment', 'payment_donation', 'subscription','payment_various'); if (! in_array($object->element, $listofqualifiedelement)) return 1; dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); @@ -120,9 +120,10 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers $res = $b->create($user); - if ($res<0) + if ($res < 0) { - setEventMessages($b->error, $b->errors, 'errors'); + $this->error = $b->error; + $this->errors = $b->errors; return -1; } else diff --git a/htdocs/fichinter/class/api_interventions.class.php b/htdocs/fichinter/class/api_interventions.class.php new file mode 100644 index 00000000000..3f5fad3d74f --- /dev/null +++ b/htdocs/fichinter/class/api_interventions.class.php @@ -0,0 +1,457 @@ + + * Copyright (C) 2016 Laurent Destailleur + * + * 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 . + */ + + use Luracast\Restler\RestException; + + require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php'; + +/** + * API class for fichinters + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class Interventions extends DolibarrApi +{ + + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'socid', + 'fk_project', + 'description' + ); + + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDSLINE = array( + 'description', + 'date', + 'duree' + ); + + /** + * @var fichinter $fichinter {@type fichinter} + */ + public $fichinter; + + /** + * Constructor + */ + function __construct() + { + global $db, $conf; + $this->db = $db; + $this->fichinter = new Fichinter($this->db); + } + + /** + * Get properties of a Expense Report object + * + * Return an array with Expense Report informations + * + * @param int $id ID of Expense Report + * @return array|mixed Data without useless information + * + * @throws RestException + */ + function get($id) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->lire) { + throw new RestException(401); + } + + $result = $this->fichinter->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Intervention report not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fichinter',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $this->fichinter->fetchObjectLinked(); + return $this->_cleanObjectDatas($this->fichinter); + } + + /** + * List of interventions + * + * Return a list of interventions + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $thirdparty_ids Thirdparty ids to filter orders of. {@example '1' or '1,2,3'} {@pattern /^[0-9,]*$/i} + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + * @return array Array of order objects + * + * @throws RestException + */ + function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '') { + global $db, $conf; + + $obj_ret = array(); + + // case of external user, $thirdparty_ids param is ignored and replaced by user's socid + $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids; + + // If the internal user must only see his customers, force searching by him + $search_sale = 0; + if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id; + + $sql = "SELECT t.rowid"; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects) + $sql.= " FROM ".MAIN_DB_PREFIX."fichinter as t"; + + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale + + $sql.= ' WHERE t.entity IN ('.getEntity('fichinter').')'; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc"; + if ($socids) $sql.= " AND t.fk_soc IN (".$socids.")"; + if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale + // Insert sale filter + if ($search_sale > 0) + { + $sql .= " AND sc.fk_user = ".$search_sale; + } + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + $sql.= $db->order($sortfield, $sortorder); + if ($limit) { + if ($page < 0) + { + $page = 0; + } + $offset = $limit * $page; + + $sql.= $db->plimit($limit + 1, $offset); + } + + dol_syslog("API Rest request"); + $result = $db->query($sql); + + if ($result) + { + $num = $db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + while ($i < $min) + { + $obj = $db->fetch_object($result); + $fichinter_static = new Fichinter($db); + if($fichinter_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($fichinter_static); + } + $i++; + } + } + else { + throw new RestException(503, 'Error when retrieve fichinter list : '.$db->lasterror()); + } + if( ! count($obj_ret)) { + throw new RestException(404, 'No finchinter found'); + } + return $obj_ret; + } + + /** + * Create intervention object + * + * @param array $request_data Request data + * @return int ID of intervention + */ + function post($request_data = NULL) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->creer) { + throw new RestException(401, "Insuffisant rights"); + } + // Check mandatory fields + $result = $this->_validate($request_data); + foreach($request_data as $field => $value) { + $this->fichinter->$field = $value; + } + + if ($this->fichinter->create(DolibarrApiAccess::$user) < 0) { + throw new RestException(500, "Error creating fichinter", array_merge(array($this->fichinter->error), $this->fichinter->errors)); + } + + return $this->fichinter->id; + } + + + /** + * Get lines of an intervention + * + * @param int $id Id of intervention + * + * @url GET {id}/lines + * + * @return int + */ + /* TODO + function getLines($id) { + if(! DolibarrApiAccess::$user->rights->ficheinter->lire) { + throw new RestException(401); + } + + $result = $this->fichinter->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Intervention not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fichinter',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $this->fichinter->getLinesArray(); + $result = array(); + foreach ($this->fichinter->lines as $line) { + array_push($result,$this->_cleanObjectDatas($line)); + } + return $result; + } + */ + + /** + * Add a line to given intervention + * + * @param int $id Id of intervention to update + * @param array $request_data Request data + * + * @url POST {id}/lines + * + * @return int + */ + function postLine($id, $request_data = NULL) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->creer) { + throw new RestException(401, "Insuffisant rights"); + } + // Check mandatory fields + $result = $this->_validateLine($request_data); + + foreach($request_data as $field => $value) { + $this->fichinter->$field = $value; + } + + if( ! $result ) { + throw new RestException(404, 'Intervention not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fichinter',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $updateRes = $this->fichinter->addLine( + DolibarrApiAccess::$user, + $id, + $this->fichinter->description, + $this->fichinter->date, + $this->fichinter->duree + ); + + if ($updateRes > 0) { + return $updateRes; + } + else { + throw new RestException(400, $this->fichinter->error); + } + } + + /** + * Delete order + * + * @param int $id Order ID + * @return array + */ + function delete($id) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->supprimer) { + throw new RestException(401); + } + $result = $this->fichinter->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Intervention not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('commande',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if( ! $this->fichinter->delete(DolibarrApiAccess::$user)) { + throw new RestException(500, 'Error when delete intervention : '.$this->fichinter->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Intervention deleted' + ) + ); + + } + + /** + * Validate an intervention + * + * If you get a bad value for param notrigger check, provide this in body + * { + * "notrigger": 0 + * } + * + * @param int $id Intervention ID + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * + * @url POST {id}/validate + * + * @return array + */ + function validate($id, $notrigger=0) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->creer) { + throw new RestException(401, "Insuffisant rights"); + } + $result = $this->fichinter->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Intervention not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fichinter',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->fichinter->setValid(DolibarrApiAccess::$user, $notrigger); + if ($result == 0) { + throw new RestException(304, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when validating Intervention: '.$this->commande->error); + } + + $this->fichinter->fetchObjectLinked(); + + return $this->_cleanObjectDatas($this->fichinter); + } + + /** + * Close an intervention + * + * @param int $id Intervention ID + * + * @url POST {id}/close + * + * @return array + */ + function closeFichinter($id) + { + if(! DolibarrApiAccess::$user->rights->ficheinter->creer) + { + throw new RestException(401, "Insuffisant rights"); + } + $result = $this->fichinter->fetch($id); + if (! $result) { + throw new RestException(404, 'Intervention not found'); + } + + if (! DolibarrApi::_checkAccessToResource('fichinter',$this->fichinter->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->fichinter->setStatut(3); + + if ($result == 0) { + throw new RestException(304, 'Error nothing done. May be object is already closed'); + } + if ($result < 0) { + throw new RestException(500, 'Error when closing Intervention: '.$this->fichinter->error); + } + + $this->fichinter->fetchObjectLinked(); + + return $this->_cleanObjectDatas($this->fichinter); + } + + /** + * Validate fields before create or update object + * + * @param array $data Data to validate + * @return array + * + * @throws RestException + */ + function _validate($data) + { + $fichinter = array(); + foreach (Interventions::$FIELDS as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $fichinter[$field] = $data[$field]; + } + return $fichinter; + } + + + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + */ + function _cleanObjectDatas($object) { + + $object = parent::_cleanObjectDatas($object); + + unset($object->statuts_short); + unset($object->statuts_logo); + unset($object->statuts); + + return $object; + } + + /** + * Validate fields before create or update object + * + * @param array $data Data to validate + * @return array + * + * @throws RestException + */ + function _validateLine($data) + { + $fichinter = array(); + foreach (Interventions::$FIELDSLINE as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $fichinter[$field] = $data[$field]; + } + return $fichinter; + } + + +} diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index 237d09570d1..ce122b045b5 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -128,7 +128,7 @@ class Fichinter extends CommonObject $sql.= " WHERE sc.fk_user = " .$user->id; $clause = "AND"; } - $sql.= " ".$clause." fi.entity IN (".getEntity($this->element, 1).")"; + $sql.= " ".$clause." fi.entity IN (".getEntity($this->element).")"; $resql=$this->db->query($sql); if ($resql) @@ -157,7 +157,7 @@ class Fichinter extends CommonObject */ function create($user, $notrigger=0) { - global $conf, $user, $langs; + global $conf, $langs; dol_syslog(get_class($this)."::create ref=".$this->ref); diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 6f473f8deb3..724f90af228 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -101,6 +101,21 @@ if (empty($reshook)) $result=$object->setPaymentMethods(GETPOST('mode_reglement_supplier_id','int')); if ($result < 0) dol_print_error($db,$object->error); } + if ($action == 'update_extras') { + $object->fetch($id); + + // Fill array 'array_options' with data from update form + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute')); + + if ($ret < 0) $error++; + if (! $error) + { + $result = $object->insertExtraFields(); + if ($result < 0) $error++; + } + if ($error) $action = 'edit_extras'; + } } @@ -779,7 +794,7 @@ if ($object->id > 0) print ''; - if (! empty($conf->global->MAIN_REPEATCONTACTONEACHTAB)) + if (! empty($conf->global->MAIN_DUPLICATE_CONTACTS_TAB_ON_MAIN_CARD)) { print '
    '; // List of contacts diff --git a/htdocs/fourn/class/paiementfourn.class.php b/htdocs/fourn/class/paiementfourn.class.php index 6d402598284..fc917e112f7 100644 --- a/htdocs/fourn/class/paiementfourn.class.php +++ b/htdocs/fourn/class/paiementfourn.class.php @@ -210,11 +210,12 @@ class PaiementFourn extends Paiement $resql=$this->db->query($sql); if ($resql) { + $invoice=new FactureFournisseur($this->db); + $invoice->fetch($facid); + // If we want to closed payed invoices if ($closepaidinvoices) { - $invoice=new FactureFournisseur($this->db); - $invoice->fetch($facid); $paiement = $invoice->getSommePaiement(); //$creditnotes=$invoice->getSumCreditNotesUsed(); $creditnotes=0; @@ -228,17 +229,34 @@ class PaiementFourn extends Paiement } else dol_syslog("Remain to pay for invoice ".$facid." not null. We do nothing."); } + + // Regenerate documents of invoices + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $invoice->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $ret = $invoice->fetch($facid); // Reload to get new records + $result = $invoice->generateDocument($invoice->modelpdf, $outputlangs); + if ($result < 0) { + setEventMessages($invoice->error, $invoice->errors, 'errors'); + $error++; + } + } } else { - dol_syslog('Paiement::Create Erreur INSERT dans paiement_facture '.$facid); + $this->error=$this->db->lasterror(); $error++; } } else { - dol_syslog('PaiementFourn::Create Montant non numerique',LOG_ERR); + dol_syslog(get_class($this).'::Create Amount line '.$key.' not a number. We discard it.'); } } diff --git a/htdocs/install/mysql/migration/7.0.0-8.0.0.sql b/htdocs/install/mysql/migration/7.0.0-8.0.0.sql index 1b9375ef1a8..498d9226b2e 100644 --- a/htdocs/install/mysql/migration/7.0.0-8.0.0.sql +++ b/htdocs/install/mysql/migration/7.0.0-8.0.0.sql @@ -22,5 +22,12 @@ -- To set a field as default NULL: -- VPGSQL8.2 ALTER TABLE llx_table ALTER COLUMN name SET DEFAULT NULL; -- Note: fields with type BLOB/TEXT can't have default value. + + + + -- For 8.0 + ALTER TABLE llx_societe ADD COLUMN fk_entrepot integer DEFAULT 0; + +ALTER TABLE llx_projet ADD COLUMN bill_time integer DEFAULT 0; \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_commandedet.sql b/htdocs/install/mysql/tables/llx_commandedet.sql index 81ba14cca2c..0d6468309f5 100644 --- a/htdocs/install/mysql/tables/llx_commandedet.sql +++ b/htdocs/install/mysql/tables/llx_commandedet.sql @@ -39,26 +39,26 @@ create table llx_commandedet remise real DEFAULT 0, -- montant de la remise fk_remise_except integer NULL, -- Lien vers table des remises fixes price real, -- prix final - subprice double(24,8) DEFAULT 0, -- P.U. HT (exemple 100) - total_ht double(24,8) DEFAULT 0, -- Total HT de la ligne toute quantite et incluant remise ligne et globale - total_tva double(24,8) DEFAULT 0, -- Total TVA de la ligne toute quantite et incluant remise ligne et globale - total_localtax1 double(24,8) DEFAULT 0, -- Total LocalTax1 - total_localtax2 double(24,8) DEFAULT 0, -- Total LocalTax2 - total_ttc double(24,8) DEFAULT 0, -- Total TTC de la ligne toute quantite et incluant remise ligne et globale - product_type integer DEFAULT 0, + subprice double(24,8) DEFAULT 0, -- P.U. HT (exemple 100) + total_ht double(24,8) DEFAULT 0, -- Total HT de la ligne toute quantite et incluant remise ligne et globale + total_tva double(24,8) DEFAULT 0, -- Total TVA de la ligne toute quantite et incluant remise ligne et globale + total_localtax1 double(24,8) DEFAULT 0, -- Total LocalTax1 + total_localtax2 double(24,8) DEFAULT 0, -- Total LocalTax2 + total_ttc double(24,8) DEFAULT 0, -- Total TTC de la ligne toute quantite et incluant remise ligne et globale + product_type integer DEFAULT 0, -- 0 or 1. Value 9 may be used by some modules (amount of line may not be included into generated discount if value is 9). date_start datetime DEFAULT NULL, -- date debut si service date_end datetime DEFAULT NULL, -- date fin si service info_bits integer DEFAULT 0, -- TVA NPR ou non - buy_price_ht double(24,8) DEFAULT 0, -- buying price + buy_price_ht double(24,8) DEFAULT 0, -- buying price fk_product_fournisseur_price integer DEFAULT NULL, -- reference of supplier price when line was added (may be used to update buy_price_ht current price when future invoice will be created) - special_code integer DEFAULT 0, -- code pour les lignes speciales + special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...) rang integer DEFAULT 0, - fk_unit integer DEFAULT NULL, -- lien vers table des unités + fk_unit integer DEFAULT NULL, -- lien vers table des unités import_key varchar(14), - fk_commandefourndet integer DEFAULT NULL, -- link to detail line of commande fourn (resplenish) + fk_commandefourndet integer DEFAULT NULL, -- link to detail line of commande fourn (resplenish) fk_multicurrency integer, multicurrency_code varchar(255), diff --git a/htdocs/install/mysql/tables/llx_facturedet.sql b/htdocs/install/mysql/tables/llx_facturedet.sql index 28c07e6d508..05c68e92751 100644 --- a/htdocs/install/mysql/tables/llx_facturedet.sql +++ b/htdocs/install/mysql/tables/llx_facturedet.sql @@ -47,7 +47,7 @@ create table llx_facturedet total_localtax1 double(24,8) DEFAULT 0, -- Total LocalTax1 for total quantity of line total_localtax2 double(24,8) DEFAULT 0, -- Total LocalTax2 for total quantity of line total_ttc double(24,8), -- Total TTC de la ligne toute quantite et incluant remise ligne et globale - product_type integer DEFAULT 0, + product_type integer DEFAULT 0, -- 0 or 1. Value 9 may be used by some modules (amount of line may not be included into generated discount if value is 9). date_start datetime DEFAULT NULL, -- date start if service date_end datetime DEFAULT NULL, -- date end if service info_bits integer DEFAULT 0, -- VAT NPR or not (for france only) @@ -57,7 +57,7 @@ create table llx_facturedet fk_code_ventilation integer DEFAULT 0 NOT NULL, -- Id in table llx_accounting_bookeeping to know accounting account for product line - special_code integer DEFAULT 0, -- code pour les lignes speciales + special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...) rang integer DEFAULT 0, -- position of line fk_contract_line integer NULL, -- id of contract line when invoice comes from contract lines import_key varchar(14), diff --git a/htdocs/install/mysql/tables/llx_projet.sql b/htdocs/install/mysql/tables/llx_projet.sql index 3875e64e1a7..8e58f0ad8c8 100644 --- a/htdocs/install/mysql/tables/llx_projet.sql +++ b/htdocs/install/mysql/tables/llx_projet.sql @@ -41,7 +41,8 @@ create table llx_projet note_public text, --budget_days real, -- budget in days is sum of field planned_workload of tasks opp_amount double(24,8), - budget_amount double(24,8), + budget_amount double(24,8), + bill_time integer DEFAULT 0, -- Set to 1 if time spent must be converted into invoices model_pdf varchar(255), import_key varchar(14) -- Import key )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_propaldet.sql b/htdocs/install/mysql/tables/llx_propaldet.sql index 70029acdb08..283708fd7ce 100644 --- a/htdocs/install/mysql/tables/llx_propaldet.sql +++ b/htdocs/install/mysql/tables/llx_propaldet.sql @@ -44,7 +44,7 @@ create table llx_propaldet total_localtax1 double(24,8) DEFAULT 0, -- Total localtax1 total_localtax2 double(24,8) DEFAULT 0, -- Total localtax2 total_ttc double(24,8) DEFAULT 0, -- Total TTC de la ligne toute quantite et incluant remise ligne et globale - product_type integer DEFAULT 0, + product_type integer DEFAULT 0, -- 0 or 1. Value 9 may be used by some modules (amount of line may not be included into generated discount if value is 9). date_start datetime DEFAULT NULL, -- date debut si service date_end datetime DEFAULT NULL, -- date fin si service info_bits integer DEFAULT 0, -- TVA NPR ou non @@ -52,8 +52,8 @@ create table llx_propaldet buy_price_ht double(24,8) DEFAULT 0, -- buying price fk_product_fournisseur_price integer DEFAULT NULL, -- reference of supplier price when line was added (may be used to update buy_price_ht current price when future invoice will be created) - special_code integer DEFAULT 0, -- code pour les lignes speciales - rang integer DEFAULT 0, -- ordre affichage sur la propal + special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...) + rang integer DEFAULT 0, -- ordre affichage sur la propal fk_unit integer DEFAULT NULL, -- lien vers table des unités fk_multicurrency integer, diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index c23ca3a183c..f6ee1f39220 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -33,8 +33,6 @@ create table llx_societe statut tinyint DEFAULT 0, -- statut parent integer, - tms timestamp, - datec datetime, -- creation date status tinyint DEFAULT 1, -- cessation d'activité ( 1 -- en activité, 0 -- cessation d'activité) @@ -57,15 +55,15 @@ create table llx_societe fk_typent integer DEFAULT 0, -- fk_forme_juridique integer DEFAULT 0, -- juridical status fk_currency varchar(3), -- default currency - siren varchar(128), -- IDProf1: siren or RCS for france - siret varchar(128), -- IDProf2: siret for france - ape varchar(128), -- IDProf3: code ape for france + siren varchar(128), -- IDProf1: siren or RCS for france, ... + siret varchar(128), -- IDProf2: siret for france, ... + ape varchar(128), -- IDProf3: code ape for france, ... idprof4 varchar(128), -- IDProf4: nu for france idprof5 varchar(128), -- IDProf5: nu for france idprof6 varchar(128), -- IDProf6: nu for france tva_intra varchar(20), -- tva - capital double(24,8), -- capital de la societe - fk_stcomm integer DEFAULT 0 NOT NULL, -- commercial statut + capital double(24,8) DEFAULT NULL, -- capital de la societe + fk_stcomm integer DEFAULT 0 NOT NULL, -- commercial statut note_private text, -- note_public text, -- model_pdf varchar(255), @@ -79,8 +77,6 @@ create table llx_societe customer_bad tinyint DEFAULT 0, -- mauvais payeur 0/1 customer_rate real DEFAULT 0, -- taux fiabilite client (0 a 1) supplier_rate real DEFAULT 0, -- taux fiabilite fournisseur (0 a 1) - fk_user_creat integer NULL, -- utilisateur qui a cree l'info - fk_user_modif integer, -- utilisateur qui a modifie l'info remise_client real DEFAULT 0, -- remise systematique pour le client mode_reglement tinyint, -- mode de reglement cond_reglement tinyint, -- condition de reglement @@ -99,10 +95,17 @@ create table llx_societe default_lang varchar(6), -- default language logo varchar(255) DEFAULT NULL, canvas varchar(32) DEFAULT NULL, -- type of canvas if used (null by default) - import_key varchar(14), -- import key + fk_entrepot integer DEFAULT 0, -- if we need a link between third party and warehouse webservices_url varchar(255), -- supplier webservice url webservices_key varchar(128), -- supplier webservice key - fk_multicurrency integer, - multicurrency_code varchar(255) + tms timestamp, -- last modification date + datec datetime, -- creation date + fk_user_creat integer NULL, -- utilisateur qui a cree l'info + fk_user_modif integer, -- utilisateur qui a modifie l'info + + fk_multicurrency integer, + multicurrency_code varchar(255), + + import_key varchar(14) -- import key )ENGINE=innodb; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index cae43a9e3b5..c2201c5d118 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -269,9 +269,10 @@ MAIN_MAIL_SMTP_SERVER=SMTP/SMTPS Host (By default in php.ini: %s) MAIN_MAIL_SMTP_PORT_NotAvailableOnLinuxLike=SMTP/SMTPS Port (Not defined into PHP on Unix like systems) MAIN_MAIL_SMTP_SERVER_NotAvailableOnLinuxLike=SMTP/SMTPS Host (Not defined into PHP on Unix like systems) MAIN_MAIL_EMAIL_FROM=Sender email for automatic emails (By default in php.ini: %s) -MAIN_MAIL_ERRORS_TO=Sender email used for error returns emails sent +MAIN_MAIL_ERRORS_TO=Email used as 'Errors-To' field in emails sent MAIN_MAIL_AUTOCOPY_TO= Send systematically a hidden carbon-copy of all sent emails to MAIN_DISABLE_ALL_MAILS=Disable all emails sendings (for test purposes or demos) +MAIN_MAIL_FORCE_SENDTO=Send all emails to (instead of real recipients, for test purposes) MAIN_MAIL_SENDMODE=Method to use to send EMails MAIN_MAIL_SMTPS_ID=SMTP ID if authentication required MAIN_MAIL_SMTPS_PW=SMTP Password if authentication required @@ -415,7 +416,7 @@ ExtrafieldParamHelpcheckbox=List of values must be lines with format key,value ( ExtrafieldParamHelpradio=List of values must be lines with format key,value (where key can't be '0')

    for example :
    1,value1
    2,value2
    3,value3
    ... ExtrafieldParamHelpsellist=List of values comes from a table
    Syntax : table_name:label_field:id_field::filter
    Example : c_typent:libelle:id::filter

    - idfilter is necessarly a primary int key
    - filter can be a simple test (eg active=1) to display only active value
    You can also use $ID$ in filter witch is the current id of current object
    To do a SELECT in filter use $SEL$
    if you want to filter on extrafields use syntax extra.fieldcode=... (where field code is the code of extrafield)

    In order to have the list depending on another complementary attribute list:
    c_typent:libelle:id:options_parent_list_code|parent_column:filter

    In order to have the list depending on another list:
    c_typent:libelle:id:parent_list_code|parent_column:filter ExtrafieldParamHelpchkbxlst=List of values comes from a table
    Syntax : table_name:label_field:id_field::filter
    Example : c_typent:libelle:id::filter

    filter can be a simple test (eg active=1) to display only active value
    You can also use $ID$ in filter witch is the current id of current object
    To do a SELECT in filter use $SEL$
    if you want to filter on extrafields use syntax extra.fieldcode=... (where field code is the code of extrafield)

    In order to have the list depending on another complementary attribute list :
    c_typent:libelle:id:options_parent_list_code|parent_column:filter

    In order to have the list depending on another list:
    c_typent:libelle:id:parent_list_code|parent_column:filter -ExtrafieldParamHelplink=Parameters must be ObjectName:Classpath
    Syntax : ObjectName:Classpath
    Example : Societe:societe/class/societe.class.php +ExtrafieldParamHelplink=Parameters must be ObjectName:Classpath
    Syntax : ObjectName:Classpath
    Examples :
    Societe:societe/class/societe.class.php
    Contact:contact/class/contact.class.php LibraryToBuildPDF=Library used for PDF generation WarningUsingFPDF=Warning: Your conf.php contains directive dolibarr_pdf_force_fpdf=1. This means you use the FPDF library to generate PDF files. This library is old and does not support a lot of features (Unicode, image transparency, cyrillic, arab and asiatic languages, ...), so you may experience errors during PDF generation.
    To solve this and have a full support of PDF generation, please download TCPDF library, then comment or remove the line $dolibarr_pdf_force_fpdf=1, and add instead $dolibarr_lib_TCPDF_PATH='path_to_TCPDF_dir' LocalTaxDesc=Some countries apply 2 or 3 taxes on each invoice line. If this is the case, choose type for second and third tax and its rate. Possible type are:
    1 : local tax apply on products and services without vat (localtax is calculated on amount without tax)
    2 : local tax apply on products and services including vat (localtax is calculated on amount + main tax)
    3 : local tax apply on products without vat (localtax is calculated on amount without tax)
    4 : local tax apply on products including vat (localtax is calculated on amount + main vat)
    5 : local tax apply on services without vat (localtax is calculated on amount without tax)
    6 : local tax apply on services including vat (localtax is calculated on amount + tax) diff --git a/htdocs/langs/en_US/blockedlog.lang b/htdocs/langs/en_US/blockedlog.lang index 93f64bddbaa..9f6a49a5146 100644 --- a/htdocs/langs/en_US/blockedlog.lang +++ b/htdocs/langs/en_US/blockedlog.lang @@ -14,6 +14,9 @@ OkCheckFingerprintValidityButChainIsKo=Archived log seems valid compared to prev AddedByAuthority=Stored into remote authority NotAddedByAuthorityYet=Not yet stored into remote authority ShowDetails=Show stored details +logPAYMENT_VARIOUS_CREATE=Payment (not assigned to invoice) created +logPAYMENT_VARIOUS_MODIFY=Payment (not assigned to invoice) modified +logPAYMENT_VARIOUS_DELETE=Payment (not assigned to invoice) logical deletion logPAYMENT_ADD_TO_BANK=Payment added to bank logPAYMENT_CUSTOMER_CREATE=Customer payment created logPAYMENT_CUSTOMER_DELETE=Customer payment logical deletion @@ -41,7 +44,7 @@ DownloadLogCSV=Export archived logs (CSV) logDOC_PREVIEW=Preview of a validated document in order to print or download logDOC_DOWNLOAD=Download of a validated document in order to print or send DataOfArchivedEvent=Full datas of archived event -ImpossibleToReloadObject=Object (type %s, id %s) removed (see 'Full data' link for unerasable saved data) +ImpossibleToReloadObject=Original object (type %s, id %s) not linked (see 'Full datas' column to get unalterable saved data) BlockedLogAreRequiredByYourCountryLegislation=Unalterable Logs module may be required by the legislation of your country. Disabling this module may render any future transactions invalid with respect to the law and the use of legal software as they can not be validated by a tax audit. BlockedLogActivatedBecauseRequiredByYourCountryLegislation=Unalterable Logs module was activated because of the legislation of your country. Disabling this module may render any future transactions invalid with respect to the law and the use of legal software as they can not be validated by a tax audit. BlockedLogDisableNotAllowedForCountry=List of countries where usage of this module is mandatory (just to prevent to disable the module by error, if your country is in this list, disable of module is not possible without editing this list first. Note also that enabling/disabling this module will keep a track into the unalterable log). diff --git a/htdocs/langs/en_US/compta.lang b/htdocs/langs/en_US/compta.lang index e54d613628e..632ef67feb9 100644 --- a/htdocs/langs/en_US/compta.lang +++ b/htdocs/langs/en_US/compta.lang @@ -1,5 +1,5 @@ # Dolibarr language file - Source file is en_US - compta -MenuFinancial=Billing / Payment +MenuFinancial=Billing | Payment TaxModuleSetupToModifyRules=Go to Taxes module setup to modify rules for calculation TaxModuleSetupToModifyRulesLT=Go to Company setup to modify rules for calculation OptionMode=Option for accountancy diff --git a/htdocs/langs/en_US/mails.lang b/htdocs/langs/en_US/mails.lang index 4be167d3061..8e2b093fdc2 100644 --- a/htdocs/langs/en_US/mails.lang +++ b/htdocs/langs/en_US/mails.lang @@ -87,6 +87,7 @@ MailingModuleDescEmailsFromFile=Emails from file MailingModuleDescEmailsFromUser=Emails input by user MailingModuleDescDolibarrUsers=Users with Emails MailingModuleDescThirdPartiesByCategories=Third parties (by categories) +SendingFromWebInterfaceIsNotAllowed=Sending from web interface is not allowed. # Libelle des modules de liste de destinataires mailing LineInFile=Line %s in file diff --git a/htdocs/langs/en_US/salaries.lang b/htdocs/langs/en_US/salaries.lang index 2a3372ed847..f1db7ea1cf3 100644 --- a/htdocs/langs/en_US/salaries.lang +++ b/htdocs/langs/en_US/salaries.lang @@ -1,7 +1,7 @@ # Dolibarr language file - Source file is en_US - salaries SALARIES_ACCOUNTING_ACCOUNT_PAYMENT=Accounting account used for user third parties SALARIES_ACCOUNTING_ACCOUNT_PAYMENT_Desc=The dedicated accounting account defined on user card will be used for Subledger accouting only. This one will be used for General Ledger and as default value of Subledger accounting if dedicated user accouting account on user is not defined. -SALARIES_ACCOUNTING_ACCOUNT_CHARGE=Accounting account by default for personnel expenses +SALARIES_ACCOUNTING_ACCOUNT_CHARGE=Accounting account by default for wage payments Salary=Salary Salaries=Salaries NewSalaryPayment=New salary payment diff --git a/htdocs/langs/es_ES/accountancy.lang b/htdocs/langs/es_ES/accountancy.lang index a5e4fbdf465..59c20932702 100644 --- a/htdocs/langs/es_ES/accountancy.lang +++ b/htdocs/langs/es_ES/accountancy.lang @@ -25,8 +25,8 @@ Chartofaccounts=Plan contable CurrentDedicatedAccountingAccount=Cuenta contable dedicada AssignDedicatedAccountingAccount=Nueva cuenta a asignar InvoiceLabel=Etiqueta factura -OverviewOfAmountOfLinesNotBound=Ver la cantidad de líneas no ligadas a cuentas contables -OverviewOfAmountOfLinesBound=Ver la cantidad de líneas ligadas a cuentas contables +OverviewOfAmountOfLinesNotBound=Ver la cantidad de líneas no vinculadas a una cuenta contable +OverviewOfAmountOfLinesBound=Ver la cantidad de líneas vinculadas a una cuenta contable OtherInfo=Otra información DeleteCptCategory=Eliminar la cuenta contable del grupo ConfirmDeleteCptCategory=¿Está seguro de querer eliminar esta cuenta contable del grupo de cuentas contables? @@ -158,7 +158,7 @@ NumPiece=Apunte TransactionNumShort=Núm. transacción AccountingCategory=Grupos personalizados GroupByAccountAccounting=Agrupar por cuenta contable -AccountingAccountGroupsDesc=You can define here some groups of accounting account. They will be used for personalized accounting reports. +AccountingAccountGroupsDesc=Puedes definir aquí algunos grupos de cuentas contables. Se usarán para informes de contabilidad personalizados. ByAccounts=Por cuentas ByPredefinedAccountGroups=Por grupos predefinidos ByPersonalizedAccountGroups=Por grupos personalizados @@ -173,7 +173,7 @@ DelBookKeeping=Eliminar los registros del Libro Mayor FinanceJournal=Diario financiero ExpenseReportsJournal=Diario informe de gastos DescFinanceJournal=El diario financiero incluye todos los tipos de pagos por cuenta bancaria -DescJournalOnlyBindedVisible=Esta es una vista de registros que están vinculados a una cuenta contable y pueden ser registrados en el Libro Mayor. +DescJournalOnlyBindedVisible=Esta es una vista del registro vinculado a una cuenta contable y que se puede registrar en el Libro Mayor. VATAccountNotDefined=Cuenta contable para IVA no definida ThirdpartyAccountNotDefined=Cuenta contable de tercero no definida ProductAccountNotDefined=Cuenta contable de producto no definida @@ -191,7 +191,7 @@ DescThirdPartyReport=Consulte aquí el listado de clientes y proveedores y sus c ListAccounts=Listado de cuentas contables UnknownAccountForThirdparty=Cuenta contable de tercero desconocida, usaremos %s UnknownAccountForThirdpartyBlocking=Cuenta contable de tercero desconocida. Error de bloqueo -UnknownAccountForThirdpartyAndWaitingAccountNotDefinedBlocking=Unknown third party account and waiting account not defined. Blocking error +UnknownAccountForThirdpartyAndWaitingAccountNotDefinedBlocking=Cuenta del terceros desconocida y cuenta de espera no definida. Error de bloqueo Pcgtype=Grupo de cuenta Pcgsubtype=Subgrupo de cuenta @@ -224,6 +224,8 @@ GeneralLedgerSomeRecordWasNotRecorded=Algunas de las operaciones que no podrán NoNewRecordSaved=No hay más registros para el diario ListOfProductsWithoutAccountingAccount=Listado de productos sin cuentas contables ChangeBinding=Cambiar la unión +Accounted=Contabilizada en el Libro Mayor +NotYetAccounted=Aún no contabilizada en el Libro Mayor ## Admin ApplyMassCategories=Aplicar categorías en masa diff --git a/htdocs/langs/es_ES/admin.lang b/htdocs/langs/es_ES/admin.lang index c8e8d5cfe43..02057302f8a 100644 --- a/htdocs/langs/es_ES/admin.lang +++ b/htdocs/langs/es_ES/admin.lang @@ -260,18 +260,18 @@ FontSize=Tamaño de fuente Content=Contenido NoticePeriod=Plazo de aviso NewByMonth=Nuevo por mes -Emails=Emails -EMailsSetup=Configuración emails +Emails=E-Mails +EMailsSetup=Configuración e-mails EMailsDesc=Esta página le permite sobrescribir sus parámetros de PHP para el envío de correos electrónicos. En la mayoría de los casos, en el sistema operativo Unix/Linux, su configuración de PHP es correcta y estos parámetros son inútiles. EmailSenderProfiles=Perfiles de remitentes de e-mails MAIN_MAIL_SMTP_PORT=Puerto del servidor SMTP (Por defecto en php.ini: %s) MAIN_MAIL_SMTP_SERVER=Nombre host o ip del servidor SMTP (Por defecto en php.ini: %s) MAIN_MAIL_SMTP_PORT_NotAvailableOnLinuxLike=Puerto del servidor SMTP (No definido en PHP en sistemas de tipo Unix) MAIN_MAIL_SMTP_SERVER_NotAvailableOnLinuxLike=Nombre servidor o ip del servidor SMTP (No definido en PHP en sistemas de tipo Unix) -MAIN_MAIL_EMAIL_FROM=Correo electrónico del remitente para correos electrónicos automáticos (por defecto en php.ini: %s) -MAIN_MAIL_ERRORS_TO=Correo electrónico del remitente utilizado para los correos electrónicos de error enviados +MAIN_MAIL_EMAIL_FROM=E-mail del remitente para e-mails automáticos (por defecto en php.ini: %s) +MAIN_MAIL_ERRORS_TO=E-mail del remitente utilizado para los e-mails de error enviados MAIN_MAIL_AUTOCOPY_TO= Enviar automáticamente copia oculta de los e-mails enviados a -MAIN_DISABLE_ALL_MAILS=Deshabilitar todos los envíos de correos electrónicos (para propósitos de prueba o demostraciones) +MAIN_DISABLE_ALL_MAILS=Deshabilitar todos los envíos de e-mail (para propósitos de prueba o demostraciones) MAIN_MAIL_SENDMODE=Método de envío de e-mails MAIN_MAIL_SMTPS_ID=ID de autentificación SMTP si se requiere autenticación SMTP MAIN_MAIL_SMTPS_PW=Contraseña autentificación SMTP si se requiere autentificación SMTP @@ -410,11 +410,11 @@ ExtrafieldCheckBoxFromList=Casilla de selección de tabla ExtrafieldLink=Objeto adjuntado ComputedFormula=Campo combinado ComputedFormulaDesc=Puede introducir aquí una fórmula utilizando otras propiedades de objeto o cualquier código PHP para obtener un valor calculado dinámico. Puede utilizar cualquier fórmula compatible con PHP, incluido el operador de condición "?" y los objetos globales siguientes: $db, $conf, $langs, $mysoc, $user, $object.
    ATENCIÓN: Sólo algunas propiedades de $object pueden estar disponibles. Si necesita propiedades no cargadas, solo busque el objeto en su fórmula como en el segundo ejemplo.
    Usando un campo computado significa que no puede ingresar ningún valor de la interfaz. Además, si hay un error de sintaxis, la fórmula puede devolver nada.

    Ejemplo de fórmula:
    $object->id < 10 ? round($object->id / 2, 2) : ($object->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)

    Ejemlo de recarga de objeto
    (($reloadedobj = new Societe($db)) && ($reloadedobj->fetch($obj->id ? $obj->id : ($obj->rowid ? $obj->rowid : $object->id)) > 0)) ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5 : '-1'

    Otro ejemplo de fórmula para forzar la carga del objeto y su objeto principal:
    (($reloadedobj = new Task($db)) && ($reloadedobj->fetch($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetch($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : 'Parent project not found' -ExtrafieldParamHelpselect=El listado de parámetros tiene que ser key,valor

    por ejemplo:
    1,value1
    2,value2
    3,value3
    ...

    Para tener una lista en funcion de atributos complementarios de lista:
    1,value1|options_parent_list_code:parent_key
    2,value2|options_parent_list_code:parent_key

    Para tener la lista en función de otra:
    1,value1|parent_list_code:parent_key
    2,value2|parent_list_code:parent_key +ExtrafieldParamHelpselect=El listado de parámetros tiene que ser key,valor

    por ejemplo:
    1,value1
    2,value2
    3,value3
    ...

    Para tener una lista en funcion de campos adicionales de lista:
    1,value1|options_parent_list_code:parent_key
    2,value2|options_parent_list_code:parent_key

    Para tener la lista en función de otra:
    1,value1|parent_list_code:parent_key
    2,value2|parent_list_code:parent_key ExtrafieldParamHelpcheckbox=El listado de parámetros tiene que ser key,valor

    por ejemplo:
    1,value1
    2,value2
    3,value3
    ... ExtrafieldParamHelpradio=El listado de parámetros tiene que ser key,valor (donde key no puede ser 0)

    por ejemplo:
    1,value1
    2,value2
    3,value3
    ... -ExtrafieldParamHelpsellist=Lista de parámetros proviene de una tabla
    Sintaxis: nombre_tabla: etiqueta_field: id_field :: filtro
    Ejemplo: c_typent: libelle: id :: filtro

    filtro puede ser una prueba simple (por ejemplo, activa = 1) Para mostrar sólo el valor activo
    También puede utilizar $ ID $ en el filtro witch es el actual id del objeto actual
    Para hacer un SELECT en el filtro de uso $ SEL $
    si desea filtrar en extrafields utilizar la sintaxis Extra.fieldcode = ... (donde código de campo es el código de extrafield)

    Para que la lista dependa de otra lista de atributos complementarios:
    c_typent: libelle: id: options_ parent_list_code | parent_column: filter

    Para que la lista dependa de otra lista:
    c_typent: libelle: id: parent_list_code | parent_column: filter -ExtrafieldParamHelpchkbxlst=Lista de parámetros proviene de una tabla
    Sintaxis: nombre_tabla: etiqueta_field: id_field :: filtro
    Ejemplo: c_typent: libelle: id :: filtro

    filtro puede ser una prueba simple (por ejemplo, activa = 1) Para mostrar sólo el valor activo
    También puede utilizar $ ID $ en el filtro witch es el id actual del objeto actual
    Para hacer un SELECT en el filtro de uso $ SEL $
    si desea filtrar en extrafields utilizar la sintaxis Extra.fieldcode = ... (donde código de campo es el código de extrafield)

    Para que la lista dependa de otra lista de atributos complementarios:
    c_typent: libelle: id: options_ parent_list_code | parent_column: filter

    Para que la lista dependa de otra lista:
    c_typent: libelle: id: parent_list_code | parent_column: filter +ExtrafieldParamHelpsellist=Lista de parámetros proviene de una tabla
    Sintaxis: nombre_tabla: etiqueta_field: id_field :: filtro
    Ejemplo: c_typent: libelle: id :: filtro

    filtro puede ser una prueba simple (por ejemplo, activa = 1) Para mostrar sólo el valor activo
    También puede utilizar $ ID $ en el filtro witch es el actual id del objeto actual
    Para hacer un SELECT en el filtro de uso $ SEL $
    si desea filtrar en campos adicionales utilizar la sintaxis Extra.fieldcode = ... (donde código de campo es el código de campo adicional)

    Para que la lista dependa de otra lista de campos adicionales:
    c_typent: libelle: id: options_ parent_list_code | parent_column: filter

    Para que la lista dependa de otra lista:
    c_typent: libelle: id: parent_list_code | parent_column: filter +ExtrafieldParamHelpchkbxlst=Lista de parámetros proviene de una tabla
    Sintaxis: nombre_tabla: etiqueta_field: id_field :: filtro
    Ejemplo: c_typent: libelle: id :: filtro

    filtro puede ser una prueba simple (por ejemplo, activa = 1) Para mostrar sólo el valor activo
    También puede utilizar $ ID $ en el filtro witch es el id actual del objeto actual
    Para hacer un SELECT en el filtro de uso $ SEL $
    si desea filtrar en campos adicionales utilizar la sintaxis Extra.fieldcode = ... (donde código de campo es el código de campo adicional)

    Para que la lista dependa de otra lista de campos adicionales:
    c_typent: libelle: id: options_ parent_list_code | parent_column: filter

    Para que la lista dependa de otra lista:
    c_typent: libelle: id: parent_list_code | parent_column: filter ExtrafieldParamHelplink=Los parámetros deben ser ObjectName: Classpath
    Sintaxis: ObjectName:Classpath
    Ejemplo: Societe:societe/class/societe.class.php LibraryToBuildPDF=Libreria usada en la generación de los PDF WarningUsingFPDF=Atención: Su archivo conf.php contiene la directiva dolibarr_pdf_force_fpdf=1. Esto hace que se use la librería FPDF para generar sus archivos PDF. Esta librería es antigua y no cubre algunas funcionalidades (Unicode, transparencia de imágenes, idiomas cirílicos, árabes o asiáticos, etc.), por lo que puede tener problemas en la generación de los PDF.
    Para resolverlo, y disponer de un soporte completo de PDF, puede descargar la librería TCPDF , y a continuación comentar o eliminar la línea $dolibarr_pdf_force_fpdf=1, y añadir en su lugar $dolibarr_lib_TCPDF_PATH='ruta_a_TCPDF' @@ -551,6 +551,8 @@ Module520Desc=Gestión de créditos Module600Name=Notificaciones Module600Desc=Enviar notificaciones por e-mail (desencadenados por algunos eventos) a los usuarios (configuración definida para cada usuario), los contactos de terceros (configuración definida en cada tercero) o e-mails fijos Module600Long=Tenga en cuenta que este módulo está dedicado a enviar mensajes de e-mail en tiempo real cuando se produce un evento. Si está buscando una función para enviar recordatorios por e-mail de los eventos de su agenda, vaya a la configuración del módulo Agenda. +Module610Name=Variantes de productos +Module610Desc=Permite la creación de variantes de productos en función de los atributos (color, tamaño, ...) Module700Name=Donaciones Module700Desc=Gestión de donaciones Module770Name=Informes de gastos @@ -598,7 +600,7 @@ Module10000Name=Sitios web Module10000Desc=Cree sitios web públicos con un editor WYSIWYG. Configure el servidor web (Apache, Nginx,...) para que apunte al directorio dedicado para tenerlo en línea en Internet. Module20000Name=Gestión de días libres retribuidos Module20000Desc=Gestión de los días libres retribuidos de los empleados -Module39000Name=Lotes de producto +Module39000Name=Lotes de productos Module39000Desc=Gestión de lotes o series, fechas de caducidad y venta de los productos Module50000Name=PayBox Module50000Desc=Módulo para ofrecer pagos online aceptando pagos con tarjeta de Débito/Crédito via PayBox. Esto puede ser usado para permitir a tus clientes realizar pagos libres o pagos en un objeto de Dolibarr en particular (factura, pedido...) @@ -824,12 +826,12 @@ Permission1232=Crear facturas de proveedores Permission1233=Validar facturas de proveedores Permission1234=Eliminar facturas de proveedores Permission1235=Enviar facturas de proveedores por correo -Permission1236=Exportar facturas de proveedores, atributos y pagos +Permission1236=Exportar facturas de proveedores, campos adicionales y pagos Permission1237=Exportar pedidos de proveedores junto con sus detalles Permission1251=Lanzar las importaciones en masa a la base de datos (carga de datos) -Permission1321=Exportar facturas a clientes, atributos y cobros +Permission1321=Exportar facturas a clientes, campos adicionales y cobros Permission1322=Reabrir una factura pagada -Permission1421=Exportar pedidos de clientes y atributos +Permission1421=Exportar pedidos de clientes y campos adicionales Permission20001=Leer peticiones días retribuidos (suyos y subordinados) Permission20002=Cear/modificar sus días retribuidos Permission20003=Eliminar peticiones de días retribuidos @@ -890,7 +892,7 @@ DictionaryStaff=Empleados DictionaryAvailability=Tiempos de entrega DictionaryOrderMethods=Métodos de pedido DictionarySource=Orígenes de presupuestos/pedidos -DictionaryAccountancyCategory=Personalized groups for reports +DictionaryAccountancyCategory=Grupos personalizados para imformes DictionaryAccountancysystem=Modelos de planes contables DictionaryAccountancyJournal=Diarios contables DictionaryEMailTemplates=Plantillas E-Mails @@ -1108,23 +1110,23 @@ MAIN_PROXY_HOST=Nombre/Dirección del servidor proxy MAIN_PROXY_PORT=Puerto del servidor proxy MAIN_PROXY_USER=Login del servidor proxy MAIN_PROXY_PASS=Contraseña del servidor proxy -DefineHereComplementaryAttributes=Defina aquí la lista de atributos adicionales, no disponibles por defecto, y que desea gestionar para %s. -ExtraFields=Atributos adicionales -ExtraFieldsLines=Atributos adicionales (líneas) -ExtraFieldsLinesRec=Atributos complementarios (plantillas de líneas de facturas) -ExtraFieldsSupplierOrdersLines=Atributos complementarios (líneas de pedido) -ExtraFieldsSupplierInvoicesLines=Atributos complementarios (líneas de factura) -ExtraFieldsThirdParties=Atributos adicionales (terceros) -ExtraFieldsContacts=Atributos adicionales (contactos/direcciones) -ExtraFieldsMember=Atributos adicionales (miembros) -ExtraFieldsMemberType=Atributos adicionales (tipos de miembros) -ExtraFieldsCustomerInvoices=Atributos adicionales (facturas a clientes) -ExtraFieldsCustomerInvoicesRec=Atributos complementarios (plantillas de facturas) -ExtraFieldsSupplierOrders=Atributos adicionales (pedidos a proveedores) -ExtraFieldsSupplierInvoices=Atributos adicionales (facturas) -ExtraFieldsProject=Atributos adicionales (proyectos) -ExtraFieldsProjectTask=Atributos adicionales (tareas) -ExtraFieldHasWrongValue=El atributo %s tiene un valor no válido +DefineHereComplementaryAttributes=Defina aquí la lista de campos adicionales, no disponibles por defecto, y que desea gestionar para %s. +ExtraFields=Campos adicionales +ExtraFieldsLines=Campos adicionales (líneas) +ExtraFieldsLinesRec=Campos adicionales (plantillas de líneas de facturas) +ExtraFieldsSupplierOrdersLines=Campos adicionales (líneas de pedido) +ExtraFieldsSupplierInvoicesLines=Campos adicionales (líneas de factura) +ExtraFieldsThirdParties=Campos adicionales (terceros) +ExtraFieldsContacts=Campos adicionales (contactos/direcciones) +ExtraFieldsMember=Campos adicionales (miembros) +ExtraFieldsMemberType=Campos adicionales (tipos de miembros) +ExtraFieldsCustomerInvoices=Campos adicionales (facturas a clientes) +ExtraFieldsCustomerInvoicesRec=Campos adicionales (plantillas de facturas) +ExtraFieldsSupplierOrders=Campos adicionales (pedidos a proveedores) +ExtraFieldsSupplierInvoices=Campos adicionales (facturas) +ExtraFieldsProject=Campos adicionales (proyectos) +ExtraFieldsProjectTask=Campos adicionales (tareas) +ExtraFieldHasWrongValue=El campo %s tiene un valor no válido AlphaNumOnlyLowerCharsAndNoSpace=sólo alfanuméricos y minúsculas sin espacio SendmailOptionNotComplete=Atención, en algunos sistemas Linux, con este método de envio, para poder enviar mails en su nombre, la configuración de sendmail debe contener la opción -ba (parámetro mail.force_extra_parameters en el archivo php.ini). Si algunos de sus destinatarios no reciben sus mensajes, pruebe a modificar este parámetro PHP con mail.force_extra_parameters=-ba. PathToDocuments=Rutas de acceso a documentos @@ -1303,17 +1305,17 @@ LDAPContactDnExample=DN completo (ej: ou=contacts,dc=example,dc=com) LDAPMemberDn=DN de los miembros LDAPMemberDnExample=DN completo (ex: ou=members,dc=society,dc=com) LDAPMemberObjectClassList=Lista de objectClass -LDAPMemberObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user for active directory) +LDAPMemberObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user para active directory) LDAPMemberTypeDn=Tipos DN de miembros de Dolibar LDAPMemberTypepDnExample=DN completo (por ejemplo, ou=memberstypes, dc=example, dc=com) LDAPMemberTypeObjectClassList=Lista de objectClass LDAPMemberTypeObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,groupOfUniqueNames) LDAPUserObjectClassList=Lista de objectClass -LDAPUserObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user for active directory) +LDAPUserObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user para active directory) LDAPGroupObjectClassList=Lista de objectClass LDAPGroupObjectClassListExample=Lista de ObjectClass que definen los atributos de un registro (ej: top,groupOfUniqueNames) LDAPContactObjectClassList=Lista de objectClass -LDAPContactObjectClassListExample=Lista de objectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user for active directory) +LDAPContactObjectClassListExample=Lista de objectClass que definen los atributos de un registro (ej: top,inetOrgPerson o top,user para active directory) LDAPTestConnect=Probar la conexión LDAP LDAPTestSynchroContact=Probar la sincronización de contactos LDAPTestSynchroUser=Probar la sincronización de usuarios @@ -1728,21 +1730,21 @@ SeeSubstitutionVars=Vea * nota para un listado de posibles variables de sustituc SeeChangeLog=Ver archivo ChangeLog (solo inglés) AllPublishers=Todos los editores UnknownPublishers=Editores desconocidos -AddRemoveTabs=Añadir o eliminar pestañas -AddDataTables=Añadir tablas de objetos -AddDictionaries=Añadir diccionarios -AddData=Agregar objetos o datos de diccionarios -AddBoxes=Añadir paneles -AddSheduledJobs=Añadir tareas programadas -AddHooks=Añadir hooks -AddTriggers=Añadir triggers -AddMenus=Añadir menús -AddPermissions=Añadir permisos -AddExportProfiles=Añadir perfiles de exportación -AddImportProfiles=Añadir perfiles de importación -AddOtherPagesOrServices=Añadir otras páginas o servicios -AddModels=Añadir modelos de documentos o numeración -AddSubstitutions=Añadir substituciones de claves +AddRemoveTabs=Añade o elimina pestañas +AddDataTables=Añade tablas de objetos +AddDictionaries=Añade diccionarios +AddData=Añade objetos o datos de diccionarios +AddBoxes=Añade paneles +AddSheduledJobs=Añade tareas programadas +AddHooks=Añade hooks +AddTriggers=Añade triggers +AddMenus=Añade menús +AddPermissions=Añade permisos +AddExportProfiles=Añade perfiles de exportación +AddImportProfiles=Añade perfiles de importación +AddOtherPagesOrServices=Añade otras páginas o servicios +AddModels=Añade modelos de documentos o numeración +AddSubstitutions=Añade substituciones de claves DetectionNotPossible=No es posible la detección UrlToGetKeyToUseAPIs=Url para conseguir token para usar la API (una vez recibido el token se guarda en la tabla de usuarios de la base de datos y se debe proporcionar en cada llamada API) ListOfAvailableAPIs=Listado de APIs disponibles diff --git a/htdocs/langs/es_ES/bills.lang b/htdocs/langs/es_ES/bills.lang index 7cf978aba75..2ece66711c7 100644 --- a/htdocs/langs/es_ES/bills.lang +++ b/htdocs/langs/es_ES/bills.lang @@ -178,7 +178,7 @@ ConfirmCancelBillQuestion=¿Porqué quiere clasificar esta factura como 'abandon ConfirmClassifyPaidPartially=¿Está seguro de querer cambiar el estado de la factura %s a pagado? ConfirmClassifyPaidPartiallyQuestion=Esta factura no ha sido pagado completamente. ¿Cual es la razón para cerrar esta factura? ConfirmClassifyPaidPartiallyReasonAvoir=El resto a pagar (%s %s) es un descuento otorgado por pronto pago. Regularizaré el IVA con un abono. -ConfirmClassifyPaidPartiallyReasonDiscount=Remaining unpaid (%s %s) is a discount granted because payment was made before term. +ConfirmClassifyPaidPartiallyReasonDiscount=El resto a pagar (%s%s) es un descuento otorgado por pronto pago. ConfirmClassifyPaidPartiallyReasonDiscountNoVat=El resto a pagar (%s %s) es un descuento otorgado por pronto pago. Acepto perder el IVA en este descuento. ConfirmClassifyPaidPartiallyReasonDiscountVat=El resto a pagar (%s %s) es un descuento otorgado por pronto pago. Recuperaré el IVA sin usar un abono. ConfirmClassifyPaidPartiallyReasonBadCustomer=Cliente moroso diff --git a/htdocs/langs/es_ES/categories.lang b/htdocs/langs/es_ES/categories.lang index 9d83ca86817..6a834e36fea 100644 --- a/htdocs/langs/es_ES/categories.lang +++ b/htdocs/langs/es_ES/categories.lang @@ -78,7 +78,7 @@ CatCusLinks=Enlaces entre clientes/clientes potenciales y etiquetas/categorías CatProdLinks=Enlaces entre productos/servicios y etiquetas/categorías CatProJectLinks=Enlaces entre proyectos y etiquetas/categorías DeleteFromCat=Eliminar de la etiqueta/categoría -ExtraFieldsCategories=Atributos complementarios +ExtraFieldsCategories=Campos adicionales CategoriesSetup=Configuración de etiquetas/categorías CategorieRecursiv=Enlazar con la etiqueta/categoría automáticamente CategorieRecursivHelp=Si está activado, el producto se enlazará a la categoría padre si lo añadimos a una subcategoría diff --git a/htdocs/langs/es_ES/companies.lang b/htdocs/langs/es_ES/companies.lang index 98fcc553b0d..d70114dacae 100644 --- a/htdocs/langs/es_ES/companies.lang +++ b/htdocs/langs/es_ES/companies.lang @@ -374,9 +374,9 @@ ContactNotLinkedToCompany=Contacto no vinculado a un tercero DolibarrLogin=Login usuario NoDolibarrAccess=Sin acceso de usuario ExportDataset_company_1=Terceros (Empresas / asociaciones / particulares) y propiedades -ExportDataset_company_2=Contactos de terceros y atributos +ExportDataset_company_2=Contactos de terceros y campos adicionales ImportDataset_company_1=Terceros (Empresas / asociaciones / particulares) y propiedades -ImportDataset_company_2=Contactos/Direcciones (de terceros o no) y atributos +ImportDataset_company_2=Contactos/Direcciones (de terceros o no) y campos adicionales ImportDataset_company_3=Cuentas bancarias ImportDataset_company_4=Terceros/Comerciales (Afecta a los usuarios comerciales de terceros) PriceLevel=Nivel de precios diff --git a/htdocs/langs/es_ES/compta.lang b/htdocs/langs/es_ES/compta.lang index 18eb89f6dbd..277c8f8fcf5 100644 --- a/htdocs/langs/es_ES/compta.lang +++ b/htdocs/langs/es_ES/compta.lang @@ -24,7 +24,7 @@ PaymentsNotLinkedToInvoice=Pagos vinculados a ninguna factura, por lo que ningu PaymentsNotLinkedToUser=Pagos no vinculados a un usuario Profit=Beneficio AccountingResult=Resultado contable -BalanceBefore=Balance (before) +BalanceBefore=Balance (antes) Balance=Saldo Debit=Debe Credit=Haber diff --git a/htdocs/langs/es_ES/donations.lang b/htdocs/langs/es_ES/donations.lang index fddc435971d..0b6c7d207f3 100644 --- a/htdocs/langs/es_ES/donations.lang +++ b/htdocs/langs/es_ES/donations.lang @@ -31,4 +31,4 @@ DONATION_ART200=Mostrar artículo 200 del CGI si se está interesado DONATION_ART238=Mostrar artículo 238 del CGI si se está interesado DONATION_ART885=Mostrar artículo 885 del CGI si se está interesado DonationPayment=Pago de donación -DonationValidated=Donation %s validated +DonationValidated=Donación %s validada diff --git a/htdocs/langs/es_ES/languages.lang b/htdocs/langs/es_ES/languages.lang index d460b1e968f..ec9b14b68fc 100644 --- a/htdocs/langs/es_ES/languages.lang +++ b/htdocs/langs/es_ES/languages.lang @@ -35,7 +35,7 @@ Language_es_PA=Español (Panamá) Language_es_PY=Español (Paraguay) Language_es_PE=Español (Perú) Language_es_PR=Español (Puerto Rico) -Language_es_UY=Spanish (Uruguay) +Language_es_UY=Español (Uruguay) Language_es_VE=Español (Venezuela) Language_et_EE=Estonio Language_eu_ES=Vasco diff --git a/htdocs/langs/es_ES/main.lang b/htdocs/langs/es_ES/main.lang index 729daa6ebcf..310a4b5dd6c 100644 --- a/htdocs/langs/es_ES/main.lang +++ b/htdocs/langs/es_ES/main.lang @@ -722,8 +722,8 @@ After=Después IPAddress=Dirección IP Frequency=Frecuencia IM=Mensajería instantánea -NewAttribute=Nuevo atributo -AttributeCode=Código atributo +NewAttribute=Nuevo campo +AttributeCode=Código URLPhoto=Url de la foto/logo SetLinkToAnotherThirdParty=Vincular a otro tercero LinkTo=Enlazar a @@ -885,7 +885,7 @@ Select2NotFound=No se han encontrado registros Select2Enter=Introducir Select2MoreCharacter=o más caracteres Select2MoreCharacters=o más caracteres -Select2MoreCharactersMore=Sintaxis de búsqueda:
    | OR (a|b)
    * Cualquier caracter (a*b)
    ^Empezar con (^ab)
    $Terminar con (ab$)
    +Select2MoreCharactersMore=Sintaxis de búsqueda:
    | O (a|b)
    * Cualquier carácter (a*b)
    ^ Empieza con (^ab)
    $ Termina con (ab$)
    Select2LoadingMoreResults=Cargando más resultados... Select2SearchInProgress=Búsqueda en progreso... SearchIntoThirdparties=Terceros @@ -912,5 +912,5 @@ CommentPage=Espacio de comentarios CommentAdded=Comentario añadido CommentDeleted=Comentario borrado Everybody=Proyecto compartido -PayedBy=Payed by -PayedTo=Payed to +PayedBy=Pagado por +PayedTo=Pagado a diff --git a/htdocs/langs/es_ES/modulebuilder.lang b/htdocs/langs/es_ES/modulebuilder.lang index 6be47b732bf..188887b7a06 100644 --- a/htdocs/langs/es_ES/modulebuilder.lang +++ b/htdocs/langs/es_ES/modulebuilder.lang @@ -43,6 +43,8 @@ PathToModulePackage=Ruta al zip del módulo/aplicación PathToModuleDocumentation=Ruta a la documentación del módulo/aplicación SpaceOrSpecialCharAreNotAllowed=Espacios o caracteres especiales no son permitidos. FileNotYetGenerated=Fichero todavía no generado +RegenerateClassAndSql=Borrar y regenerar archivos de clase y sql +RegenerateMissingFiles=Generar archivos no encontrados SpecificationFile=Fichero con las reglas de negocio LanguageFile=Archivo para el idioma ConfirmDeleteProperty=¿Estás seguro que quieres eliminar la propiedad %s? Esto cambiará código en la clase PHP pero también eliminará la columna de la definición de la tabla del objeto. diff --git a/htdocs/langs/es_ES/multicurrency.lang b/htdocs/langs/es_ES/multicurrency.lang index dba8d088ca5..493c5f400a5 100644 --- a/htdocs/langs/es_ES/multicurrency.lang +++ b/htdocs/langs/es_ES/multicurrency.lang @@ -7,7 +7,7 @@ multicurrency_syncronize_error=Error sincronización: %s MULTICURRENCY_USE_RATE_ON_DOCUMENT_DATE=Usar fecha del documento para encontrar la tasa de la divisa, en lugar de usar la última tasa conocida multicurrency_useOriginTx=Cuando un objeto se crea desde otro, mantenga la conversión original del objeto de origen (de lo contrario, utilice la tasa de conversión más reciente conocida) CurrencyLayerAccount=CurrencyLayer API -CurrencyLayerAccount_help_to_synchronize=Debe crear una cuenta en su sitio web para utilizar esta función.
    Obtenga su clave API
    Si utiliza una cuenta gratuita, no puede cambiar la divisa origen (USD por defecto)
    . Pero si su divisa principal no es USD, puede usar la divisa origen alternativa para forzar su divisa principal.

    Está limitado a 1000 sincronizaciones por mes +CurrencyLayerAccount_help_to_synchronize=Debe crear una cuenta en su sitio web para usar esta funcionalidad
    Obtenga su Clave API
    Si usa una cuenta gratuita no puede cambiar la moneda origen (por defecto USD)
    Pero si su moneda principal no es USD puede usar la moneda origen alternativa para forzar su moneda principal

    Estará limitado a 1000 sincronizaciones por mes multicurrency_appId=Clave API multicurrency_appCurrencySource=Divisa origen multicurrency_alternateCurrencySource=Divisa origen alternativa diff --git a/htdocs/langs/es_ES/other.lang b/htdocs/langs/es_ES/other.lang index 2646aea5291..99dfadd2d7d 100644 --- a/htdocs/langs/es_ES/other.lang +++ b/htdocs/langs/es_ES/other.lang @@ -162,9 +162,9 @@ SizeUnitinch=pulgada SizeUnitfoot=pie SizeUnitpoint=punto BugTracker=Incidencias -SendNewPasswordDesc=Este formulario le permite solicitar una nueva contraseña. Se le enviará a su dirección de e-mail.
    El cambio se hará efectivo una vez que haga clic en el enlace de confirmación en el e-mail.
    Compruebe su bandeja de entrada. +SendNewPasswordDesc=Este formulario le permite obtener una nueva contraseña. Le será enviada a su e-mail.
    El cambio será efectivo una vez haga clic en el enlace de confirmación del e-mail.
    Revise su e-mail. BackToLoginPage=Volver a la página de conexión -AuthenticationDoesNotAllowSendNewPassword=El modo de autenticación es %s.
    En este modo, Dolibarr no conoce ni cambia su contraseña.
    Póngase en contacto con el administrador del sistema si desea cambiar su contraseña. +AuthenticationDoesNotAllowSendNewPassword=El modo de autentificación de Dolibarr está configurado como "%s".
    En este modo Dolibarr no puede conocer ni modificar su contraseña
    Contacte con su administrador para conocer las modalidades de cambio. EnableGDLibraryDesc=Instale o active la libreria GD en su PHP para poder usar esta opción ProfIdShortDesc=Prof Id %s es una información dependiente del país del tercero.
    Por ejemplo, para el país %s, és el código %s. DolibarrDemo=Demo de Dolibarr ERP/CRM diff --git a/htdocs/langs/es_ES/printing.lang b/htdocs/langs/es_ES/printing.lang index 352718f6cb9..f9735557d02 100644 --- a/htdocs/langs/es_ES/printing.lang +++ b/htdocs/langs/es_ES/printing.lang @@ -49,4 +49,6 @@ DirectPrintingJobsDesc=Esta página lista los trabajos encontrados en las impres GoogleAuthNotConfigured=Configuración de Google OAuth no realizada. Habilite el módulo de OAuth y establezca un Google ID / Secreto. GoogleAuthConfigured=Las credenciales OAuth de Google se encuentran en la configuración del módulo OAuth. PrintingDriverDescprintgcp=Configuración variables del driver de impresión Google Cloud Print. +PrintingDriverDescprintipp=Configuración variables para el driver de impresión Cups. PrintTestDescprintgcp=Listado de impresoras para Google Cloud Print. +PrintTestDescprintipp=Listado de Impresoras para Cups. diff --git a/htdocs/langs/es_ES/products.lang b/htdocs/langs/es_ES/products.lang index 394aa9e6be1..7234df78d8e 100644 --- a/htdocs/langs/es_ES/products.lang +++ b/htdocs/langs/es_ES/products.lang @@ -239,7 +239,7 @@ MinimumRecommendedPrice=El precio mínimo recomendado es: %s PriceExpressionEditor=Editor de expresión de precios PriceExpressionSelected=Expresión de precios seleccionada PriceExpressionEditorHelp1="price = 2 + 2" o "2 + 2" para configurar un precio. Use ; para separar expresiones -PriceExpressionEditorHelp2=Puede acceder a los atributos adicionales con variables como #extrafield_myextrafieldkey# y variables globales con #global_mycode# +PriceExpressionEditorHelp2=Puede acceder a los campos adicionales con variables como #extrafield_myextrafieldkey# y variables globales con #global_mycode# PriceExpressionEditorHelp3=En productos y servicios, y precios de proveedor están disponibles las siguientes variables
    #tva_tx# #localtax1_tx# #localtax2_tx# #weight# #length# #surface# #price_min# PriceExpressionEditorHelp4=Solamente en los precios de productos y servicios: #supplier_min_price#
    In supplier prices only: #supplier_quantity# and #supplier_tva_tx# PriceExpressionEditorHelp5=Valores globales disponibles: diff --git a/htdocs/langs/es_ES/users.lang b/htdocs/langs/es_ES/users.lang index daddb0fcf66..f089a880b64 100644 --- a/htdocs/langs/es_ES/users.lang +++ b/htdocs/langs/es_ES/users.lang @@ -63,7 +63,7 @@ CreateDolibarrThirdParty=Crear un tercero LoginAccountDisableInDolibarr=La cuenta está desactivada en Dolibarr UsePersonalValue=Utilizar valores personalizados InternalUser=Usuario interno -ExportDataset_user_1=Usuarios Dolibarr y atributos +ExportDataset_user_1=Usuarios Dolibarr y campos adicionales DomainUser=Usuario de dominio Reactivate=Reactivar CreateInternalUserDesc=Este formulario le permite crear un usuario interno para su empresa/asociación. Para crear un usuario externo (cliente, proveedor, etc), use el botón "Crear una cuenta de usuario" desde una ficha de un contacto del tercero. diff --git a/htdocs/langs/es_ES/website.lang b/htdocs/langs/es_ES/website.lang index 38a2155f292..14f1f3c2083 100644 --- a/htdocs/langs/es_ES/website.lang +++ b/htdocs/langs/es_ES/website.lang @@ -41,7 +41,7 @@ VirtualHostUrlNotDefined=URL del Host Virtual servido por un servidor externo no NoPageYet=No hay páginas todavía SyntaxHelp=Ayuda en la sintaxis del código YouCanEditHtmlSourceckeditor=Puede editar código fuente HTML utilizando el botón "Origen" en el editor. -YouCanEditHtmlSource=Puede editar el código fuente HTML usando el botón "Origen" en el editor. También puede incluir código PHP en esta fuente mediante etiquetas <?php ?>. Las siguientes variables globales están disponibles: $conf, $langs, $db, $mysoc, $user, $website.

    También puede incluir contenido de otra Página/Contenedor con la siguiente sintaxis: <?php dolIncludeHtmlContent ($websitekey. '/contentaliastoinclude.php'); ?>

    Para incluir un vínculo para descargar un archivo almacenado en el directorio de documentos/medios, utilice la sintaxis:
    <a href="/document.php?modulepart=medias&file=filename.ext". +YouCanEditHtmlSource=
    Puede incluir código PHP en este fuente usando los tags <?php ?>. Dispone de estas variables globales: $conf, $langs, $db, $mysoc, $user, $website.

    También puede incluir contenido de otra Página/Contenedor con la siguiente sintaxis:
    <?php includeContainer('alias_of_container_to_include'); ?>

    Para incluir un enlace para descargar un archivo guardado en el directorio documents, use el wrapper document.php :
    Por ejemplo, para un archivo de documents/ecm (es necesario estar logueado), la sintaxis:
    <a href="/document.php?modulepart=ecm&file=[relative_dir/]filename.ext">
    Para un archivo de into documents/medias (directorio abierto para acceso público), la sintaxis es:
    <a href="/document.php?modulepart=medias&file=[relative_dir/]filename.ext">
    Para un archivo compartido mediante un enlace compartido (acceso abierto utilizando la clave hash para compartir del archivo), la sintaxis es:
    <a href="/document.php?hashp=publicsharekeyoffile">

    Para incluir una imagen guardada en el directorio documents , use el wrapper viewimage.php :
    Ejemplo para una imagen de documents/medias (acceso abierto), la sintaxis es:
    <a href="/viewimage.php?modulepart=medias&file=[relative_dir/]filename.ext">
    ClonePage=Clonar página/contenedor CloneSite=Clonar sitio SiteAdded=Sitio web agregado diff --git a/htdocs/langs/es_ES/withdrawals.lang b/htdocs/langs/es_ES/withdrawals.lang index a8b25e5088e..355380794e6 100644 --- a/htdocs/langs/es_ES/withdrawals.lang +++ b/htdocs/langs/es_ES/withdrawals.lang @@ -26,7 +26,7 @@ LastWithdrawalReceipt=Las %s últimas domiciliaciones MakeWithdrawRequest=Realizar una petición de domiciliación WithdrawRequestsDone=%s domiciliaciones registradas ThirdPartyBankCode=Código banco del tercero -NoInvoiceCouldBeWithdrawed=No se ha domiciliado ninguna factura. Asegúrese de que las facturas son de empresas con los datos de cuentas bancarias correctos. +NoInvoiceCouldBeWithdrawed=No se ha podido realizar la petición de domiciliación de ninguna factura. Compruebe que los terceros de las facturas relacionadas tienen una cuenta IBAN válida y dicho IBAN tiene un RUM con modo %s. ClassCredited=Clasificar como "Abonada" ClassCreditedConfirm=¿Está seguro de querer clasificar esta domiciliación como abonada en su cuenta bancaria? TransData=Fecha envío diff --git a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php index 62b35bfdf39..e413c969119 100644 --- a/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php +++ b/htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php @@ -211,6 +211,7 @@ class InterfaceMyModuleTriggers extends DolibarrTriggers // Contracts case 'CONTRACT_CREATE': case 'CONTRACT_ACTIVATE': + case 'CONTRACT_MODIFY': case 'CONTRACT_CANCEL': case 'CONTRACT_CLOSE': case 'CONTRACT_DELETE': diff --git a/htdocs/modulebuilder/template/mymoduleindex.php b/htdocs/modulebuilder/template/mymoduleindex.php index c6f70b0ba85..8073d31fd60 100644 --- a/htdocs/modulebuilder/template/mymoduleindex.php +++ b/htdocs/modulebuilder/template/mymoduleindex.php @@ -175,7 +175,7 @@ if (! empty($conf->mymodule->enabled) && $user->rights->mymodule->read) $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.client IN (1, 2, 3)"; - $sql.= " AND s.entity IN (".getEntity($companystatic->element, 1).")"; + $sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND s.rowid = $socid"; $sql .= " ORDER BY s.tms DESC"; diff --git a/htdocs/product/card.php b/htdocs/product/card.php index a54f1d90885..861c46328df 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1106,11 +1106,11 @@ else print "
    '.$langs->trans("Categories").''; $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1); - print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%'); + print $form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, '', 0, '100%'); print "
    '.$langs->trans("Label").'
    '.$langs->trans("Status").''; + print ''; + print '
    '.$langs->trans("Status").''.$object->getLibStatut(4).'
    '.$langs->trans("OpportunityProbability").' %'; - print ''; - print '
    '.$langs->trans("OpportunityProbability").' %'; + print ''; + print '
    '.$langs->trans("OpportunityAmount").'
    '.$langs->trans("OpportunityAmount").'
    '.$langs->trans("DateStart").''; @@ -1205,7 +1213,7 @@ elseif ($object->id > 0) // List of actions on element include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; $formactions = new FormActions($db); - $somethingshown = $formactions->showactions($object, 'project', $socid, 1, '', $MAXEVENT, '', $morehtmlright); + $somethingshown = $formactions->showactions($object, 'project', 0, 1, '', $MAXEVENT, '', $morehtmlright); print ''; } diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 7a42e77c644..e24a444702c 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -303,16 +303,9 @@ class Project extends CommonObject $resql=$this->db->query($sql); if ($resql) { - if (!$notrigger) + // Update extrafield + if (! $error) { - // Call trigger - $result=$this->call_trigger('PROJECT_MODIFY',$user); - if ($result < 0) { $error++; } - // End call triggers - } - - //Update extrafield - if (!$error) { if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used { $result=$this->insertExtraFields(); @@ -323,6 +316,14 @@ class Project extends CommonObject } } + if (! $error && !$notrigger) + { + // Call trigger + $result=$this->call_trigger('PROJECT_MODIFY',$user); + if ($result < 0) { $error++; } + // End call triggers + } + if (! $error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) { // We remove directory @@ -508,13 +509,13 @@ class Project extends CommonObject } /** - * Return list of elements for type, linked to project + * Return list of elements for type, linked to a project * * @param string $type 'propal','order','invoice','order_supplier','invoice_supplier',... * @param string $tablename name of table associated of the type * @param string $datefieldname name of date field for filter - * @param string $dates Start date (ex 00:00:00) - * @param string $datee End date (ex 23:59:59) + * @param int $dates Start date + * @param int $datee End date * @return mixed Array list of object ids linked to project, < 0 or string if error */ function get_element_list($type, $tablename, $datefieldname='', $dates='', $datee='') @@ -523,29 +524,31 @@ class Project extends CommonObject if ($this->id <= 0) return $elements; + $ids = $this->id; + if ($type == 'agenda') { - $sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project=" . $this->id; + $sql = "SELECT id as rowid FROM " . MAIN_DB_PREFIX . "actioncomm WHERE fk_project IN (". $ids .")"; } elseif ($type == 'expensereport') { - $sql = "SELECT ed.rowid FROM " . MAIN_DB_PREFIX . "expensereport as e, " . MAIN_DB_PREFIX . "expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND ed.fk_projet=" . $this->id; + $sql = "SELECT ed.rowid FROM " . MAIN_DB_PREFIX . "expensereport as e, " . MAIN_DB_PREFIX . "expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND ed.fk_projet IN (". $ids .")"; } elseif ($type == 'project_task') { - $sql = "SELECT DISTINCT pt.rowid FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet=" . $this->id; + $sql = "SELECT DISTINCT pt.rowid FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet IN (". $ids .")"; } elseif ($type == 'project_task_time') // Case we want to duplicate line foreach user { - $sql = "SELECT DISTINCT pt.rowid, ptt.fk_user FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet=" . $this->id; + $sql = "SELECT DISTINCT pt.rowid, ptt.fk_user FROM " . MAIN_DB_PREFIX . "projet_task as pt, " . MAIN_DB_PREFIX . "projet_task_time as ptt WHERE pt.rowid = ptt.fk_task AND pt.fk_projet IN (". $ids .")"; } elseif ($type == 'stock_mouvement') { - $sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM ' . MAIN_DB_PREFIX . 'stock_mouvement as ms WHERE ms.origintype = "project" AND ms.fk_origin = ' . $this->id . ' AND ms.type_mouvement = 1'; + $sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM ' . MAIN_DB_PREFIX . "stock_mouvement as ms WHERE ms.origintype = 'project' AND ms.fk_origin IN (". $ids .") AND ms.type_mouvement = 1"; } else { - $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE fk_projet=" . $this->id; + $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . $tablename." WHERE fk_projet IN (". $ids .")"; } if ($dates > 0) diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 38a6c8e8c7c..d4829d8e839 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -103,9 +103,9 @@ $socid=$object->socid; //if ($user->societe_id > 0) $socid = $user->societe_id; // For external user, no check is done on company because readability is managed by public status of project and assignement. $result = restrictedArea($user, 'projet', $projectid, 'projet&project'); - $hookmanager->initHooks(array('projectOverview')); + /* * View */ @@ -470,7 +470,7 @@ $listofreferent=array( ); $parameters=array('listofreferent'=>$listofreferent); -$resHook = $hookmanager->executeHooks('completeListOfReferent',$parameters,$object,$action); +$resHook = $hookmanager->executeHooks('completeListOfReferent', $parameters, $object, $action); if(!empty($hookmanager->resArray)) { diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 6a5fcbdfc62..978c646a524 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -26,7 +26,7 @@ * * Note that you can add following constant to change behaviour of page * MEMBER_NEWFORM_AMOUNT Default amount for auto-subscribe form - * MEMBER_NEWFORM_EDITAMOUNT Amount can be edited + * MEMBER_NEWFORM_EDITAMOUNT 0 or 1 = Amount can be edited * MEMBER_NEWFORM_PAYONLINE Suggest payment with paypal, paybox or stripe * MEMBER_NEWFORM_DOLIBARRTURNOVER Show field turnover (specific for dolibarr foundation) * MEMBER_URL_REDIRECT_SUBSCRIPTION Url to redirect once subscribe submitted diff --git a/htdocs/public/paybox/newpayment.php b/htdocs/public/paybox/newpayment.php index 9d7f79081a9..bd27554c500 100644 --- a/htdocs/public/paybox/newpayment.php +++ b/htdocs/public/paybox/newpayment.php @@ -155,7 +155,7 @@ if (! empty($conf->global->PAYMENT_SECURITY_TOKEN)) if (GETPOST('action','aZ09') == 'dopayment') { - $PRICE=price2num(GETPOST("newamount"),'MT'); + $PRICE=price2num(GETPOST("newamount",'alpha'),'MT'); $email=GETPOST("email"); $origfulltag=GETPOST("fulltag",'alpha'); @@ -275,7 +275,7 @@ print $text; // Output payment summary form print '
    '; print ''; -print ''."\n"; +print ''."\n"; $found=false; $error=0; @@ -305,7 +305,7 @@ if (! GETPOST("source") && $valid) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -392,7 +392,7 @@ if (GETPOST("source") == 'order' && $valid) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -480,7 +480,7 @@ if (GETPOST("source") == 'invoice' && $valid) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -656,7 +656,7 @@ if (GETPOST("source") == 'contractline' && $valid) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -754,7 +754,7 @@ if (GETPOST("source") == 'membersubscription' && $valid) print ''."\n"; - if (empty($amount) && ! GETPOST('newamount')) $_GET['newamount']=$member->last_subscription_amount; + if (empty($amount) && ! GETPOST('newamount','alpha')) $_GET['newamount']=$member->last_subscription_amount; } // Amount @@ -762,12 +762,31 @@ if (GETPOST("source") == 'membersubscription' && $valid) print ''."\n"; - if (empty($amount) && ! GETPOST('newamount')) $_GET['newamount']=$member->last_subscription_amount; + if (empty($amount) && ! GETPOST('newamount','alpha')) $_GET['newamount']=$member->last_subscription_amount; } // Amount @@ -1215,27 +1215,31 @@ if ($source == 'membersubscription') if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) print ')'; } print '
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.price($member->last_subscription_amount); print '
    '.$langs->trans("Amount"); if (empty($amount)) print ' ('.$langs->trans("ToComplete").')'; print ''; + $valtoshow=''; if (empty($amount) || ! is_numeric($amount)) { - $valtoshow=GETPOST("newamount",'int'); + $valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); + // force default subscription amount to value defined into constant... + if (empty($valtoshow)) + { + if (! empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + else { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $amount = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + } + } + if (empty($amount) || ! is_numeric($amount)) + { + //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow); print ''; - print ''; + print ''; } else { $valtoshow=$amount; diff --git a/htdocs/public/paybox/paymentok.php b/htdocs/public/paybox/paymentok.php index e3812c28dc1..63c15b035f2 100644 --- a/htdocs/public/paybox/paymentok.php +++ b/htdocs/public/paybox/paymentok.php @@ -126,6 +126,7 @@ $result=$interface->run_triggers('PAYBOX_PAYMENT_OK',$object,$user,$langs,$conf) if ($result < 0) { $error++; $errors=$interface->errors; } // Fin appel triggers +$tmptag=dolExplodeIntoArray($fulltag,'.','='); // Send an email if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) @@ -152,7 +153,6 @@ if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) $urlback=$_SERVER["REQUEST_URI"]; $topic='['.$appli.'] '.$langs->transnoentitiesnoconv("NewOnlinePaymentReceived"); - $tmptag=dolExplodeIntoArray($fulltag,'.','='); $content=""; if (! empty($tmptag['MEM'])) { diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index efeb1323a3d..74ffcfd120a 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -268,7 +268,7 @@ if ($action == 'dopayment') { if ($paymentmethod == 'paypal') { - $PAYPAL_API_PRICE=price2num(GETPOST("newamount"),'MT'); + $PAYPAL_API_PRICE=price2num(GETPOST("newamount",'alpha'),'MT'); $PAYPAL_PAYMENT_TYPE='Sale'; $origfulltag=GETPOST("fulltag",'alpha'); @@ -366,7 +366,7 @@ if ($action == 'dopayment') if ($paymentmethod == 'stripe') { - if (GETPOST('newamount')) $amount = GETPOST('newamount'); + if (GETPOST('newamount','alpha')) $amount = price2num(GETPOST('newamount','alpha'),'MT'); else { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")), null, 'errors'); @@ -647,7 +647,7 @@ if (! $source) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -738,7 +738,7 @@ if ($source == 'order') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -858,7 +858,7 @@ if ($source == 'invoice') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -1079,7 +1079,7 @@ if ($source == 'contractline') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -1202,7 +1202,7 @@ if ($source == 'membersubscription') print ''.price($member->last_subscription_amount); print '
    '; + $valtoshow=''; if (empty($amount) || ! is_numeric($amount)) { - $valtoshow=GETPOST("newamount",'int'); + $valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); // force default subscription amount to value defined into constant... - if (! empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { - if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { - $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT; + if (empty($valtoshow)) + { + if (! empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT; + } } - } - else { - if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { - $amount = $conf->global->MEMBER_NEWFORM_AMOUNT; + else { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $amount = $conf->global->MEMBER_NEWFORM_AMOUNT; + } } } } if (empty($amount) || ! is_numeric($amount)) { - //$valtoshow=GETPOST("newamount",'int'); + //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow); print ''; - print ''; + print ''; } else { $valtoshow=$amount; diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php index 7ccd95abcdf..d74305890df 100644 --- a/htdocs/public/payment/paymentok.php +++ b/htdocs/public/payment/paymentok.php @@ -188,7 +188,7 @@ if (! empty($conf->paypal->enabled)) if ($PAYPALTOKEN) { // Get on url call - $onlinetoken = $PAYPALTOKEN; + $onlinetoken = $PAYPALTOKEN; $fulltag = $FULLTAG; $payerID = $PAYPALPAYERID; // Set by newpayment.php @@ -291,6 +291,8 @@ if ($ispaymentok) $sendemail = ''; if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) $sendemail=$conf->global->ONLINE_PAYMENT_SENDEMAIL; + $tmptag=dolExplodeIntoArray($fulltag,'.','='); + // Send an email if ($sendemail) { @@ -316,7 +318,6 @@ if ($ispaymentok) $urlback=$_SERVER["REQUEST_URI"]; $topic='['.$appli.'] '.$langs->transnoentitiesnoconv("NewOnlinePaymentReceived"); - $tmptag=dolExplodeIntoArray($fulltag,'.','='); $content=""; if (! empty($tmptag['MEM'])) { @@ -388,6 +389,8 @@ else if ($paymentmethod == 'paybox' && ! empty($conf->global->PAYBOX_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYBOX_PAYONLINE_SENDEMAIL; if ($paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->STRIPE_PAYONLINE_SENDEMAIL; + $tmptag=dolExplodeIntoArray($fulltag,'.','='); + // Send an email if ($sendemail) { diff --git a/htdocs/public/paypal/newpayment.php b/htdocs/public/paypal/newpayment.php index fac192bd318..b1ecfa43803 100644 --- a/htdocs/public/paypal/newpayment.php +++ b/htdocs/public/paypal/newpayment.php @@ -192,7 +192,7 @@ if (! empty($conf->global->PAYPAL_SECURITY_TOKEN)) if (GETPOST('action','aZ09') == 'dopayment') { - $PAYPAL_API_PRICE=price2num(GETPOST("newamount"),'MT'); + $PAYPAL_API_PRICE=price2num(GETPOST("newamount",'alpha'),'MT'); $PAYPAL_PAYMENT_TYPE='Sale'; $origfulltag=GETPOST("fulltag",'alpha'); @@ -361,7 +361,7 @@ print $text; // Output payment summary form print '
    '; print ''; -print ''."\n"; +print ''."\n"; $found=false; $error=0; @@ -375,21 +375,19 @@ if (! GETPOST("source")) $fulltag=$tag; // Creditor - print ''."\n"; // Amount - print ''."\n"; // Tag - print ''."\n"; - if (empty($amount) && ! GETPOST('newamount')) $_GET['newamount']=$member->last_subscription_amount; + if (empty($amount) && ! GETPOST('newamount','alpha')) $_GET['newamount']=$member->last_subscription_amount; } // Amount @@ -915,12 +912,31 @@ if (GETPOST("source") == 'membersubscription') print ')'; } print '
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.$langs->trans("Creditor"); print ''.$creditor.''; print ''; print '
    '.$langs->trans("Amount"); if (empty($amount)) print ' ('.$langs->trans("ToComplete").')'; print ''; if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -402,7 +400,6 @@ if (! GETPOST("source")) print '
    '.$langs->trans("PaymentCode"); print ''.$fulltag.''; print ''; @@ -475,7 +472,7 @@ if (GETPOST("source") == 'order') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -585,7 +582,7 @@ if (GETPOST("source") == 'invoice') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -783,7 +780,7 @@ if (GETPOST("source") == 'contractline') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -902,7 +899,7 @@ if (GETPOST("source") == 'membersubscription') print ''.price($member->last_subscription_amount); print '
    '; + $valtoshow=''; if (empty($amount) || ! is_numeric($amount)) { - $valtoshow=GETPOST("newamount",'int'); + $valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); + // force default subscription amount to value defined into constant... + if (empty($valtoshow)) + { + if (! empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + else { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $amount = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + } + } + if (empty($amount) || ! is_numeric($amount)) + { + //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow); print ''; - print ''; + print ''; } else { $valtoshow=$amount; diff --git a/htdocs/public/paypal/paymentok.php b/htdocs/public/paypal/paymentok.php index 9ae2e90795e..80ec1d8ec2b 100644 --- a/htdocs/public/paypal/paymentok.php +++ b/htdocs/public/paypal/paymentok.php @@ -181,6 +181,8 @@ if ($PAYPALTOKEN) if ($result < 0) { $error++; $errors=$interface->errors; } // Fin appel triggers + $tmptag=dolExplodeIntoArray($fulltag,'.','='); + // Send an email if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) { @@ -206,7 +208,6 @@ if ($PAYPALTOKEN) $urlback=$_SERVER["REQUEST_URI"]; $topic='['.$appli.'] '.$langs->transnoentitiesnoconv("NewOnlinePaymentReceived"); - $tmptag=dolExplodeIntoArray($fulltag,'.','='); $content=""; if (! empty($tmptag['MEM'])) { @@ -265,6 +266,8 @@ if ($PAYPALTOKEN) if ($mysoc->email) echo "\nPlease, send a screenshot of this page to ".$mysoc->email."
    \n"; + $tmptag=dolExplodeIntoArray($fulltag,'.','='); + // Send an email if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) { diff --git a/htdocs/public/stripe/newpayment.php b/htdocs/public/stripe/newpayment.php index 36b27658ee0..36cd64b4f01 100644 --- a/htdocs/public/stripe/newpayment.php +++ b/htdocs/public/stripe/newpayment.php @@ -202,7 +202,7 @@ else if (! empty($conf->global->ONLINE_PAYMENT_CREDITOR)) $creditor=$conf->globa if ($action == 'dopayment') // We click on button Create payment { - if (GETPOST('newamount')) $amount = GETPOST('newamount'); + if (GETPOST('newamount','alpha')) $amount = price2num(GETPOST('newamount','alpha'),'MT'); else { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")), null, 'errors'); @@ -429,7 +429,7 @@ print $text; // Output payment summary form print '
    '; print ''; -print ''."\n"; +print ''."\n"; $found=false; $error=0; @@ -455,7 +455,7 @@ if (! GETPOST("source")) if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -541,7 +541,7 @@ if (GETPOST("source") == 'order') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -652,7 +652,7 @@ if (GETPOST("source") == 'invoice') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -852,7 +852,7 @@ if (GETPOST("source") == 'contractline') if (empty($amount) || ! is_numeric($amount)) { print ''; - print ''; + print ''; } else { print ''.price($amount).''; @@ -971,7 +971,7 @@ if (GETPOST("source") == 'membersubscription') print ''."\n"; - if (empty($amount) && ! GETPOST('newamount')) $_GET['newamount']=$member->last_subscription_amount; + if (empty($amount) && ! GETPOST('newamount','alpha')) $_GET['newamount']=$member->last_subscription_amount; } // Amount @@ -984,12 +984,31 @@ if (GETPOST("source") == 'membersubscription') print ')'; } print '\n"; $companystatic->name_alias = $savalias; if (! $i) $totalarray['nbfield']++; diff --git a/htdocs/societe/note.php b/htdocs/societe/note.php index 0dbb20ebd00..d0766bc24d8 100644 --- a/htdocs/societe/note.php +++ b/htdocs/societe/note.php @@ -62,7 +62,7 @@ if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/' $help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; llxHeader('',$title,$help_url); -if ($id > 0) +if ($object->id > 0) { /* * Affichage onglets @@ -120,6 +120,11 @@ if ($id > 0) dol_fiche_end(); } +else +{ + $langs->load("errors"); + print $langs->trans("ErrorRecordNotFound"); +} llxFooter(); $db->close(); diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php index cd7eaf67c73..9d90d458363 100644 --- a/htdocs/theme/eldy/style.css.php +++ b/htdocs/theme/eldy/style.css.php @@ -357,7 +357,7 @@ input.buttonpayment { background: none; padding-left: 30px; text-align: ; - border: 2px solid #ccc; + border: 1px solid #ddd; background-color: #eee; white-space: normal; } @@ -589,6 +589,9 @@ textarea.centpercent { .wordwrap { word-wrap: break-word; } +.wordbreak { + word-break: break-all; +} .nobold { font-weight: normal !important; } @@ -1442,14 +1445,14 @@ a.tmenudisabled:link, a.tmenudisabled:visited, a.tmenudisabled:hover, a.tmenudis a.tmenu:link, a.tmenu:visited, a.tmenu:hover, a.tmenu:active { font-weight: normal; - padding: 0px 5px 0px 3px; + padding: 0px 4px 0px 4px; white-space: nowrap; color: #; text-decoration: none; } a.tmenusel:link, a.tmenusel:visited, a.tmenusel:hover, a.tmenusel:active { font-weight: normal; - padding: 0px 5px 0px 3px; + padding: 0px 4px 0px 4px; margin: 0px 0px 0px 0px; white-space: nowrap; color: #; @@ -1538,12 +1541,8 @@ div.menu_titre { } .mainmenuaspan { - - padding-: 4px; + padding-: 2px; padding-: 2px; - - padding-: 4px; - } div.mainmenu { @@ -5015,8 +5014,8 @@ div.tabsElem a.tab { margin-left: 1px; } .mainmenuaspan { - /*display: none;*/ font-size: 10px; + padding-left: 0; padding-right: 0; } .topmenuimage { diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index e86d85a2c34..7cb107b66a5 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -591,6 +591,9 @@ textarea.centpercent { .wordwrap { word-wrap: break-word; } +.wordbreak { + word-break: break-all; +} .nobold { font-weight: normal !important; } @@ -1563,12 +1566,8 @@ div.menu_titre { } .mainmenuaspan { - - padding-: 4px; + padding-: 2px; padding-: 2px; - - padding-: 4px; - } div.mainmenu { @@ -5019,7 +5018,6 @@ border-top-right-radius: 6px; color: #; } .mainmenuaspan { - /*display: none;*/ font-size: 12px; } .topmenuimage { @@ -5044,8 +5042,9 @@ border-top-right-radius: 6px; text-overflow: clip; } .mainmenuaspan { - /*display: none;*/ font-size: 10px; + padding-left: 0; + padding-right: 0; } .topmenuimage { background-size: 20px auto;
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.$langs->trans("ThisIsInformationOnPayment").' :
    '.price($member->last_subscription_amount); print '
    '; + $valtoshow=''; if (empty($amount) || ! is_numeric($amount)) { - $valtoshow=GETPOST("newamount",'int'); + $valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); + // force default subscription amount to value defined into constant... + if (empty($valtoshow)) + { + if (! empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + else { + if (! empty($conf->global->MEMBER_NEWFORM_AMOUNT)) { + $amount = $conf->global->MEMBER_NEWFORM_AMOUNT; + } + } + } + } + if (empty($amount) || ! is_numeric($amount)) + { + //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT'); if (! empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow=max($conf->global->MEMBER_MIN_AMOUNT,$valtoshow); print ''; - print ''; + print ''; } else { $valtoshow=$amount; diff --git a/htdocs/public/stripe/paymentok.php b/htdocs/public/stripe/paymentok.php index f018bc98b7a..d0ce82d1ca8 100644 --- a/htdocs/public/stripe/paymentok.php +++ b/htdocs/public/stripe/paymentok.php @@ -127,6 +127,8 @@ if ($ispaymentok) $sendemail = ''; if (! empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) $sendemail=$conf->global->ONLINE_PAYMENT_SENDEMAIL; + $tmptag=dolExplodeIntoArray($fulltag,'.','='); + // Send an email if ($sendemail) { @@ -152,7 +154,6 @@ if ($ispaymentok) $urlback=$_SERVER["REQUEST_URI"]; $topic='['.$appli.'] '.$langs->transnoentitiesnoconv("NewOnlinePaymentReceived"); - $tmptag=dolExplodeIntoArray($fulltag,'.','='); $content=""; if (! empty($tmptag['MEM'])) { diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index d3a3854309a..9fdad8916e1 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -119,7 +119,7 @@ if (empty($reshook)) { $object->fetch($socid); - $errors = 0; + $error = 0; $soc_origin_id = GETPOST('soc_origin', 'int'); $soc_origin = new Societe($db); @@ -131,13 +131,13 @@ if (empty($reshook)) } else { - if (!$errors && $soc_origin->fetch($soc_origin_id) < 1) + if (!$error && $soc_origin->fetch($soc_origin_id) < 1) { setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors'); - $errors++; + $error++; } - if (!$errors) + if (!$error) { // TODO Move the merge function into class of object. @@ -184,48 +184,67 @@ if (empty($reshook)) $suppcats = $static_cat->containing($soc_origin->id, 'supplier', 'id'); $object->setCategories($suppcats, 'supplier'); + // If thirdparty has a new code that is same than origin, we clean origin code to avoid duplicate key from database unique keys. + if ($soc_origin->code_client == $object->code_client + || $soc_origin->code_fournisseur == $object->code_fournisseur + || $soc_origin->barcode == $object->barcode) + { + dol_syslog("We clean customer and supplier code so we will be able to make the update of target"); + $soc_origin->code_client = ''; + $soc_origin->code_fournisseur = ''; + $soc_origin->barcode = ''; + $soc_origin->update($soc_origin->id, $user, 0, 1, 1, 'merge'); + } + // Update - $object->update($object->id, $user, 0); + $object->update($object->id, $user, 0, 1, 1, 'merge'); + if ($result < 0) + { + $error++; + } // Move links - $objects = array( - 'Adherent' => '/adherents/class/adherent.class.php', - 'Societe' => '/societe/class/societe.class.php', - 'Categorie' => '/categories/class/categorie.class.php', - 'ActionComm' => '/comm/action/class/actioncomm.class.php', - 'Propal' => '/comm/propal/class/propal.class.php', - 'Commande' => '/commande/class/commande.class.php', - 'Facture' => '/compta/facture/class/facture.class.php', - 'FactureRec' => '/compta/facture/class/facture-rec.class.php', - 'LignePrelevement' => '/compta/prelevement/class/ligneprelevement.class.php', - 'Contact' => '/contact/class/contact.class.php', - 'Contrat' => '/contrat/class/contrat.class.php', - 'Expedition' => '/expedition/class/expedition.class.php', - 'Fichinter' => '/fichinter/class/fichinter.class.php', - 'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php', - 'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php', - 'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php', - 'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php', - 'Livraison' => '/livraison/class/livraison.class.php', - 'Product' => '/product/class/product.class.php', - 'Project' => '/projet/class/project.class.php', - 'User' => '/user/class/user.class.php', - ); - - //First, all core objects must update their tables - foreach ($objects as $object_name => $object_file) + if (! $error) { - require_once DOL_DOCUMENT_ROOT.$object_file; + $objects = array( + 'Adherent' => '/adherents/class/adherent.class.php', + 'Societe' => '/societe/class/societe.class.php', + 'Categorie' => '/categories/class/categorie.class.php', + 'ActionComm' => '/comm/action/class/actioncomm.class.php', + 'Propal' => '/comm/propal/class/propal.class.php', + 'Commande' => '/commande/class/commande.class.php', + 'Facture' => '/compta/facture/class/facture.class.php', + 'FactureRec' => '/compta/facture/class/facture-rec.class.php', + 'LignePrelevement' => '/compta/prelevement/class/ligneprelevement.class.php', + 'Contact' => '/contact/class/contact.class.php', + 'Contrat' => '/contrat/class/contrat.class.php', + 'Expedition' => '/expedition/class/expedition.class.php', + 'Fichinter' => '/fichinter/class/fichinter.class.php', + 'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php', + 'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php', + 'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php', + 'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php', + 'Livraison' => '/livraison/class/livraison.class.php', + 'Product' => '/product/class/product.class.php', + 'Project' => '/projet/class/project.class.php', + 'User' => '/user/class/user.class.php', + ); - if (!$errors && !$object_name::replaceThirdparty($db, $soc_origin->id, $object->id)) + //First, all core objects must update their tables + foreach ($objects as $object_name => $object_file) { - $errors++; - setEventMessages($db->lasterror(), null, 'errors'); + require_once DOL_DOCUMENT_ROOT.$object_file; + + if (!$error && !$object_name::replaceThirdparty($db, $soc_origin->id, $object->id)) + { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + } } } - //External modules should update their ones too - if (!$errors) + // External modules should update their ones too + if (! $error) { $reshook = $hookmanager->executeHooks('replaceThirdparty', array( 'soc_origin' => $soc_origin->id, @@ -235,7 +254,7 @@ if (empty($reshook)) if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - $errors++; + $error++; } } @@ -254,16 +273,16 @@ if (empty($reshook)) // End call triggers } - if (!$errors) + if (!$error) { //We finally remove the old thirdparty if ($soc_origin->delete($soc_origin->id, $user) < 1) { - $errors++; + $error++; } } - if (!$errors) + if (!$error) { setEventMessages($langs->trans('ThirdpartiesMergeSuccess'), null, 'mesgs'); $db->commit(); @@ -1890,6 +1909,7 @@ else $cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, null, null, null, 1); $c = new Categorie($db); $cats = $c->containing($object->id, Categorie::TYPE_CUSTOMER); + $arrayselected=array(); foreach ($cats as $cat) { $arrayselected[] = $cat->id; } @@ -1904,6 +1924,7 @@ else $cate_arbo = $form->select_all_categories(Categorie::TYPE_SUPPLIER, null, null, null, null, 1); $c = new Categorie($db); $cats = $c->containing($object->id, Categorie::TYPE_SUPPLIER); + $arrayselected=array(); foreach ($cats as $cat) { $arrayselected[] = $cat->id; } diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 658dc6a50e2..35301b06a07 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -243,6 +243,218 @@ class Thirdparties extends DolibarrApi return false; } + /** + * Merge a thirdparty into another one. + * + * Merge content (properties, notes) and objects (like invoices, events, orders, proposals, ...) of a thirdparty into a target thirdparty, + * then delete the merged thirdparty. + * If a property has a defined value both in thirdparty to delete and thirdparty to keep, the value into the thirdparty to + * delete will be ignored, the value of target thirdparty will remain, except for notes (content is concatenated). + * + * @param int $id ID of thirdparty to keep (the target thirdparty) + * @param int $idtodelete ID of thirdparty to remove (the thirdparty to delete), once data has been merged into the target thirdparty. + * @return int + * + * @url PUT {id}/merge/{idtodelete} + */ + function merge($id, $idtodelete) + { + global $db, $hookmanager; + + if ($id == $idtodelete) + { + throw new RestException(400, 'Try to merge a thirdparty into itself'); + } + + if(! DolibarrApiAccess::$user->rights->societe->creer) { + throw new RestException(401); + } + + $result = $this->company->fetch($id); // include the fetch of extra fields + if( ! $result ) { + throw new RestException(404, 'Thirdparty not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('societe',$this->company->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $this->companytoremove = new Societe($db); + + $result = $this->companytoremove->fetch($idtodelete); // include the fetch of extra fields + if( ! $result ) { + throw new RestException(404, 'Thirdparty not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('societe',$this->companytoremove->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $soc_origin = $this->companytoremove; + $object = $this->company; + $user = DolibarrApiAccess::$user; + + + // Call same code than into action 'confirm_merge' + + + $db->begin(); + + // Recopy some data + $object->client = $object->client | $soc_origin->client; + $object->fournisseur = $object->fournisseur | $soc_origin->fournisseur; + $listofproperties=array( + 'address', 'zip', 'town', 'state_id', 'country_id', 'phone', 'phone_pro', 'fax', 'email', 'skype', 'url', 'barcode', + 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', + 'tva_intra', 'effectif_id', 'forme_juridique', 'remise_percent', 'mode_reglement_supplier_id', 'cond_reglement_supplier_id', 'name_bis', + 'stcomm_id', 'outstanding_limit', 'price_level', 'parent', 'default_lang', 'ref', 'ref_ext', 'import_key', 'fk_incoterms', 'fk_multicurrency', + 'code_client', 'code_fournisseur', 'code_compta', 'code_compta_fournisseur', + 'model_pdf', 'fk_projet' + ); + foreach ($listofproperties as $property) + { + if (empty($object->$property)) $object->$property = $soc_origin->$property; + } + + // Concat some data + $listofproperties=array( + 'note_public', 'note_private' + ); + foreach ($listofproperties as $property) + { + $object->$property = dol_concatdesc($object->$property, $soc_origin->$property); + } + + // Merge extrafields + if (is_array($soc_origin->array_options)) + { + foreach ($soc_origin->array_options as $key => $val) + { + if (empty($object->array_options[$key])) $object->array_options[$key] = $val; + } + } + + // Merge categories + $static_cat = new Categorie($db); + $custcats = $static_cat->containing($soc_origin->id, 'customer', 'id'); + $object->setCategories($custcats, 'customer'); + $suppcats = $static_cat->containing($soc_origin->id, 'supplier', 'id'); + $object->setCategories($suppcats, 'supplier'); + + // If thirdparty has a new code that is same than origin, we clean origin code to avoid duplicate key from database unique keys. + if ($soc_origin->code_client == $object->code_client + || $soc_origin->code_fournisseur == $object->code_fournisseur + || $soc_origin->barcode == $object->barcode) + { + dol_syslog("We clean customer and supplier code so we will be able to make the update of target"); + $soc_origin->code_client = ''; + $soc_origin->code_fournisseur = ''; + $soc_origin->barcode = ''; + $soc_origin->update($soc_origin->id, $user, 0, 1, 1, 'merge'); + } + + // Update + $result = $object->update($object->id, $user, 0, 1, 1, 'merge'); + if ($result < 0) + { + $error++; + } + + // Move links + if (! $error) + { + $objects = array( + 'Adherent' => '/adherents/class/adherent.class.php', + 'Societe' => '/societe/class/societe.class.php', + 'Categorie' => '/categories/class/categorie.class.php', + 'ActionComm' => '/comm/action/class/actioncomm.class.php', + 'Propal' => '/comm/propal/class/propal.class.php', + 'Commande' => '/commande/class/commande.class.php', + 'Facture' => '/compta/facture/class/facture.class.php', + 'FactureRec' => '/compta/facture/class/facture-rec.class.php', + 'LignePrelevement' => '/compta/prelevement/class/ligneprelevement.class.php', + 'Contact' => '/contact/class/contact.class.php', + 'Contrat' => '/contrat/class/contrat.class.php', + 'Expedition' => '/expedition/class/expedition.class.php', + 'Fichinter' => '/fichinter/class/fichinter.class.php', + 'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php', + 'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php', + 'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php', + 'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php', + 'Livraison' => '/livraison/class/livraison.class.php', + 'Product' => '/product/class/product.class.php', + 'Project' => '/projet/class/project.class.php', + 'User' => '/user/class/user.class.php', + ); + + //First, all core objects must update their tables + foreach ($objects as $object_name => $object_file) + { + require_once DOL_DOCUMENT_ROOT.$object_file; + + if (!$errors && !$object_name::replaceThirdparty($db, $soc_origin->id, $object->id)) + { + $errors++; + //setEventMessages($db->lasterror(), null, 'errors'); + } + } + } + + // External modules should update their ones too + if (!$errors) + { + $reshook = $hookmanager->executeHooks('replaceThirdparty', array( + 'soc_origin' => $soc_origin->id, + 'soc_dest' => $object->id + ), $soc_dest, $action); + + if ($reshook < 0) + { + //setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + $errors++; + } + } + + + if (! $error) + { + $object->context=array('merge'=>1, 'mergefromid'=>$soc_origin->id); + + // Call trigger + $result=$object->call_trigger('COMPANY_MODIFY',$user); + if ($result < 0) + { + //setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + // End call triggers + } + + if (! $error) + { + //We finally remove the old thirdparty + if ($soc_origin->delete($soc_origin->id, $user) < 1) + { + $errors++; + } + } + + // End of merge + + if ($error) + { + $db->rollback(); + + throw new RestException(500, 'Error failed to merged thirdparty '.$this->companytoremove->id.' into '.$id.'. Enable and read log file for more information.'); + } + else + { + $db->commit(); + } + + return $this->get($id); + } + /** * Delete thirdparty * @@ -339,6 +551,139 @@ class Thirdparties extends DolibarrApi } + + /** + * Get outstanding proposals of thirdparty + * + * @param int $id ID of the thirdparty + * @param string $mode 'customer' or 'supplier' + * + * @url GET {id}/outstandingproposals + * + * @return array List of outstandings proposals of thirdparty + * + * @throws 400 + * @throws 401 + * @throws 404 + */ + function getOutStandingProposals($id, $mode='customer') + { + $obj_ret = array(); + + if(! DolibarrApiAccess::$user->rights->societe->lire) { + throw new RestException(401); + } + + if(empty($id)) { + throw new RestException(400, 'Thirdparty ID is mandatory'); + } + + if( ! DolibarrApi::_checkAccessToResource('societe',$id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->company->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Thirdparty not found'); + } + + $result = $this->company->getOutstandingProposals($mode); + + unset($result['total_ht']); + unset($result['total_ttc']); + + return $result; + } + + + /** + * Get outstanding orders of thirdparty + * + * @param int $id ID of the thirdparty + * @param string $mode 'customer' or 'supplier' + * + * @url GET {id}/outstandingorders + * + * @return array List of outstandings orders of thirdparty + * + * @throws 400 + * @throws 401 + * @throws 404 + */ + function getOutStandingOrder($id, $mode='customer') + { + $obj_ret = array(); + + if(! DolibarrApiAccess::$user->rights->societe->lire) { + throw new RestException(401); + } + + if(empty($id)) { + throw new RestException(400, 'Thirdparty ID is mandatory'); + } + + if( ! DolibarrApi::_checkAccessToResource('societe',$id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->company->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Thirdparty not found'); + } + + $result = $this->company->getOutstandingOrders($mode); + + unset($result['total_ht']); + unset($result['total_ttc']); + + return $result; + } + + /** + * Get outstanding invoices of thirdparty + * + * @param int $id ID of the thirdparty + * @param string $mode 'customer' or 'supplier' + * + * @url GET {id}/outstandinginvoices + * + * @return array List of outstandings invoices of thirdparty + * + * @throws 400 + * @throws 401 + * @throws 404 + */ + function getOutStandingInvoices($id, $mode='customer') + { + $obj_ret = array(); + + if(! DolibarrApiAccess::$user->rights->societe->lire) { + throw new RestException(401); + } + + if(empty($id)) { + throw new RestException(400, 'Thirdparty ID is mandatory'); + } + + if( ! DolibarrApi::_checkAccessToResource('societe',$id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->company->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Thirdparty not found'); + } + + $result = $this->company->getOutstandingBills($mode); + + unset($result['total_ht']); + unset($result['total_ttc']); + + return $result; + } + + + /** * Get fixed amount discount of a thirdparty (all sources: deposit, credit note, commercial offers...) * diff --git a/htdocs/societe/class/client.class.php b/htdocs/societe/class/client.class.php index b4ee6b86249..6db71eb4218 100644 --- a/htdocs/societe/class/client.class.php +++ b/htdocs/societe/class/client.class.php @@ -65,7 +65,7 @@ class Client extends Societe $clause = "AND"; } $sql.= " ".$clause." s.client IN (1,2,3)"; - $sql.= ' AND s.entity IN ('.getEntity($this->element, 1).')'; + $sql.= ' AND s.entity IN ('.getEntity($this->element).')'; $sql.= " GROUP BY s.client"; $resql=$this->db->query($sql); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 4b1e074b7ee..b1255e10b9c 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -739,7 +739,7 @@ class Societe extends CommonObject * @param int $call_trigger 0=no, 1=yes * @param int $allowmodcodeclient Inclut modif code client et code compta * @param int $allowmodcodefournisseur Inclut modif code fournisseur et code compta fournisseur - * @param string $action 'add' or 'update' + * @param string $action 'add' or 'update' or 'merge' * @param int $nosyncmember Do not synchronize info of linked member * @return int <0 if KO, >=0 if OK */ @@ -868,7 +868,12 @@ class Societe extends CommonObject // Check name is required and codes are ok or unique. // If error, this->errors[] is filled $result = 0; - if ($action != 'add') $result = $this->verify(); // We don't check when update called during a create because verify was already done + if ($action != 'add' && $action != 'merge') + { + // We don't check when update called during a create because verify was already done. + // For a merge, we suppose source data is clean and a customer code of a deleted thirdparty must be accepted into a target thirdparty with empty code without duplicate error + $result = $this->verify(); + } if ($result >= 0) { @@ -1149,7 +1154,8 @@ class Societe extends CommonObject $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_departements as d ON s.fk_departement = d.rowid'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_typent as te ON s.fk_typent = te.id'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON s.fk_incoterms = i.rowid'; - $sql .= ' WHERE s.entity IN ('.getEntity($this->element, 1).')'; + + $sql .= ' WHERE s.entity IN ('.getEntity($this->element).')'; if ($rowid) $sql .= ' AND s.rowid = '.$rowid; if ($ref) $sql .= " AND s.nom = '".$this->db->escape($ref)."'"; if ($ref_ext) $sql .= " AND s.ref_ext = '".$this->db->escape($ref_ext)."'"; @@ -3475,7 +3481,7 @@ class Societe extends CommonObject $outstandingOpened+=$obj->total_ttc; } } - return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); + return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); // 'opened' is 'incl taxes' } else return array(); @@ -3515,7 +3521,7 @@ class Societe extends CommonObject $outstandingOpened+=$obj->total_ttc; } } - return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); + return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); // 'opened' is 'incl taxes' } else return array(); @@ -3586,7 +3592,7 @@ class Societe extends CommonObject $outstandingOpened+=$obj->total_ttc - $paiement - $creditnotes - $deposits; } } - return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); + return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); // 'opened' is 'incl taxes' } else { @@ -3781,16 +3787,22 @@ class Societe extends CommonObject * Function used to replace a thirdparty id with another one. * It must be used within a transaction to avoid trouble * - * @param DoliDB $db Database handler - * @param int $origin_id Old thirdparty id - * @param int $dest_id New thirdparty id - * @return bool + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id (will be removed) + * @param int $dest_id New thirdparty id + * @return bool True if success, False if error */ public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) { + if ($origin_id == $id) + { + dol_syslog('Error: Try to merge a thirdparty into itself'); + return false; + } + /** - * Thirdparty commercials cannot be the same in both thirdparties so we look for them and remove some - * Because this function is meant to be executed within a transaction, we won't take care of it. + * Thirdparty commercials cannot be the same in both thirdparties so we look for them and remove some to avoid duplicate. + * Because this function is meant to be executed within a transaction, we won't take care of begin/commit. */ $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'societe_commerciaux '; $sql .= ' WHERE fk_soc = '.(int) $dest_id.' AND fk_user IN ( '; diff --git a/htdocs/societe/contact.php b/htdocs/societe/contact.php index 4077c1e1b28..d57f61045c0 100644 --- a/htdocs/societe/contact.php +++ b/htdocs/societe/contact.php @@ -44,11 +44,7 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; if (! empty($conf->adherent->enabled)) require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; -$langs->load("companies"); -$langs->load("commercial"); -$langs->load("bills"); -$langs->load("banks"); -$langs->load("users"); +$langs->loadLangs(array("companies","commercial","bills","banks","users")); if (! empty($conf->categorie->enabled)) $langs->load("categories"); if (! empty($conf->incoterm->enabled)) $langs->load("incoterm"); if (! empty($conf->notification->enabled)) $langs->load("mails"); @@ -115,6 +111,9 @@ if (empty($reshook)) exit; } } + + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; } @@ -169,8 +168,6 @@ else if ($action != 'presend') { - print '
    '; - // Contacts list if (empty($conf->global->SOCIETE_DISABLE_CONTACTS)) { @@ -182,10 +179,6 @@ else { $result=show_addresses($conf,$langs,$db,$object,$_SERVER["PHP_SELF"].'?socid='.$object->id); } - - - print '
    '; - } } diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index 6de4ae1296c..47852c71403 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -142,6 +142,9 @@ if (($tmp = $langs->transnoentities("ProfId4".$mysoc->country_code)) && $tmp != if (($tmp = $langs->transnoentities("ProfId5".$mysoc->country_code)) && $tmp != "ProfId5".$mysoc->country_code && $tmp != '-') $fieldstosearchall['s.idprof5']='ProfId5'; if (($tmp = $langs->transnoentities("ProfId6".$mysoc->country_code)) && $tmp != "ProfId6".$mysoc->country_code && $tmp != '-') $fieldstosearchall['s.idprof6']='ProfId6'; if (!empty($conf->barcode->enabled)) $fieldstosearchall['s.barcode']='Gencod'; +// Personalized search criterias. Example: $conf->global->THIRDPARTY_QUICKSEARCH_ON_FIELDS = 's.nom=ThirdPartyName;s.name_alias=AliasNameShort;s.code_client=CustomerCode' +if (! empty($conf->global->THIRDPARTY_QUICKSEARCH_ON_FIELDS)) $fieldstosearchall=dolExplodeIntoArray($conf->global->THIRDPARTY_QUICKSEARCH_ON_FIELDS); + // Define list of fields to show into list $checkedcustomercode=(in_array($contextpage, array('thirdpartylist', 'customerlist', 'prospectlist')) ? 1 : 0); @@ -513,7 +516,7 @@ $param=''; if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; if ($search_all != '') $param = "&sall=".urlencode($search_all); -if ($sall != '') $param .= "&sall=".urlencode($sall); +if ($sall != '') $param.= "&sall=".urlencode($sall); if ($search_categ_cus > 0) $param.='&search_categ_cus='.urlencode($search_categ_cus); if ($search_categ_sup > 0) $param.='&search_categ_sup='.urlencode($search_categ_sup); if ($search_sale > 0) $param.='&search_sale='.urlencode($search_sale); @@ -995,16 +998,7 @@ while ($i < min($num, $limit)) $savalias = $obj->name_alias; if (! empty($arrayfields['s.name_alias']['checked'])) $companystatic->name_alias=''; print '
    '; - //if (! empty($arrayfields['s.name_alias']['checked'])) // Hide alias from output - //{ - $savalias=$companystatic->name_alias; - $companystatic->name_alias=''; - //} print $companystatic->getNomUrl(1,'',100); - //if (! empty($arrayfields['s.name_alias']['checked'])) // Hide alias from output - //{ - $companystatic->name_alias=$savalias; - //} print "