Merge remote-tracking branch 'Dolibarr/develop' into develop

This commit is contained in:
Francis Appels 2020-10-05 12:10:30 +02:00
commit 00ebb7fc97
46 changed files with 356 additions and 228 deletions

View File

@ -13,5 +13,5 @@ jobs:
- name: Exakat
uses: docker://exakat/exakat-ga
with:
ignore_rules: 'Performances/PrePostIncrement,Functions/WrongNumberOfArguments,Variables/UndefinedVariable,Classes/DontUnsetProperties,Classes/NonPpp,Classes/StaticMethodsCalledFromObject,Classes/UseClassOperator,Functions/UsesDefaultArguments,Php/NoClassInGlobal,Php/ShouldUseCoalesce,Structures/MergeIfThen,Structures/ElseIfElseif,Structures/RepeatedPrint,Structures/UselessParenthesis'
ignore_rules: 'Classes/UseInstanceof,Performances/PrePostIncrement,Functions/WrongNumberOfArguments,Variables/UndefinedVariable,Classes/DontUnsetProperties,Classes/NonPpp,Classes/StaticMethodsCalledFromObject,Classes/UseClassOperator,Functions/UsesDefaultArguments,Php/NoClassInGlobal,Php/ShouldUseCoalesce,Structures/MergeIfThen,Structures/ElseIfElseif,Structures/RepeatedPrint,Structures/UselessParenthesis,Structures/SwitchWithoutDefault,Structures/ShouldMakeTernary,Structures/UseConstant'
ignore_dirs: '/htdocs/includes,/htdocs/build,/htdocs/dev,/htdocs/doc,/htdocs/scripts,/htdocs/test'

View File

@ -23,7 +23,7 @@ Following changes may create regressions for some external modules, but were nec
you must now also include declaration of the Trait 'CommonIncoterm' in your class. All incoterm functions were moved into this Trait.
* The GETPOST(..., 'alpha') has now the same behaviour than GETPOST(..., 'alphanohtml') so no html will be allowed. Use GETPOST(..., 'restricthtml') to accept HTML.
* If you have links in your code with '&action=delete' as a parameter, you must also add '&token='.newToken() as another parameter to avoid CSRF protection errors.
* The API addPayment for api_invoice has evolved to accept amount into a foreign currency. You must provide array(amount=>X,mutlicurrency_ammount=>Y) instead of amount.
***** ChangeLog for 12.0.3 compared to 12.0.2 *****
FIX: 10.0 - when the mime file name is different from the filesystem name, the attachment name should be the mime filename

View File

@ -26,7 +26,7 @@
$sapi_type = php_sapi_name();
$script_file = basename(__FILE__);
$path=dirname(__FILE__).'/';
$path=__DIR__.'/';
// Test si mode batch
if (substr($sapi_type, 0, 3) == 'cgi') {

View File

@ -91,11 +91,7 @@ $hookmanager->initHooks(array('admin'));
// Put here declaration of dictionaries properties
// Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this.
if (! empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES)) {
$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 0, 15, 30, 0, 37, 0, 25, 0);
} else {
$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 27, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 0, 15, 30, 0, 37, 0, 25, 0);
}
$taborder = array(9, 0, 4, 3, 2, 0, 1, 8, 19, 16, 39, 27, 40, 38, 0, 5, 11, 0, 32, 33, 34, 0, 6, 0, 29, 0, 7, 24, 28, 17, 35, 36, 0, 10, 23, 12, 13, 0, 14, 0, 22, 20, 18, 21, 0, 15, 30, 0, 37, 0, 25, 0);
// Name of SQL tables of dictionaries
$tabname = array();
@ -133,7 +129,6 @@ $tabname[30] = MAIN_DB_PREFIX."c_format_cards";
$tabname[32] = MAIN_DB_PREFIX."c_hrm_public_holiday";
$tabname[33] = MAIN_DB_PREFIX."c_hrm_department";
$tabname[34] = MAIN_DB_PREFIX."c_hrm_function";
$tabname[35] = MAIN_DB_PREFIX."c_exp_tax_cat";
$tabname[36] = MAIN_DB_PREFIX."c_exp_tax_range";
$tabname[37] = MAIN_DB_PREFIX."c_units";
@ -485,8 +480,8 @@ $tabcond[35] = !empty($conf->expensereport->enabled);
$tabcond[36] = !empty($conf->expensereport->enabled);
$tabcond[37] = !empty($conf->product->enabled);
$tabcond[38] = !empty($conf->socialnetworks->enabled);
$tabcond[39] = (! empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS));
$tabcond[40] = ! empty($conf->societe->enabled);
$tabcond[39] = (!empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES));
$tabcond[40] = (!empty($conf->societe->enabled) && !empty($conf->global->THIRDPARTY_ENABLE_PROSPECTION_ON_ALTERNATIVE_ADRESSES));
// List of help for fields
$tabhelp = array();

View File

@ -154,6 +154,9 @@ if (ini_get('safe_mode') && !empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
}
}
print '<input type="text" name="MAIN_ANTIVIRUS_COMMAND" class="minwidth500imp" value="'.(!empty($conf->global->MAIN_ANTIVIRUS_COMMAND) ?dol_escape_htmltag($conf->global->MAIN_ANTIVIRUS_COMMAND) : '').'">';
if (defined('MAIN_ANTIVIRUS_COMMAND')) {
print '<br><span class="opacitymedium">'.$langs->trans("ValueIsForcedBySystem").'</span>';
}
print "</td>";
print '</tr>';
@ -165,6 +168,9 @@ print '<span class="opacitymedium">'.$langs->trans("AntiVirusParamExample").'</s
print '</td>';
print '<td>';
print '<input type="text" name="MAIN_ANTIVIRUS_PARAM" class="minwidth500imp" value="'.(!empty($conf->global->MAIN_ANTIVIRUS_PARAM) ?dol_escape_htmltag($conf->global->MAIN_ANTIVIRUS_PARAM) : '').'">';
if (defined('MAIN_ANTIVIRUS_PARAM')) {
print '<br><span class="opacitymedium">'.$langs->trans("ValueIsForcedBySystem").'</span>';
}
print "</td>";
print '</tr>';

View File

@ -1,5 +1,5 @@
<?php
/* Copyright (C) 2005-2017 Laurent Destailleur <eldy@users.sourceforge.net>
/* Copyright (C) 2005-2020 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2007-2012 Regis Houssin <regis.houssin@inodbox.com>
*
@ -19,7 +19,7 @@
/**
* \file htdocs/admin/system/dolibarr.php
* \brief Page to show Dolibarr informations
* \brief Page to show Dolibarr information
*/
require '../../main.inc.php';
@ -365,7 +365,7 @@ foreach ($configfileparameters as $key => $value)
print '<td>'.$newkey.'</td>';
// Value
print "<td>";
if ($newkey == 'dolibarr_main_db_pass') {
if (in_array($newkey, array('dolibarr_main_db_pass', 'dolibarr_main_auth_ldap_admin_pass'))) {
if (empty($dolibarr_main_prod)) {
print '<!-- '.${$newkey}.' -->';
}

View File

@ -56,11 +56,13 @@ $arrayfields = array(
'name'=>array('label'=>$langs->trans("Modules"), 'checked'=>1, 'position'=>10),
'version'=>array('label'=>$langs->trans("Version"), 'checked'=>1, 'position'=>20),
'id'=>array('label'=>$langs->trans("IdModule"), 'checked'=>1, 'position'=>30),
'module_position'=>array('label'=>$langs->trans("Position"), 'checked'=>1, 'position'=>35),
'permission'=>array('label'=>$langs->trans("IdPermissions"), 'checked'=>1, 'position'=>40)
);
$arrayfields = dol_sort_array($arrayfields, 'position');
/*
* Actions
*/
@ -129,6 +131,7 @@ foreach ($modules as $key=>$module) {
$newModule->name = $module->getName();
$newModule->version = $module->getVersion();
$newModule->id = $key;
$newModule->module_position = $module->module_position;
$alt = $module->name.' - '.$modules_files[$key];
@ -223,6 +226,10 @@ if ($arrayfields['id']['checked']) {
print '<input class="flat" type="text" name="search_id" size="8" value="'.$search_id.'">';
print '</td>';
}
if ($arrayfields['module_position']['checked']) {
print '<td class="liste_titre left">';
print '</td>';
}
if ($arrayfields['permission']['checked']) {
print '<td class="liste_titre left">';
print '<input class="flat" type="text" name="search_permission" size="8" value="'.$search_permission.'">';
@ -247,6 +254,9 @@ if ($arrayfields['version']['checked']) {
if ($arrayfields['id']['checked']) {
print_liste_field_titre($arrayfields['id']['label'], $_SERVER["PHP_SELF"], "id", "", "", "", $sortfield, $sortorder);
}
if ($arrayfields['module_position']['checked']) {
print_liste_field_titre($arrayfields['module_position']['label'], $_SERVER["PHP_SELF"], "module_position", "", "", "", $sortfield, $sortorder);
}
if ($arrayfields['permission']['checked']) {
print_liste_field_titre($arrayfields['permission']['label'], $_SERVER["PHP_SELF"], "permission", "", "", "", $sortfield, $sortorder);
}
@ -273,6 +283,8 @@ if ($sortfield == "id" && $sortorder == "desc") usort($moduleList, "compareIdDes
if ($sortfield == "permission" && $sortorder == "asc") usort($moduleList, "comparePermissionIdsAsc");
if ($sortfield == "permission" && $sortorder == "desc") usort($moduleList, "comparePermissionIdsDesc");
$moduleList = dol_sort_array($moduleList, 'module_position');
foreach ($moduleList as $module) {
print '<tr class="oddeven">';
@ -291,6 +303,10 @@ foreach ($moduleList as $module) {
print '<td class="center">'.$module->id.'</td>';
}
if ($arrayfields['module_position']['checked']) {
print '<td class="center">'.$module->module_position.'</td>';
}
if ($arrayfields['permission']['checked']) {
$idperms = '';

View File

@ -147,7 +147,7 @@ print '<td class="liste_titre">';
print $langs->trans("DatabaseName").' : <b>'.$dolibarr_main_db_name.'</b><br>';
print '</td>';
print '</tr>';
print '<tr class="oddeven"><td style="padding-left: 8px">';
print '<tr class="oddeven nohover"><td style="padding-left: 8px" class="nohover">';
print '<table class="centpercent">';
print '<tr>';
print '<td class="tdtop">';
@ -160,10 +160,10 @@ if (in_array($type, array('mysql', 'mysqli'))) {
print '</div>';
print '<br>';
print '<div class="formelementrow"><input type="radio" name="what" value="mysqlnobin" id="radio_dump_mysql_nobin" />';
print '<label for="radio_dump_mysql">MySQL Dump (php) '.img_warning($langs->trans('BackupPHPWarning')).'</label>';
print '<label for="radio_dump_mysql_nobin">MySQL Dump (php) '.img_warning($langs->trans('BackupPHPWarning')).'</label>';
print '</div>';
} elseif (in_array($type, array('pgsql'))) {
print '<div class="formelementrow"><input type="radio" name="what" value="postgresql" id="radio_dump_postgresql" />';
print '<div class="formelementrow"><input type="radio" name="what" value="postgresql" id="radio_dump_postgresql" />';
print '<label for="radio_dump_postgresql">PostgreSQL Dump (pg_dump)</label>';
print '</div>';
} else {

View File

@ -544,9 +544,10 @@ class Orders extends DolibarrApi
* Unlink a contact type of given order
*
* @param int $id Id of order to update
* @param int $rowid Row key of the contact in the array contact_ids.
* @param int $contactid Id of contact
* @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER).
*
* @url DELETE {id}/contact/{rowid}
* @url DELETE {id}/contact/{contactid}/{type}
*
* @return int
*
@ -554,7 +555,7 @@ class Orders extends DolibarrApi
* @throws RestException 404
* @throws RestException 500
*/
public function deleteContact($id, $rowid)
public function deleteContact($id, $contactid, $type)
{
if (!DolibarrApiAccess::$user->rights->commande->creer) {
throw new RestException(401);
@ -569,10 +570,16 @@ class Orders extends DolibarrApi
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$result = $this->commande->delete_linked_contact($rowid);
$contacts = $this->commande->liste_contact();
if (!$result) {
throw new RestException(500, 'Error when deleted the contact');
foreach ($contacts as $contact) {
if ($contact['id'] == $contactid && $contact['code'] == $type) {
$result = $this->commande->delete_contact($contact['rowid']);
if (!$result) {
throw new RestException(500, 'Error when deleted the contact');
}
}
}
return array(

View File

@ -1365,6 +1365,8 @@ if ($action == 'create')
// Only on template invoices
$substitutionarray['__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__'] = $langs->trans("DateNextInvoiceBeforeGen").' ('.$langs->trans("Example").': '.dol_print_date(($object->date_when ? $object->date_when : dol_now()), 'dayhour').')';
$substitutionarray['__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__'] = $langs->trans("DateNextInvoiceAfterGen").' ('.$langs->trans("Example").': '.dol_print_date(dol_time_plus_duree(($object->date_when ? $object->date_when : dol_now()), $object->frequency, $object->unit_frequency), 'dayhour').')';
$substitutionarray['__INVOICE_COUNTER_CURRENT__'] = $object->nb_gen_done;
$substitutionarray['__INVOICE_COUNTER_MAX__'] = $object->nb_gen_max;
$htmltext = '<i>'.$langs->trans("FollowingConstantsWillBeSubstituted").':<br>';
foreach ($substitutionarray as $key => $val)

View File

@ -477,8 +477,9 @@ class Invoices extends DolibarrApi
*
* @param int $id Id of invoice to update
* @param int $rowid Row key of the contact in the array contact_ids.
* @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER).
*
* @url DELETE {id}/contact/{rowid}
* @url DELETE {id}/contact/{rowid}/{type}
*
* @return array
*
@ -486,7 +487,7 @@ class Invoices extends DolibarrApi
* @throws RestException 404
* @throws RestException 500
*/
public function deleteContact($id, $rowid)
public function deleteContact($id, $rowid, $type)
{
if (!DolibarrApiAccess::$user->rights->facture->creer) {
throw new RestException(401);
@ -502,10 +503,17 @@ class Invoices extends DolibarrApi
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$result = $this->invoice->delete_contact($rowid);
if ($result < 0) {
throw new RestException(500, 'Error when deleted the contact');
}
$contacts = $this->invoice->liste_contact();
foreach ($contacts as $contact) {
if ($contact['id'] == $rowid && $contact['code'] == $type) {
$result = $this->invoice->delete_contact($contact['rowid']);
if (!$result) {
throw new RestException(500, 'Error when deleted the contact');
}
}
}
return $this->_cleanObjectDatas($this->invoice);
}
@ -1397,28 +1405,29 @@ class Invoices extends DolibarrApi
/**
* Add a payment to pay partially or completely one or several invoices.
* Warning: Take care that all invoices are owned by the same customer.
* Example of value for parameter arrayofamounts: {"1": "99.99", "2": "10"}
* Example of value for parameter arrayofamounts: {"1": {"amount": "99.99", "multicurrency_amount": ""}, "2": {"amount": "", "multicurrency_amount": "10"}}
*
* @param array $arrayofamounts {@from body} Array with id of invoices with amount to pay for each invoice
* @param string $datepaye {@from body} Payment date {@type timestamp}
* @param int $paymentid {@from body} Payment mode Id {@min 1}
* @param string $closepaidinvoices {@from body} Close paid invoices {@choice yes,no}
* @param int $accountid {@from body} Account Id {@min 1}
* @param string $num_payment {@from body} Payment number (optional)
* @param string $comment {@from body} Note private (optional)
* @param string $chqemetteur {@from body} Payment issuer (mandatory if paiementcode = 'CHQ')
* @param string $chqbank {@from body} Issuer bank name (optional)
* @param int $paymentid {@from body} Payment mode Id {@min 1}
* @param string $closepaidinvoices {@from body} Close paid invoices {@choice yes,no}
* @param int $accountid {@from body} Account Id {@min 1}
* @param string $num_payment {@from body} Payment number (optional)
* @param string $comment {@from body} Note private (optional)
* @param string $chqemetteur {@from body} Payment issuer (mandatory if paiementcode = 'CHQ')
* @param string $chqbank {@from body} Issuer bank name (optional)
* @param string $ref_ext {@from body} External reference (optional)
* @param bool $accepthigherpayment {@from body} Accept higher payments that it remains to be paid (optional)
*
* @url POST /paymentsdistributed
*
* @return int Payment ID
*
* @throws RestException 400
* @throws RestException 401
* @throws RestException 403
* @throws RestException 404
*/
public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '')
public function addPaymentDistributed($arrayofamounts, $datepaye, $paymentid, $closepaidinvoices, $accountid, $num_payment = '', $comment = '', $chqemetteur = '', $chqbank = '', $ref_ext = '', $accepthigherpayment = false)
{
global $conf;
@ -1451,7 +1460,7 @@ class Invoices extends DolibarrApi
$multicurrency_amounts = array();
// Loop on each invoice to pay
foreach ($arrayofamounts as $id => $amount)
foreach ($arrayofamounts as $id => $amountarray)
{
$result = $this->invoice->fetch($id);
if (!$result) {
@ -1459,33 +1468,52 @@ class Invoices extends DolibarrApi
throw new RestException(404, 'Invoice ID '.$id.' not found');
}
// Calculate amount to pay
$totalpaye = $this->invoice->getSommePaiement();
$totalcreditnotes = $this->invoice->getSumCreditNotesUsed();
$totaldeposits = $this->invoice->getSumDepositsUsed();
$resteapayer = price2num($this->invoice->total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits, 'MT');
if ($amount != 'remain')
{
if ($amount > $resteapayer)
{
$this->db->rollback();
throw new RestException(400, 'Payment amount on invoice ID '.$id.' ('.$amount.') is higher than remain to pay ('.$resteapayer.')');
}
$resteapayer = $amount;
if (($amountarray["amount"] == "remain" || $amountarray["amount"] > 0) && ($amountarray["multicurrency_amount"] == "remain" || $amountarray["multicurrency_amount"] > 0)) {
$this->db->rollback();
throw new RestException(400, 'Payment in both currency '.$id.' ( amount: '.$amountarray["amount"].', multicurrency_amount: '.$amountarray["multicurrency_amount"].')');
}
// Clean parameters amount if payment is for a credit note
if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
$resteapayer = price2num($resteapayer, 'MT');
$amounts[$id] = -$resteapayer;
$is_multicurrency = 0;
$total_ttc = $this->invoice->total_ttc;
if ($amountarray["multicurrency_amount"] > 0 || $amountarray["multicurrency_amount"] == "remain") {
$is_multicurrency = 1;
$total_ttc = $this->invoice->multicurrency_total_ttc;
}
// Calculate amount to pay
$totalpaye = $this->invoice->getSommePaiement($is_multicurrency);
$totalcreditnotes = $this->invoice->getSumCreditNotesUsed($is_multicurrency);
$totaldeposits = $this->invoice->getSumDepositsUsed($is_multicurrency);
$remainstopay = $amount = price2num($total_ttc - $totalpaye - $totalcreditnotes - $totaldeposits, 'MT');
if (!$is_multicurrency && $amountarray["amount"] != 'remain')
{
$amount = price2num($amountarray["amount"], 'MT');
}
if ($is_multicurrency && $amountarray["multicurrency_amount"] != 'remain')
{
$amount = price2num($amountarray["multicurrency_amount"], 'MT');
}
if ($amount > $remainstopay && $accepthigherpayment == false) {
$this->db->rollback();
throw new RestException(400, 'Payment amount on invoice ID '.$id.' ('.$amount.') is higher than remain to pay ('.$remainstopay.')');
}
if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) {
$amount = -$amount;
}
if ($is_multicurrency) {
$amounts[$id] = null;
// Multicurrency
$newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
$multicurrency_amounts[$id] = -$newvalue;
$multicurrency_amounts[$id] = $amount;
} else {
$resteapayer = price2num($resteapayer, 'MT');
$amounts[$id] = $resteapayer;
$amounts[$id] = $amount;
// Multicurrency
$newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT');
$multicurrency_amounts[$id] = $newvalue;
$multicurrency_amounts[$id] = null;
}
}
@ -1498,7 +1526,7 @@ class Invoices extends DolibarrApi
$paymentobj->paiementcode = dol_getIdFromCode($this->db, $paymentid, 'c_paiement', 'id', 'code', 1);
$paymentobj->num_payment = $num_payment;
$paymentobj->note_private = $comment;
$paymentobj->ref_ext = $ref_ext;
$payment_id = $paymentobj->create(DolibarrApiAccess::$user, ($closepaidinvoices == 'yes' ? 1 : 0)); // This include closing invoices
if ($payment_id < 0)
{

View File

@ -458,7 +458,7 @@ class Facture extends CommonInvoice
$nextdatewhen = null;
$previousdaynextdatewhen = null;
// Create invoice from a template invoice
// Create invoice from a template recurring invoice
if ($this->fac_rec > 0)
{
$this->fk_fac_rec_source = $this->fac_rec;

View File

@ -287,6 +287,18 @@ $dolibarr_cron_allow_cli='0';
// Examples: '-1' (sending by cli is forbidden)
// $dolibarr_mailing_limit_sendbycli='0';
// MAIN_ANTIVIRUS_COMMAND (as a constant)
// Force a value for the antivirus command line tool so setup for admin user interface has no effect.
// Default value: ''
// Example: '/usr/bin/clamdscan';
// define('MAIN_ANTIVIRUS_COMMAND', '/usr/bin/clamdscan');
// MAIN_ANTIVIRUS_PARAM (as a constant)
// Force a value for the antivirus parameters on command line so setup for admin user interface has no effect.
// Default value: ''
// Example: '--fdpass';
// define('MAIN_ANTIVIRUS_PARAM', '--fdpass');
//##################
// Other

View File

@ -170,29 +170,6 @@ class ModeleBoxes // Can't be abtract as it is instantiated to build "empty" box
}
}
/**
* Standard method to get content of a box
*
* @param array $head Array with properties of box title
* @param array $contents Array with properties of box lines
*
* @return string
*/
public function outputBox($head = null, $contents = null)
{
global $langs, $user, $conf;
// Trick to get result into a var from a function that makes print instead of return
// TODO Replace ob_start with param nooutput=1 into showBox
ob_start();
$result = $this->showBox($head, $contents);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Standard method to show a box (usage by boxes not mandatory, a box can still use its own showBox function)
*

View File

@ -684,6 +684,9 @@ class Conf
// If we are in develop mode, we activate the option MAIN_SECURITY_CSRF_WITH_TOKEN to 1 if not already defined.
if (!isset($this->global->MAIN_SECURITY_CSRF_WITH_TOKEN) && $this->global->MAIN_FEATURES_LEVEL >= 2) $this->global->MAIN_SECURITY_CSRF_WITH_TOKEN = 1;
if (defined('MAIN_ANTIVIRUS_COMMAND')) $this->global->MAIN_ANTIVIRUS_COMMAND = constant('MAIN_ANTIVIRUS_COMMAND');
if (defined('MAIN_ANTIVIRUS_PARAM')) $this->global->MAIN_ANTIVIRUS_PARAM = constant('MAIN_ANTIVIRUS_PARAM');
// For backward compatibility
if (isset($this->product)) $this->produit = $this->product;
if (isset($this->facture)) $this->invoice = $this->facture;

View File

@ -1916,13 +1916,16 @@ class Form
* 'warehouseclosed' = count products from closed warehouses,
* 'warehouseinternal' = count products from warehouses for internal correct/transfer only
* @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...])
* @return void
* @param string $nooutput No print, return the output into a string
* @return void|string
*/
public 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())
public 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(), $nooutput = 0)
{
// phpcs:enable
global $langs, $conf;
$out = '';
// check parameters
$price_level = (!empty($price_level) ? $price_level : 0);
if (is_null($ajaxoptions)) $ajaxoptions = array();
@ -1962,100 +1965,103 @@ class Form
if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
$urloption .= '&socid='.$socid;
}
print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
if (!empty($conf->variants->enabled)) {
?>
$out .= '
<script>
selected = <?php echo json_encode($selected_combinations) ?>;
selected = '.json_encode($selected_combinations).';
combvalues = {};
jQuery(document).ready(function () {
jQuery("input[name='prod_entry_mode']").change(function () {
if (jQuery(this).val() == 'free') {
jQuery('div#attributes_box').empty();
jQuery("input[name=\'prod_entry_mode\']").change(function () {
if (jQuery(this).val() == \'free\') {
jQuery(\'div#attributes_box\').empty();
}
});
jQuery("input#<?php echo $htmlname ?>").change(function () {
jQuery("input#'.$htmlname.'").change(function () {
if (!jQuery(this).val()) {
jQuery('div#attributes_box').empty();
jQuery(\'div#attributes_box\').empty();
return;
}
jQuery.getJSON("<?php echo dol_buildpath('/variants/ajax/getCombinations.php', 2) ?>", {
jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
id: jQuery(this).val()
}, function (data) {
jQuery('div#attributes_box').empty();
jQuery(\'div#attributes_box\').empty();
jQuery.each(data, function (key, val) {
combvalues[val.id] = val.values;
var span = jQuery(document.createElement('div')).css({
'display': 'table-row'
var span = jQuery(document.createElement(\'div\')).css({
\'display\': \'table-row\'
});
span.append(
jQuery(document.createElement('div')).text(val.label).css({
'font-weight': 'bold',
'display': 'table-cell',
'text-align': 'right'
jQuery(document.createElement(\'div\')).text(val.label).css({
\'font-weight\': \'bold\',
\'display\': \'table-cell\',
\'text-align\': \'right\'
})
);
var html = jQuery(document.createElement('select')).attr('name', 'combinations[' + val.id + ']').css({
'margin-left': '15px',
'white-space': 'pre'
var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
\'margin-left\': \'15px\',
\'white-space\': \'pre\'
}).append(
jQuery(document.createElement('option')).val('')
jQuery(document.createElement(\'option\')).val(\'\')
);
jQuery.each(combvalues[val.id], function (key, val) {
var tag = jQuery(document.createElement('option')).val(val.id).html(val.value);
var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
if (selected[val.fk_product_attribute] == val.id) {
tag.attr('selected', 'selected');
tag.attr(\'selected\', \'selected\');
}
html.append(tag);
});
span.append(html);
jQuery('div#attributes_box').append(span);
jQuery(\'div#attributes_box\').append(span);
});
})
});
<?php if ($selected): ?>
jQuery("input#<?php echo $htmlname ?>").change();
<?php endif ?>
'.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
});
</script>
<?php
';
}
if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
elseif ($hidelabel > 1) {
$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
if ($hidelabel == 2) {
print img_picto($langs->trans("Search"), 'search');
$out .= img_picto($langs->trans("Search"), 'search');
}
}
print '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
if ($hidelabel == 3) {
print img_picto($langs->trans("Search"), 'search');
$out .= img_picto($langs->trans("Search"), 'search');
}
} else {
print $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
$out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
}
if (empty($nooutput)) print $out;
else return $out;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return list of products for a customer
* Return list of products for a customer.
* Called by select_produits.
*
* @param int $selected Preselected product
* @param string $htmlname Name of select html
@ -2262,7 +2268,7 @@ class Form
$sql .= $this->db->plimit($limit, 0);
// Build output string
dol_syslog(get_class($this)."::select_produits_list search product", LOG_DEBUG);
dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
$result = $this->db->query($sql);
if ($result)
{
@ -2308,7 +2314,7 @@ class Form
$sql .= " WHERE fk_product_price=".$objp->price_rowid;
$sql .= " ORDER BY quantity ASC";
dol_syslog(get_class($this)."::select_produits_list search price by qty", LOG_DEBUG);
dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
$result2 = $this->db->query($sql);
if ($result2)
{

View File

@ -114,6 +114,9 @@ class FormFile
if (empty($usewithoutform)) // Try to avoid this and set instead the form by the caller.
{
// Add a param as GET parameter to detect when POST were cleaned by PHP because a file larger than post_max_size
$url .= (strpos('?', $url) === false ? '?' : '&').'uploadform=1';
$out .= '<form name="'.$htmlname.'" id="'.$htmlname.'" action="'.$url.'" enctype="multipart/form-data" method="POST">';
$out .= '<input type="hidden" name="token" value="'.newToken().'">';
$out .= '<input type="hidden" id="'.$htmlname.'_section_dir" name="section_dir" value="'.$sectiondir.'">';

View File

@ -1162,7 +1162,7 @@ class FormOther
//print 'box_order '.$boxactivated[$ii]->box_order.'<br>';
// Show box
$box->loadBox($box_max_lines);
$boxlista .= $box->outputBox();
$boxlista .= $box->showBox(null, null, 1);
}
}
@ -1171,7 +1171,7 @@ class FormOther
$emptybox->box_id = 'A';
$emptybox->info_box_head = array();
$emptybox->info_box_contents = array();
$boxlista .= $emptybox->outputBox(array(), array());
$boxlista .= $emptybox->showBox(array(), array(), 1);
}
$boxlista .= "<!-- End box left container -->\n";
@ -1189,7 +1189,7 @@ class FormOther
//print 'box_order '.$boxactivated[$ii]->box_order.'<br>';
// Show box
$box->loadBox($box_max_lines);
$boxlistb .= $box->outputBox();
$boxlistb .= $box->showBox(null, null, 1);
}
}
@ -1198,7 +1198,7 @@ class FormOther
$emptybox->box_id = 'B';
$emptybox->info_box_head = array();
$emptybox->info_box_contents = array();
$boxlistb .= $emptybox->outputBox(array(), array());
$boxlistb .= $emptybox->showBox(array(), array(), 1);
}
$boxlistb .= "<!-- End box right container -->\n";

View File

@ -1689,8 +1689,11 @@ function phpinfo_array()
{
ob_start();
phpinfo();
$phpinfostring = ob_get_contents();
ob_end_clean();
$info_arr = array();
$info_lines = explode("\n", strip_tags(ob_get_clean(), "<tr><td><h2>")); // end of ob_start()
$info_lines = explode("\n", strip_tags($phpinfostring, "<tr><td><h2>"));
$cat = "General";
foreach ($info_lines as $line)
{

View File

@ -1075,13 +1075,11 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable
}
}
if ($reshook < 0) // At least one blocking error returned by one hook
{
if ($reshook < 0) { // At least one blocking error returned by one hook
$errmsg = join(',', $hookmanager->errors);
if (empty($errmsg)) $errmsg = 'ErrorReturnedBySomeHooks'; // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
return $errmsg;
} elseif (empty($reshook))
{
} elseif (empty($reshook)) {
// The file functions must be in OS filesystem encoding.
$src_file_osencoded = dol_osencode($src_file);
$file_name_osencoded = dol_osencode($file_name);
@ -1535,6 +1533,8 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess
$nbok = 0;
for ($i = 0; $i < $nbfile; $i++)
{
if (empty($TFile['name'][$i])) continue; // For example, when submitting a form with no file name
// Define $destfull (path to file including filename) and $destfile (only filename)
$destfull = $upload_dir."/".$TFile['name'][$i];
$destfile = $TFile['name'][$i];

View File

@ -8919,3 +8919,47 @@ function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0,
print '</tr>';
}
/**
* Return a file on output using a lo memory.
* It can return very large files with no need of memory.
* WARNING: This close output buffers.
*
* @param string $fullpath_original_file_osencoded Full path of file to return.
* @param int $method -1 automatic, 0=readfile, 1=fread, 2=stream_copy_to_stream
* @return void
*/
function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
{
global $conf;
if ($method == -1) {
$method = 0;
if (! empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) $method = 1;
if (! empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) $method = 2;
}
// Be sure we don't have output buffering enabled to have readfile working correctly
while (ob_get_level()) ob_end_flush();
// Solution 0
if ($method == 0) {
readfile($fullpath_original_file_osencoded);
}
// Solution 1
elseif ($method == 1) {
$handle = fopen($fullpath_original_file_osencoded, "rb");
while (!feof($handle)) {
print fread($handle, 8192);
}
fclose($handle);
}
// Solution 2
elseif ($method == 2) {
$handle1 = fopen($fullpath_original_file_osencoded, "rb");
$handle2 = fopen("php://output", "wb");
stream_copy_to_stream($handle1, $handle2);
fclose($handle1);
fclose($handle2);
}
}

View File

@ -353,7 +353,7 @@ class pdf_crabe extends ModelePDFFactures
// Set certificate
$cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT;
// If use has no certificate, we try to take the company one
// If user has no certificate, we try to take the company one
if (!$cert) {
$cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT;
}

View File

@ -369,7 +369,7 @@ class pdf_sponge extends ModelePDFFactures
// Set certificate
$cert = empty($user->conf->CERTIFICATE_CRT) ? '' : $user->conf->CERTIFICATE_CRT;
// If use has no certificate, we try to take the company one
// If user has no certificate, we try to take the company one
if (!$cert) {
$cert = empty($conf->global->CERTIFICATE_CRT) ? '' : $conf->global->CERTIFICATE_CRT;
}

View File

@ -54,7 +54,7 @@ class modBom extends DolibarrModules
// It is used to group modules by family in module setup page
$this->family = "products";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '60';
$this->module_position = '65';
// Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));

View File

@ -46,12 +46,11 @@ class modCashDesk extends DolibarrModules
$this->rights_class = 'cashdesk';
$this->family = "portal";
$this->module_position = '55';
$this->module_position = '59';
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));
$this->description = "CashDesk module";
$this->revision = '1.27';
$this->version = 'dolibarr';
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);

View File

@ -45,7 +45,7 @@ class modDeplacement extends DolibarrModules
$this->numero = 75;
$this->family = "hr";
$this->module_position = '41';
$this->module_position = '43';
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));
$this->description = "Gestion des notes de frais et deplacements"; // Si traduction Module75Desc non trouvee

View File

@ -52,7 +52,7 @@ class modEmailCollector extends DolibarrModules
// It is used to group modules by family in module setup page
$this->family = "interface";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '12';
$this->module_position = '23';
// Gives the possibility to the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));

View File

@ -48,7 +48,7 @@ class modMailing extends DolibarrModules
// It is used to group modules by family in module setup page
$this->family = "interface";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '11';
$this->module_position = '22';
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));

View File

@ -52,7 +52,7 @@ class modMrp extends DolibarrModules
// It is used to group modules by family in module setup page
$this->family = "products";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '62';
$this->module_position = '66';
// Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
// Module label (no space allowed), used if translation string 'ModuleMrpName' not found (Mrp is name of module).

View File

@ -51,7 +51,7 @@ class modProduct extends DolibarrModules
$this->numero = 50;
$this->family = "products";
$this->module_position = '25';
$this->module_position = '26';
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));
$this->description = "Product management";

View File

@ -52,7 +52,7 @@ class modRecruitment extends DolibarrModules
// It is used to group modules by family in module setup page
$this->family = "hr";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '51';
$this->module_position = '44';
// Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
// Module label (no space allowed), used if translation string 'ModuleRecruitmentName' not found (Recruitment is name of module).

View File

@ -41,7 +41,7 @@ class modWebServicesClient extends DolibarrModules
$this->numero = 2660;
$this->family = "interface";
$this->module_position = '26';
$this->module_position = '25';
// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
$this->name = preg_replace('/^mod/i', '', get_class($this));
$this->description = "Enable the web service client to call external supplier web services";

View File

@ -309,21 +309,21 @@ if (!empty($extrafields))
<?php
if (! empty($usemargins) && $user->rights->margins->creer)
{
?>
?>
/* Some js test when we click on button "Add" */
jQuery(document).ready(function() {
<?php
if (! empty($conf->global->DISPLAY_MARGIN_RATES)) { ?>
$("input[name='np_marginRate']:first").blur(function(e) {
return checkFreeLine(e, "np_marginRate");
});
<?php
$("input[name='np_marginRate']:first").blur(function(e) {
return checkFreeLine(e, "np_marginRate");
});
<?php
}
if (! empty($conf->global->DISPLAY_MARK_RATES)) { ?>
$("input[name='np_markRate']:first").blur(function(e) {
return checkFreeLine(e, "np_markRate");
});
<?php
$("input[name='np_markRate']:first").blur(function(e) {
return checkFreeLine(e, "np_markRate");
});
<?php
}
?>
});
@ -373,7 +373,7 @@ if (! empty($usemargins) && $user->rights->margins->creer)
return true;
}
<?php
<?php
}
?>

View File

@ -261,10 +261,11 @@ if (!$attachment && !empty($conf->global->MAIN_USE_EXIF_ROTATION) && image_forma
$readfile = !$imgres;
}
if (is_object($db)) $db->close();
// Send file now
if ($readfile) {
header('Content-Length: '.dol_filesize($fullpath_original_file));
readfile($fullpath_original_file_osencoded);
readfileLowMemory($fullpath_original_file_osencoded);
}
if (is_object($db)) $db->close();

View File

@ -269,8 +269,12 @@ foreach ($data as $val)
print '<tr class="oddeven" height="24">';
print '<td class="center">';
if ($year) print '<a href="'.$_SERVER["PHP_SELF"].'?year='.$year.'">'.$year.'</a>';
else print $langs->trans("ValidationDateNotDefinedEvenIfShipmentValidated");
if ($year) {
print '<a href="'.$_SERVER["PHP_SELF"].'?year='.$year.'">'.$year.'</a>';
} else {
// Technical error that should not happen
print 'Error: validation date of shipment is not defined. This looks strange because shipment is validated. Try to run /install/repair.php?standard=confirmed';
}
print '</td>';
print '<td class="right">'.$val['nb'].'</td>';
/*print '<td class="right">'.price(price2num($val['total'],'MT'),1).'</td>';

View File

@ -587,7 +587,7 @@ if (empty($reshook))
}
$object->fetch_thirdparty();
$desc = GETPOST('np_desc', 'alpha');
$desc = GETPOST('np_desc', 'restricthtml');
$date_inter = dol_mktime(GETPOST('dihour', 'int'), GETPOST('dimin', 'int'), 0, GETPOST('dimonth', 'int'), GETPOST('diday', 'int'), GETPOST('diyear', 'int'));
$duration = convertTime2Seconds(GETPOST('durationhour', 'int'), GETPOST('durationmin', 'int'));
@ -1534,7 +1534,7 @@ if ($action == 'create')
// editeur wysiwyg
if (empty($conf->global->FICHINTER_EMPTY_LINE_DESC)) {
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
$doleditor = new DolEditor('np_desc', GETPOST('np_desc', 'alpha'), '', 100, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%');
$doleditor = new DolEditor('np_desc', GETPOST('np_desc', 'restricthtml'), '', 100, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_DETAILS, ROWS_2, '90%');
$doleditor->Create();
}
print '</td>';

View File

@ -30,6 +30,9 @@
-- Missing in v12 or lower
ALTER TABLE llx_payment_salary MODIFY COLUMN ref varchar(30) NULL;
ALTER TABLE llx_payment_various MODIFY COLUMN ref varchar(30) NULL;
ALTER TABLE llx_prelevement_bons ADD COLUMN type varchar(16) DEFAULT 'debit-order';
ALTER TABLE llx_prelevement_facture_demande ADD INDEX idx_prelevement_facture_demande_fk_facture (fk_facture);

View File

@ -383,6 +383,7 @@ delete from llx_commande_fournisseur_dispatch where fk_commandefourndet = 0 or f
delete from llx_menu where menu_handler = 'smartphone';
update llx_expedition set date_valid = date_creation where fk_statut = 1 and date_valid IS NULL;
update llx_expedition set date_valid = NOW() where fk_statut = 1 and date_valid IS NULL;
-- Detect bad consistency between duraction_effective of a task and sum of time of tasks
-- select pt.rowid, pt.duration_effective, SUM(ptt.task_duration) as y from llx_projet_task as pt, llx_projet_task_time as ptt where ptt.fk_task = pt.rowid group by pt.rowid, pt.duration_effective having pt.duration_effective <> y;

View File

@ -439,7 +439,7 @@ ExtrafieldParamHelpPassword=Leaving this field blank means this value will be st
ExtrafieldParamHelpselect=List of values must be lines with format key,value (where key can't be '0')<br><br> for example: <br>1,value1<br>2,value2<br>code3,value3<br>...<br><br>In order to have the list depending on another complementary attribute list:<br>1,value1|options_<i>parent_list_code</i>:parent_key<br>2,value2|options_<i>parent_list_code</i>:parent_key <br><br>In order to have the list depending on another list:<br>1,value1|<i>parent_list_code</i>:parent_key<br>2,value2|<i>parent_list_code</i>:parent_key
ExtrafieldParamHelpcheckbox=List of values must be lines with format key,value (where key can't be '0')<br><br> for example: <br>1,value1<br>2,value2<br>3,value3<br>...
ExtrafieldParamHelpradio=List of values must be lines with format key,value (where key can't be '0')<br><br> for example: <br>1,value1<br>2,value2<br>3,value3<br>...
ExtrafieldParamHelpsellist=List of values comes from a table<br>Syntax: table_name:label_field:id_field::filter<br>Example: c_typent:libelle:id::filter<br><br>- idfilter is necessarly a primary int key<br>- filter can be a simple test (eg active=1) to display only active value<br>You can also use $ID$ in filter witch is the current id of current object<br>To do a SELECT in filter use $SEL$<br>if you want to filter on extrafields use syntax extra.fieldcode=... (where field code is the code of extrafield)<br><br>In order to have the list depending on another complementary attribute list:<br>c_typent:libelle:id:options_<i>parent_list_code</i>|parent_column:filter <br><br>In order to have the list depending on another list:<br>c_typent:libelle:id:<i>parent_list_code</i>|parent_column:filter
ExtrafieldParamHelpsellist=List of values comes from a table<br>Syntax: table_name:label_field:id_field::filter<br>Example: c_typent:libelle:id::filter<br><br>- id_field is necessarly a primary int key<br>- filter can be a simple test (eg active=1) to display only active value<br>You can also use $ID$ in filter which is the current id of current object<br>To use a SELECT into the filter use the keyword $SEL$ to bypass anti-injection protection.<br>if you want to filter on extrafields use syntax extra.fieldcode=... (where field code is the code of extrafield)<br><br>In order to have the list depending on another complementary attribute list:<br>c_typent:libelle:id:options_<i>parent_list_code</i>|parent_column:filter <br><br>In order to have the list depending on another list:<br>c_typent:libelle:id:<i>parent_list_code</i>|parent_column:filter
ExtrafieldParamHelpchkbxlst=List of values comes from a table<br>Syntax: table_name:label_field:id_field::filter<br>Example: c_typent:libelle:id::filter<br><br>filter can be a simple test (eg active=1) to display only active value<br>You can also use $ID$ in filter witch is the current id of current object<br>To do a SELECT in filter use $SEL$<br>if you want to filter on extrafields use syntax extra.fieldcode=... (where field code is the code of extrafield)<br><br>In order to have the list depending on another complementary attribute list:<br>c_typent:libelle:id:options_<i>parent_list_code</i>|parent_column:filter <br><br>In order to have the list depending on another list:<br>c_typent:libelle:id:<i>parent_list_code</i>|parent_column:filter
ExtrafieldParamHelplink=Parameters must be ObjectName:Classpath<br>Syntax: ObjectName:Classpath
ExtrafieldParamHelpSeparator=Keep empty for a simple separator<br>Set this to 1 for a collapsing separator (open by default for new session, then status is kept for each user session)<br>Set this to 2 for a collapsing separator (collapsed by default for new session, then status is kept fore each user session)
@ -1221,7 +1221,8 @@ RestoreDesc=To restore a Dolibarr backup, two steps are required.
RestoreDesc2=Restore the backup file (zip file for example) of the "documents" directory to a new Dolibarr installation or into this current documents directory (<b>%s</b>).
RestoreDesc3=Restore the database structure and data from a backup dump file into the database of the new Dolibarr installation or into the database of this current installation (<b>%s</b>). Warning, once the restore is complete, you must use a login/password, that existed from the backup time/installation to connect again.<br>To restore a backup database into this current installation, you can follow this assistant.
RestoreMySQL=MySQL import
ForcedToByAModule= This rule is forced to <b>%s</b> by an activated module
ForcedToByAModule=This rule is forced to <b>%s</b> by an activated module
ValueIsForcedBySystem=This value is forced by the system. You can't change it.
PreviousDumpFiles=Existing backup files
PreviousArchiveFiles=Existing archive files
WeekStartOnDay=First day of the week

View File

@ -378,10 +378,18 @@ if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && !empty($conf->gl
in_array(GETPOST('action', 'aZ09'), array('add', 'addtimespent', 'update', 'install', 'delete', 'deleteprof', 'deletepayment')))
{
if (!GETPOSTISSET('token')) {
dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." refused by CSRFCHECK_WITH_TOKEN protection. Token not provided.");
print "Access to this page this way (POST method or page with CSRFCHECK_WITH_TOKEN on or having a sensible value for action parameter) is refused by CSRF protection in main.inc.php. Token not provided.\n";
print "If you access your server behind a proxy using url rewriting, you might check that all HTTP header is propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file or MAIN_SECURITY_CSRF_WITH_TOKEN to 0 into setup).\n";
die;
if (GETPOST('uploadform')) {
dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." refused. File size too large.");
$langs->loadLangs(array("errors", "install"));
print $langs->trans("ErrorFileSizeTooLarge").' ';
print $langs->trans("ErrorGoBackAndCorrectParameters");
die;
} else {
dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." refused by CSRFCHECK_WITH_TOKEN protection. Token not provided.");
print "Access to this page this way (POST method or page with CSRFCHECK_WITH_TOKEN on or having a sensible value for action parameter) is refused by CSRF protection in main.inc.php. Token not provided.\n";
print "If you access your server behind a proxy using url rewriting, you might check that all HTTP header is propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file or MAIN_SECURITY_CSRF_WITH_TOKEN to 0 into setup).\n";
die;
}
}
}

View File

@ -18,6 +18,7 @@
* Copyright (C) 2017 Josep Lluís Amador <joseplluis@lliuretic.cat>
* Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2019-2020 Thibault FOUCART <support@ptibogxiv.net>
* Copyright (C) 2020 Pierre Ardoin <mapiolca@me.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -2387,7 +2388,11 @@ if ($action != 'create' && $action != 'edit' && $action != 'delete')
// Documents
$objectref = dol_sanitizeFileName($object->ref);
$relativepath = $comref.'/'.$objectref.'.pdf';
$filedir = $conf->product->dir_output.'/'.$objectref;
if (!empty($conf->product->multidir_output[$object->entity])) {
$filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities
} else {
$filedir = $conf->product->dir_output.'/'.$objectref;
}
$urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
$genallowed = $usercanread;
$delallowed = $usercancreate;

View File

@ -73,48 +73,3 @@ function inventoryPrepareHead(&$inventory, $title = 'Inventory', $get = '')
array(dol_buildpath('/product/inventory/inventory.php?id='.$inventory->id.$get, 1), $langs->trans('Inventory'), 'inventory')
);
}
/**
* Define head array for tabs of inventory tools setup pages
*
* @param Inventory $inventory Object inventory
*
* @return string html of products
*/
function inventorySelectProducts(&$inventory)
{
global $conf, $db, $langs;
$except_product_id = array();
foreach ($inventory->Inventorydet as $Inventorydet)
{
$except_product_id[] = $Inventorydet->fk_product;
}
ob_start();
$form = new Form($db);
$form->select_produits(-1, 'fk_product');
$TChildWarehouses = array($inventory->fk_warehouse);
$e = new Entrepot($db);
$e->fetch($inventory->fk_warehouse);
if (method_exists($e, 'get_children_warehouses')) $e->get_children_warehouses($e->id, $TChildWarehouses);
$Tab = array();
$sql = 'SELECT rowid, label
FROM '.MAIN_DB_PREFIX.'entrepot WHERE rowid IN('.implode(', ', $TChildWarehouses).')';
if (method_exists($e, 'get_children_warehouses')) $sql .= ' ORDER BY fk_parent';
$resql = $db->query($sql);
while ($res = $db->fetch_object($resql)) {
$Tab[$res->rowid] = $res->label;
}
print '&nbsp;&nbsp;&nbsp;';
print $langs->trans('Warehouse').' : '.$form::selectarray('fk_warehouse', $Tab);
$select_html = ob_get_clean();
return $select_html;
}

View File

@ -44,6 +44,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
$place = (GETPOST('place', 'aZ09') ? GETPOST('place', 'aZ09') : 0); // $place is id of table for Bar or Restaurant or multiple sales
$action = GETPOST('action', 'aZ09');
$setterminal = GETPOST('setterminal', 'int');
$setcurrency = GETPOST('setcurrency', 'aZ09');
if ($_SESSION["takeposterminal"] == "")
{
@ -57,6 +58,11 @@ if ($setterminal > 0)
setcookie("takeposterminal", $setterminal, (time() + (86400 * 354)), '/', null, false, true); // Permanent takeposterminal var in a cookie
}
if ($setcurrency!="")
{
$_SESSION["takeposcustomercurrency"] = $setcurrency;
}
$_SESSION["urlfrom"] = '/takepos/index.php';
$langs->loadLangs(array("bills", "orders", "commercial", "cashdesk", "receiptprinter", "banks"));
@ -725,14 +731,10 @@ function CashReport(rowid)
$.colorbox({href:"../compta/cashcontrol/report.php?id="+rowid+"&contextpage=takepos", width:"60%", height:"90%", transition:"none", iframe:"true", title:"<?php echo $langs->trans("CashReport"); ?>"});
}
// Popup to select the terminal to use
function TerminalsDialog()
// TakePOS Popup
function ModalBox(ModalID)
{
var modal = document.getElementById("ModalTerminal");
var span = document.getElementsByClassName("close")[0];
span.onclick = function() {
modal.style.display = "none";
}
var modal = document.getElementById(ModalID);
modal.style.display = "block";
}
@ -767,7 +769,7 @@ $( document ).ready(function() {
//IF NO TERMINAL SELECTED
if ($_SESSION["takeposterminal"] == "")
{
print "TerminalsDialog();";
print "ModalBox('ModalTerminal');";
}
if ($conf->global->TAKEPOS_CONTROL_CASH_OPENING)
{
@ -798,7 +800,7 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
<div class="topnav">
<div class="topnav-left">
<div class="inline-block valignmiddle">
<a class="topnav-terminalhour" onclick="TerminalsDialog();">
<a class="topnav-terminalhour" onclick="ModalBox('ModalTerminal');">
<span class="fa fa-cash-register"></span>
<span class="hideonsmartphone">
<?php echo $langs->trans("Terminal"); ?>
@ -808,7 +810,13 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
else echo $_SESSION["takeposterminal"];
echo '<span class="hideonsmartphone"> - '.dol_print_date(dol_now(), "day").'</span>';
?>
</a></div>
</a>
<?php
if (!empty($conf->multicurrency->enabled)){
print '<a class="valignmiddle tdoverflowmax100 minwidth75" id="multicurrency" onclick="ModalBox(\'ModalCurrency\');" title=""><span class="fas fa-coins paddingrightonly"></span>'.$langs->trans("Currency").'</a>';
}
?>
</div>
<!-- section for customer and open sales -->
<div class="inline-block valignmiddle" id="customerandsales">
</div>
@ -841,7 +849,7 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
<div id="ModalTerminal" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close">&times;</span>
<span class="close" href="#" onclick="document.getElementById('ModalTerminal').style.display = 'none';">&times;</span>
<h3><?php print $langs->trans("TerminalSelect");?></h3>
</div>
<div class="modal-body">
@ -854,10 +862,30 @@ if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) {
?>
</div>
</div>
</div>
<!-- Modal multicurrency box -->
<div id="ModalCurrency" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="close" href="#" onclick="document.getElementById('ModalCurrency').style.display = 'none';">&times;</span>
<h3><?php print $langs->trans("SetMultiCurrencyCode");?></h3>
</div>
<div class="modal-body">
<?php
$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
$sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
$resql = $db->query($sql);
if ($resql)
{
while ($obj = $db->fetch_object($resql))
print '<button type="button" class="block" onclick="location.href=\'index.php?setcurrency='.$obj->code.'\'">'.$obj->code.'</button>';
}
?>
</div>
</div>
</div>
<div class="row1<?php if (empty($conf->global->TAKEPOS_HIDE_HEAD_BAR)) print 'withhead'; ?>">

View File

@ -1090,7 +1090,16 @@ if ($placeid > 0)
}
else $htmlforlines .= $line->qty;
$htmlforlines .= '</td>';
$htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">'.price($line->total_ttc).'</td>';
$htmlforlines .= '<td class="right classfortooltip" title="'.$moreinfo.'">';
$htmlforlines .= price($line->total_ttc);
if (!empty($conf->multicurrency->enabled) && $_SESSION["takeposcustomercurrency"]!="" && $conf->currency!=$_SESSION["takeposcustomercurrency"]) {
//Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
$multicurrency = new MultiCurrency($db);
$multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
$htmlforlines .= ' ('.price($line->total_ttc*$multicurrency->rate->rate).' '.$_SESSION["takeposcustomercurrency"].')';
}
$htmlforlines .= '</td>';
}
$htmlforlines .= '</tr>'."\n";
$htmlforlines .= $htmlsupplements[$line->id];

View File

@ -182,6 +182,16 @@ if ($conf->global->TAKEPOS_SHOW_CUSTOMER)
<th class="right"><?php if ($gift!=1) echo ''.$langs->trans("TotalTTC").'</th><td class="right">'.price($object->total_ttc, 1, '', 1, - 1, - 1, $conf->currency)."\n"; ?></td>
</tr>
<?php
if (!empty($conf->multicurrency->enabled) && $_SESSION["takeposcustomercurrency"]!="" && $conf->currency!=$_SESSION["takeposcustomercurrency"]) {
//Only show customer currency if multicurrency module is enabled, if currency selected and if this currency selected is not the same as main currency
include_once DOL_DOCUMENT_ROOT.'/multicurrency/class/multicurrency.class.php';
$multicurrency = new MultiCurrency($db);
$multicurrency->fetch(0, $_SESSION["takeposcustomercurrency"]);
echo '<tr><th class="right">';
if ($gift!=1) echo ''.$langs->trans("TotalTTC").' '.$_SESSION["takeposcustomercurrency"].'</th><td class="right">'.price($object->total_ttc*$multicurrency->rate->rate, 1, '', 1, - 1, - 1, $_SESSION["takeposcustomercurrency"])."\n";
echo '</td></tr>';
}
if ($conf->global->TAKEPOS_PRINT_PAYMENT_METHOD) {
$sql = "SELECT p.pos_change as pos_change, p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,";
$sql .= " cp.code";

View File

@ -60,10 +60,12 @@ if ($action=="send")
$model_id = $conf->global->TAKEPOS_EMAIL_TEMPLATE_INVOICE;
$arraydefaultmessage = $formmail->getEMailTemplate($db, 'facture_send', $user, $outputlangs, $model_id);
$subject = $arraydefaultmessage->topic;
ob_start(); // turn on output receipt
include 'receipt.php';
$receipt = ob_get_contents(); // get the contents of the output buffer
ob_end_clean();
$msg="<html>".$arraydefaultmessage->content."<br>".$receipt."</html>";
$sendto=$email;
$from=$mysoc->email;