diff --git a/.travis.yml b/.travis.yml index 1f4fc328a49..ee378d191dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,10 @@ addons: - php8.1-mysqli - php8.1-xml - php8.1-intl + - php8.2-pgsql + - php8.2-mysqli + - php8.2-xml + - php8.2-intl env: global: @@ -73,8 +77,8 @@ jobs: php: '8.1' env: DB=mysql - stage: PHP Dev - if: type = push AND branch = 17.0 - php: nightly + if: type = push AND branch = develop + php: '8.2' env: DB=mysql notifications: @@ -120,7 +124,7 @@ install: squizlabs/php_codesniffer ^3 fi # phpunit 9 is required for php 8 - if [ "$TRAVIS_PHP_VERSION" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then + if [ "$TRAVIS_PHP_VERSION" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = '8.2' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then composer self-update 2.4.4 composer -n require --ignore-platform-reqs phpunit/phpunit ^8 \ php-parallel-lint/php-parallel-lint ^1.2 \ @@ -260,7 +264,7 @@ before_script: # enable php-fpm - sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf - | - if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then + if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = '8.2' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then # Copy the included pool sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf fi diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 68bec8431a7..a0e741a290f 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -231,7 +231,7 @@ if ($action == 'install') { if (!$error) { @dol_delete_dir_recursive($dirins.'/'.$modulenameval); // delete the target directory $submodulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulenameval; - if (!dol_is_dir($modulenamedir)) { + if (!dol_is_dir($submodulenamedir)) { $submodulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulenameval; } dol_syslog("We copy now directory ".$submodulenamedir." into target dir ".$dirins.'/'.$modulenameval); @@ -476,7 +476,7 @@ foreach ($modulesdir as $dir) { dol_syslog("Module ".get_class($objMod)." not qualified"); } } else { - print "Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)
"; + print "admin/modules.php Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)
"; } } catch (Exception $e) { dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR); diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php index 7a7e49a3129..9c8473f5f7f 100644 --- a/htdocs/admin/stock.php +++ b/htdocs/admin/stock.php @@ -181,16 +181,25 @@ $formproduct = new FormProduct($db); $disabled = ''; if (isModEnabled('productbatch')) { + // If module lot/serial enabled, we force the inc/dec mode to STOCK_CALCULATE_ON_SHIPMENT_CLOSE and STOCK_CALCULATE_ON_RECEPTION_CLOSE $langs->load("productbatch"); $disabled = ' disabled'; - print info_admin($langs->trans("WhenProductBatchModuleOnOptionAreForced")); + + // STOCK_CALCULATE_ON_SHIPMENT_CLOSE + $descmode = $langs->trans('DeStockOnShipmentOnClosing'); + if (!isModEnabled('reception')) { + // STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER + $incmode = $langs->trans('ReStockOnDispatchOrder'); + } else { + // STOCK_CALCULATE_ON_RECEPTION_CLOSE + $incmode = $langs->trans('StockOnReceptionOnClosing'); + } + print info_admin($langs->trans("WhenProductBatchModuleOnOptionAreForced", $descmode, $incmode)); } -//if (!empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) || !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) -//{ + print info_admin($langs->trans("IfYouUsePointOfSaleCheckModule")); print '
'; -//} print '
'; @@ -221,7 +230,7 @@ if (isModEnabled('facture')) { print $form->selectarray("STOCK_CALCULATE_ON_BILL", $arrval, $conf->global->STOCK_CALCULATE_ON_BILL); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module30Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module30Name")).''; } print "\n\n"; $found++; @@ -242,7 +251,7 @@ if (isModEnabled('commande')) { print $form->selectarray("STOCK_CALCULATE_ON_VALIDATE_ORDER", $arrval, $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module25Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module25Name")).''; } print "\n\n"; $found++; @@ -261,7 +270,7 @@ if (isModEnabled("expedition")) { print $form->selectarray("STOCK_CALCULATE_ON_SHIPMENT", $arrval, $conf->global->STOCK_CALCULATE_ON_SHIPMENT); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")).''; } print "\n\n"; $found++; @@ -278,7 +287,7 @@ if (isModEnabled("expedition")) { print $form->selectarray("STOCK_CALCULATE_ON_SHIPMENT_CLOSE", $arrval, $conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")).''; } print "\n\n"; $found++; @@ -313,7 +322,7 @@ if ((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMO print $form->selectarray("STOCK_CALCULATE_ON_SUPPLIER_BILL", $arrval, $conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).''; } print "\n\n"; $found++; @@ -335,7 +344,7 @@ if ((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMO print $form->selectarray("STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", $arrval, $conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).''; } print "\n\n"; $found++; @@ -380,7 +389,7 @@ if (isModEnabled("reception")) { print $form->selectarray("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", $arrval, $conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER); } } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + print ''.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).''; } print "\n\n"; $found++; diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 7a8fb3114fc..a6177876bf7 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -746,12 +746,22 @@ if (empty($reshook)) { $fk_unit = GETPOST('unit', 'alpha'); + // update price_ht with discount + // TODO Use object->updateline instead objedtline->update + + $price_ht = price2num(GETPOST('elprice'), 'MU'); + $remise_percent = price2num(GETPOST('elremise_percent'), 2); + if ($remise_percent > 0) { + $remise = round(($price_ht * $remise_percent / 100), 2); + $price_ht = ($price_ht - $remise); + } + $objectline->fk_product = GETPOST('idprod', 'int'); $objectline->description = GETPOST('product_desc', 'restricthtml'); - $objectline->price_ht = price2num(GETPOST('elprice'), 'MU'); + $objectline->price_ht = $price_ht; $objectline->subprice = price2num(GETPOST('elprice'), 'MU'); $objectline->qty = price2num(GETPOST('elqty'), 'MS'); - $objectline->remise_percent = price2num(GETPOST('elremise_percent'), 2); + $objectline->remise_percent = $remise_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; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index e53cc85c21f..d411321386b 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -6461,6 +6461,14 @@ abstract class CommonObject dol_syslog('Error bad setup of extrafield', LOG_WARNING); } break; + case 'checkbox': + case 'chkbxlst': + if (is_array($this->array_options[$key])) { + $new_array_options[$key] = implode(',', $this->array_options[$key]); + } else { + $new_array_options[$key] = $this->array_options[$key]; + } + break; } } @@ -6814,6 +6822,14 @@ abstract class CommonObject } break; */ + case 'checkbox': + case 'chkbxlst': + if (is_array($this->array_options[$key])) { + $new_array_options[$key] = implode(',', $this->array_options[$key]); + } else { + $new_array_options[$key] = $this->array_options[$key]; + } + break; } $this->db->begin(); @@ -8256,7 +8272,7 @@ abstract class CommonObject // Test on 'enabled' ('enabled' is different than 'list' = 'visibility') $enabled = 1; if ($enabled && isset($extrafields->attributes[$this->table_element]['enabled'][$key])) { - $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '1'); + $enabled = dol_eval($extrafields->attributes[$this->table_element]['enabled'][$key], 1, 1, '2'); } if (empty($enabled)) { continue; @@ -8264,12 +8280,12 @@ abstract class CommonObject $visibility = 1; if ($visibility && isset($extrafields->attributes[$this->table_element]['list'][$key])) { - $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '1'); + $visibility = dol_eval($extrafields->attributes[$this->table_element]['list'][$key], 1, 1, '2'); } $perms = 1; if ($perms && isset($extrafields->attributes[$this->table_element]['perms'][$key])) { - $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '1'); + $perms = dol_eval($extrafields->attributes[$this->table_element]['perms'][$key], 1, 1, '2'); } if (($mode == 'create') && abs($visibility) != 1 && abs($visibility) != 3) { @@ -9982,7 +9998,7 @@ abstract class CommonObject $this->db->begin(); $statusfield = 'status'; - if ($this->element == 'don' || $this->element == 'donation') { + if (in_array($this->element, array('don', 'donation', 'shipping'))) { $statusfield = 'fk_statut'; } diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 589d28453fc..b3991ecfcf2 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -109,6 +109,24 @@ class Conf public $tzuserinputkey = 'tzserver'; // Use 'tzuserrel' to always store date in GMT and show date in time zone of user. + // TODO Remove this part. + public $fournisseur; + public $product; + public $service; + public $contrat; + public $actions; + public $agenda; + public $commande; + public $propal; + public $facture; + public $user; + public $adherent; + public $bank; + public $notification; + public $expensereport; + public $productbatch; + + /** * Constructor @@ -165,7 +183,6 @@ class Conf $this->commande = new stdClass(); $this->propal = new stdClass(); $this->facture = new stdClass(); - $this->contrat = new stdClass(); $this->user = new stdClass(); $this->adherent = new stdClass(); $this->bank = new stdClass(); @@ -635,18 +652,19 @@ class Conf unset($this->global->PROJECT_USE_SEARCH_TO_SELECT); } - if (!empty($this->productbatch->enabled)) { + if (isModEnabled('productbatch')) { + // If module lot/serial enabled, we force the inc/dec mode to STOCK_CALCULATE_ON_SHIPMENT_CLOSE and STOCK_CALCULATE_ON_RECEPTION_CLOSE $this->global->STOCK_CALCULATE_ON_BILL = 0; $this->global->STOCK_CALCULATE_ON_VALIDATE_ORDER = 0; - if (empty($this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) $this->global->STOCK_CALCULATE_ON_SHIPMENT = 1; if (empty($this->global->STOCK_CALCULATE_ON_SHIPMENT)) $this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE = 1; + if (empty($this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) $this->global->STOCK_CALCULATE_ON_SHIPMENT = 1; $this->global->STOCK_CALCULATE_ON_SUPPLIER_BILL = 0; $this->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER = 0; - if (empty($this->reception->enabled)) { + if (!isModEnabled('reception')) { $this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER = 1; } else { - if (empty($this->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) $this->global->STOCK_CALCULATE_ON_RECEPTION = 1; if (empty($this->global->STOCK_CALCULATE_ON_RECEPTION)) $this->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE = 1; + if (empty($this->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) $this->global->STOCK_CALCULATE_ON_RECEPTION = 1; } } diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 2ae0529b14a..5c44e140be9 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -961,9 +961,9 @@ class ExtraFields $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; - $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1'); + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2'); $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; - $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1'); + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2'); $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key]; $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; $hidden = (empty($list) ? 1 : 0); // If empty, 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) @@ -1597,9 +1597,9 @@ class ExtraFields $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key]; $required = $this->attributes[$extrafieldsobjectkey]['required'][$key]; $param = $this->attributes[$extrafieldsobjectkey]['param'][$key]; - $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1'); + $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '2'); $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key]; - $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1'); + $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '2'); $help = $this->attributes[$extrafieldsobjectkey]['help'][$key]; $hidden = (empty($list) ? 1 : 0); // If $list empty, 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) @@ -2097,17 +2097,17 @@ class ExtraFields $enabled = 1; if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not - $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '1'); + $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '2'); } $visibility = 1; if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility - $visibility = intval(dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '1')); + $visibility = intval(dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '2')); } $perms = 1; if (isset($this->attributes[$object->table_element]['perms'][$key])) { - $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '1'); + $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '2'); } if (empty($enabled) || ( diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index eea1047bc51..5484fea6663 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -5087,21 +5087,21 @@ class Form * print '});'."\n"; * print ''."\n"; * - * @param string $page Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated) - * @param string $title Title - * @param string $question Question - * @param string $action Action - * @param array|string $formquestion An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>'autofocus' or 'style=...')) - * 'type' can be 'text', 'password', 'checkbox', 'radio', 'date', 'datetime', 'select', 'multiselect', 'morecss', - * 'other', 'onecolumn' or 'hidden'... - * @param int|string $selectedchoice '' or 'no', or 'yes' or '1', 1, '0' or 0 - * @param int|string $useajax 0=No, 1=Yes use Ajax to show the popup, 2=Yes and also submit page with &confirm=no if choice is No, 'xxx'=Yes and preoutput confirm box with div id=dialog-confirm-xxx - * @param int|string $height Force height of box (0 = auto) - * @param int $width Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones. - * @param int $disableformtag 1=Disable form tag. Can be used if we are already inside a section. - * @param string $labelbuttonyes Label for Yes - * @param string $labelbuttonno Label for No - * @return string HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form + * @param string $page Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated) + * @param string $title Title + * @param string $question Question + * @param string $action Action + * @param array|string $formquestion An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>'autofocus' or 'style=...')) + * 'type' can be 'text', 'password', 'checkbox', 'radio', 'date', 'datetime', 'select', 'multiselect', 'morecss', + * 'other', 'onecolumn' or 'hidden'... + * @param int|string $selectedchoice '' or 'no', or 'yes' or '1', 1, '0' or 0 + * @param int|string $useajax 0=No, 1=Yes use Ajax to show the popup, 2=Yes and also submit page with &confirm=no if choice is No, 'xxx'=Yes and preoutput confirm box with div id=dialog-confirm-xxx + * @param int|string $height Force height of box (0 = auto) + * @param int $width Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones. + * @param int $disableformtag 1=Disable form tag. Can be used if we are already inside a section. + * @param string $labelbuttonyes Label for Yes + * @param string $labelbuttonno Label for No + * @return string HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form */ public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No') { diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php index 28b4e21fdd4..71a340869b1 100644 --- a/htdocs/core/class/html.formprojet.class.php +++ b/htdocs/core/class/html.formprojet.class.php @@ -380,7 +380,7 @@ class FormProjets include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus); $out .= $comboenhancement; - $morecss .= ' minwidth200 maxwidth500'; + $morecss .= ' minwidth150'; } if (empty($option_only)) { diff --git a/htdocs/core/modules/modExpedition.class.php b/htdocs/core/modules/modExpedition.class.php index 2ff117404ee..590e5b6b488 100644 --- a/htdocs/core/modules/modExpedition.class.php +++ b/htdocs/core/modules/modExpedition.class.php @@ -360,9 +360,11 @@ class modExpedition extends DolibarrModules $sql = array( "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[0][2])."' AND type = 'shipping' AND entity = ".((int) $conf->entity), - "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."','shipping',".((int) $conf->entity).")", + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."', 'shipping', ".((int) $conf->entity).")", "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[3][2])."' AND type = 'delivery' AND entity = ".((int) $conf->entity), - "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[3][2])."','delivery',".((int) $conf->entity).")", + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[3][2])."', 'delivery', ".((int) $conf->entity).")", + //"DELETE FROM ".MAIN_DB_PREFIX."const WHERE name IN ('STOCK_CALCULATE_ON_BILL', 'STOCK_CALCULATE_ON_VALIDATE_ORDER', 'STOCK_CALCULATE_ON_SHIPMENT', 'STOCK_CALCULATE_ON_SHIPMENT_CLOSE') AND entity = ".((int) $conf->entity), + //"INSERT INTO ".MAIN_DB_PREFIX."const (name, value, entity) VALUES ('STOCK_CALCULATE_ON_SHIPMENT_CLOSE', 1, ".((int) $conf->entity).")" ); return $this->_init($sql, $options); diff --git a/htdocs/core/modules/modMrp.class.php b/htdocs/core/modules/modMrp.class.php index 58e7791845a..593a5611de0 100644 --- a/htdocs/core/modules/modMrp.class.php +++ b/htdocs/core/modules/modMrp.class.php @@ -119,7 +119,7 @@ class modMrp extends DolibarrModules $this->hidden = false; // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) $this->depends = array('modBom'); - $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->requiredby = array('modWorkstation'); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) $this->langfiles = array("mrp"); $this->phpmin = array(7, 0); // Minimum version of PHP required by module diff --git a/htdocs/core/modules/modReception.class.php b/htdocs/core/modules/modReception.class.php index 6e7cba2b053..d6341e6279d 100644 --- a/htdocs/core/modules/modReception.class.php +++ b/htdocs/core/modules/modReception.class.php @@ -282,8 +282,10 @@ class modReception extends DolibarrModules $sql = array(); $sql = array( - "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[0][2])."' AND type = 'reception' AND entity = ".((int) $conf->entity), - "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."','reception',".((int) $conf->entity).")", + "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[0][2])."' AND type = 'reception' AND entity = ".((int) $conf->entity), + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."','reception',".((int) $conf->entity).")", + //"DELETE FROM ".MAIN_DB_PREFIX."const WHERE name IN ('STOCK_CALCULATE_ON_SUPPLIER_BILL', 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER', 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER', 'STOCK_CALCULATE_ON_RECEPTION', 'STOCK_CALCULATE_ON_RECEPTION_CLOSE') AND entity = ".((int) $conf->entity), + //"INSERT INTO ".MAIN_DB_PREFIX."const (name, value, entity) VALUES ('STOCK_CALCULATE_ON_RECEPTION_CLOSE', 1, ".((int) $conf->entity).")" ); return $this->_init($sql, $options); diff --git a/htdocs/core/modules/modStockTransfer.class.php b/htdocs/core/modules/modStockTransfer.class.php index 279add98bad..34de040fdb8 100644 --- a/htdocs/core/modules/modStockTransfer.class.php +++ b/htdocs/core/modules/modStockTransfer.class.php @@ -61,7 +61,7 @@ class modStockTransfer extends DolibarrModules // Module description, used if translation string 'ModuleStockTransferDesc' not found (StockTransfer is name of module). $this->description = $langs->trans("ModuleStockTransferDesc"); // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = "StockTransfer description (Long)"; + $this->descriptionlong = "Advanced management of stock transfer orders with generation of stock transfer sheets"; // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' $this->version = 'experimental'; // Url to the file with your last numberversion of this module diff --git a/htdocs/core/modules/modWorkstation.class.php b/htdocs/core/modules/modWorkstation.class.php index a8be0f23226..6bba7b1807a 100644 --- a/htdocs/core/modules/modWorkstation.class.php +++ b/htdocs/core/modules/modWorkstation.class.php @@ -120,7 +120,7 @@ class modWorkstation extends DolibarrModules // A condition to hide module $this->hidden = false; // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) - $this->depends = array(); + $this->depends = array('modMrp'); $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) $this->langfiles = array("mrp"); diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index 38b99fc5736..94eb8ff0a86 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -74,15 +74,15 @@ if (empty($reshook) && isset($extrafields->attributes[$object->table_element]['l $enabled = 1; if ($enabled && isset($extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra])) { - $enabled = dol_eval($extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra], 1); + $enabled = dol_eval($extrafields->attributes[$object->table_element]['enabled'][$tmpkeyextra], 1, 1, '2'); } if ($enabled && isset($extrafields->attributes[$object->table_element]['list'][$tmpkeyextra])) { - $enabled = dol_eval($extrafields->attributes[$object->table_element]['list'][$tmpkeyextra], 1); + $enabled = dol_eval($extrafields->attributes[$object->table_element]['list'][$tmpkeyextra], 1, 1, '2'); } $perms = 1; if ($perms && isset($extrafields->attributes[$object->table_element]['perms'][$tmpkeyextra])) { - $perms = dol_eval($extrafields->attributes[$object->table_element]['perms'][$tmpkeyextra], 1); + $perms = dol_eval($extrafields->attributes[$object->table_element]['perms'][$tmpkeyextra], 1, 1, '2'); } //print $tmpkeyextra.'-'.$enabled.'-'.$perms.'
'."\n"; diff --git a/htdocs/core/tpl/objectline_title.tpl.php b/htdocs/core/tpl/objectline_title.tpl.php index cbe5d0dee10..f7afa80bf55 100644 --- a/htdocs/core/tpl/objectline_title.tpl.php +++ b/htdocs/core/tpl/objectline_title.tpl.php @@ -134,14 +134,14 @@ if (isset($this->situation_cycle_ref) && $this->situation_cycle_ref) { if ($usemargins && isModEnabled('margin') && empty($user->socid)) { if (!empty($user->rights->margins->creer)) { if ($conf->global->MARGIN_TYPE == "1") { - print ''.$langs->trans('BuyingPrice').''; + print ''.$langs->trans('BuyingPrice').''; } else { - print ''.$langs->trans('CostPrice').''; + print ''.$langs->trans('CostPrice').''; } } if (!empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous) { - print ''.$langs->trans('MarginRate'); + print ''.$langs->trans('MarginRate'); if ($user->hasRight("propal", "creer")) { print 'id.'">'.img_edit($langs->trans("UpdateForAllLines"), 0, 'class="clickmarginforalllines opacitymedium paddingleft cursorpointer"').''; if (GETPOST('mode', 'aZ09') == 'marginforalllines') { @@ -154,7 +154,7 @@ if ($usemargins && isModEnabled('margin') && empty($user->socid)) { print ''; } if (!empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous) { - print ''.$langs->trans('MarkRate').''; + print ''.$langs->trans('MarkRate').''; } } diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index b0e283fc17a..f7d8ea37649 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -865,7 +865,7 @@ class EmailCollector extends CommonObject /** * overwitePropertiesOfObject * - * @param object $object Current object + * @param object $object Current object we will set ->properties * @param string $actionparam Action parameters * @param string $messagetext Body * @param string $subject Subject @@ -896,8 +896,13 @@ class EmailCollector extends CommonObject // Overwrite values with values extracted from source email // $this->actionparam = 'opportunity_status=123;abc=EXTRACT:BODY:....' $arrayvaluetouse = dolExplodeIntoArray($actionparam, '(\n\r|\r|\n|;)', '='); + + $tmp = array(); + + // Loop on each property set into actionparam foreach ($arrayvaluetouse as $propertytooverwrite => $valueforproperty) { - $tmpclass = ''; $tmpproperty = ''; + $tmpclass = ''; + $tmpproperty = ''; $tmparray = explode('.', $propertytooverwrite); if (count($tmparray) == 2) { $tmpclass = $tmparray[0]; @@ -952,23 +957,39 @@ class EmailCollector extends CommonObject if (preg_match('/^options_/', $tmpproperty)) { $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted); } else { - $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted); + if (property_exists($object, $tmpproperty)) { + $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted); + } else { + $tmp[$tmpproperty] = $this->decodeSMTPSubject($valueextracted); + } } } else { // extract from BODY if (preg_match('/^options_/', $tmpproperty)) { $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $this->decodeSMTPSubject($valueextracted); } else { - $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted); + if (property_exists($object, $tmpproperty)) { + $object->$tmpproperty = $this->decodeSMTPSubject($valueextracted); + } else { + $tmp[$tmpproperty] = $this->decodeSMTPSubject($valueextracted); + } } } if (preg_match('/^options_/', $tmpproperty)) { $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->array_options[preg_replace('/^options_/', '', $tmpproperty)], 128)); } else { - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->$tmpproperty, 128)); + if (property_exists($object, $tmpproperty)) { + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->$tmpproperty, 128)); + } else { + $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($tmp[$tmpproperty], 128)); + } } } else { // Regex not found - $object->$tmpproperty = null; + if (property_exists($object, $tmpproperty)) { + $object->$tmpproperty = null; + } else { + $tmp[$tmpproperty] = null; + } $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> not found, so property '.dol_escape_htmltag($tmpproperty).' is set to null.'; } @@ -983,7 +1004,11 @@ class EmailCollector extends CommonObject if (preg_match('/^options_/', $tmpproperty)) { $valuecurrent = $object->array_options[preg_replace('/^options_/', '', $tmpproperty)]; } else { - $valuecurrent = $object->$tmpproperty; + if (property_exists($object, $tmpproperty)) { + $valuecurrent = $object->$tmpproperty; + } else { + $valuecurrent = $tmp[$tmpproperty]; + } } if ($regforregex[1] == 'SET' || empty($valuecurrent)) { @@ -993,24 +1018,38 @@ class EmailCollector extends CommonObject $matcharray = array(); preg_match_all('/__([a-z0-9]+(?:_[a-z0-9]+)?)__/i', $valuetouse, $matcharray); //var_dump($tmpproperty.' - '.$object->$tmpproperty.' - '.$valuetouse); var_dump($matcharray); - if (is_array($matcharray[1])) { // $matcharray[1] is array with list of substitution key found without the __ + if (is_array($matcharray[1])) { // $matcharray[1] is an array with the list of substitution key found without the __X__ syntax into the SET entry foreach ($matcharray[1] as $keytoreplace) { - if ($keytoreplace && isset($object->$keytoreplace)) { - $substitutionarray['__'.$keytoreplace.'__'] = $object->$keytoreplace; + if ($keytoreplace) { + if (preg_match('/^options_/', $keytoreplace)) { + $substitutionarray['__'.$keytoreplace.'__'] = $object->array_options[preg_replace('/^options_/', '', $keytoreplace)]; + } else { + if (property_exists($object, $keytoreplace)) { + $substitutionarray['__'.$keytoreplace.'__'] = $object->$keytoreplace; + } else { + $substitutionarray['__'.$keytoreplace.'__'] = $tmp[$keytoreplace]; + } + } } } } //var_dump($substitutionarray); - dol_syslog(var_export($substitutionarray, true)); + dol_syslog('substitutionarray='.var_export($substitutionarray, true)); //var_dump($substitutionarray); $valuetouse = make_substitutions($valuetouse, $substitutionarray); if (preg_match('/^options_/', $tmpproperty)) { $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $valuetouse; - } else { - $object->$tmpproperty = $valuetouse; - } - $operationslog .= '
Set value '.dol_escape_htmltag($valuetouse).' into variable '.dol_escape_htmltag($tmpproperty); + $operationslog .= '
Set value '.dol_escape_htmltag($valuetouse).' into object->array_options['.dol_escape_htmltag(preg_replace('/^options_/', '', $tmpproperty)).']'; + } else { + if (property_exists($object, $tmpproperty)) { + $object->$tmpproperty = $valuetouse; + } else { + $tmp[$tmpproperty] = $valuetouse; + } + + $operationslog .= '
Set value '.dol_escape_htmltag($valuetouse).' into object->'.dol_escape_htmltag($tmpproperty); + } } } else { $errorforthisaction++; @@ -1041,7 +1080,7 @@ class EmailCollector extends CommonObject require_once DOL_DOCUMENT_ROOT.'/includes/webklex/php-imap/vendor/autoload.php'; } - dol_syslog("EmailCollector::doCollectOneCollector start for id=".$this->id." - ".$this->ref, LOG_DEBUG); + dol_syslog("EmailCollector::doCollectOneCollector start for id=".$this->id." - ".$this->ref, LOG_INFO); $langs->loadLangs(array("project", "companies", "mails", "errors", "ticket", "agenda", "commercial")); @@ -1470,6 +1509,9 @@ class EmailCollector extends CommonObject try { //var_dump($Query->count()); + if ($mode > 0) { + $Query->leaveUnread(); + } $arrayofemail = $Query->limit($this->maxemailpercollect)->setFetchOrder("asc")->get(); //var_dump($arrayofemail); } catch (Exception $e) { @@ -2016,6 +2058,7 @@ class EmailCollector extends CommonObject $result = $contactstatic->fetch(0, null, '', $from); if ($result > 0) { + dol_syslog("We found a contact with the email ".$from); $contactid = $contactstatic->id; $contactfoundby = 'email of contact ('.$from.')'; if (empty($thirdpartyid) && $contactstatic->socid > 0) { @@ -2031,12 +2074,44 @@ class EmailCollector extends CommonObject if (empty($thirdpartyid)) { // Try to find thirdparty using email $result = $thirdpartystatic->fetch(0, '', '', '', '', '', '', '', '', '', $from); if ($result > 0) { + dol_syslog("We found a thirdparty with the email ".$from); + $thirdpartyid = $thirdpartystatic->id;; $thirdpartyfoundby = 'email ('.$from.')'; } } - // Do operations - if ($mode < 2) { + /* + if ($replyto) { + if (empty($contactid)) { // Try to find contact using email + $result = $contactstatic->fetch(0, null, '', $replyto); + + if ($result > 0) { + dol_syslog("We found a contact with the email ".$replyto); + $contactid = $contactstatic->id; + $contactfoundby = 'email of contact ('.$replyto.')'; + if (empty($thirdpartyid) && $contactstatic->socid > 0) { + $result = $thirdpartystatic->fetch($contactstatic->socid); + if ($result > 0) { + $thirdpartyid = $thirdpartystatic->id; + $thirdpartyfoundby = 'email of contact ('.$replyto.')'; + } + } + } + } + + if (empty($thirdpartyid)) { // Try to find thirdparty using email + $result = $thirdpartystatic->fetch(0, '', '', '', '', '', '', '', '', '', $replyto); + if ($result > 0) { + dol_syslog("We found a thirdparty with the email ".$replyto); + $thirdpartyid = $thirdpartystatic->id;; + $thirdpartyfoundby = 'email ('.$replyto.')'; + } + } + } + */ + + // Do operations (extract variables and creating data) + if ($mode < 2) { // 0=Mode production, 1=Mode test (read IMAP and try SQL update then rollback), 2=Mode test with no SQL updates foreach ($this->actions as $operation) { $errorforthisaction = 0; @@ -2047,6 +2122,8 @@ class EmailCollector extends CommonObject continue; } + $operationslog .= '
* Process operation '.$operation['type']; + // Make Operation dol_syslog("Execute action ".$operation['type']." actionparam=".$operation['actionparam'].' thirdpartystatic->id='.$thirdpartystatic->id.' contactstatic->id='.$contactstatic->id.' projectstatic->id='.$projectstatic->id); dol_syslog("Execute action fk_element_id=".$fk_element_id." fk_element_type=".$fk_element_type); // If a Dolibarr tracker id is found, we should now the id of object @@ -2084,6 +2161,8 @@ class EmailCollector extends CommonObject $emailtouseforthirdparty = ''; $namealiastouseforthirdparty = ''; + $operationslog .= '
Loop on each property to set into actionparam'; + // $actionparam = 'param=SET:aaa' or 'param=EXTRACT:BODY:....' $arrayvaluetouse = dolExplodeIntoArray($actionparam, '(\n\r|\r|\n|;)', '='); foreach ($arrayvaluetouse as $propertytooverwrite => $valueforproperty) { @@ -2115,21 +2194,21 @@ class EmailCollector extends CommonObject if ($propertytooverwrite == 'id') { $idtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty); } elseif ($propertytooverwrite == 'email') { $emailtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found emailtouseforthirdparty='.dol_escape_htmltag($emailtouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found emailtouseforthirdparty='.dol_escape_htmltag($emailtouseforthirdparty); } elseif ($propertytooverwrite == 'name') { $nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); } elseif ($propertytooverwrite == 'name_alias') { - $nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; + $namealiastouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); } else { - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> We discard this, not used to search existing thirdparty'; + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> We discard this, not used to search existing thirdparty'; } } else { // Regex not found @@ -2138,7 +2217,7 @@ class EmailCollector extends CommonObject $emailtouseforthirdparty = null; $namealiastouseforthirdparty = null; - $operationslog .= '
Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found'; + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found'; } //var_dump($object->$tmpproperty);exit; } else { @@ -2154,19 +2233,19 @@ class EmailCollector extends CommonObject if ($propertytooverwrite == 'id') { $idtouseforthirdparty = $reg[2]; - $operationslog .= '
We set property idtouseforthrdparty='.dol_escape_htmltag($idtouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.'We set property idtouseforthrdparty='.dol_escape_htmltag($idtouseforthirdparty); } elseif ($propertytooverwrite == 'email') { $emailtouseforthirdparty = $reg[2]; - $operationslog .= '
We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.'We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty); } elseif ($propertytooverwrite == 'name') { $nametouseforthirdparty = $reg[2]; - $operationslog .= '
We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.'We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty); } elseif ($propertytooverwrite == 'name_alias') { $namealiastouseforthirdparty = $reg[2]; - $operationslog .= '
We set property namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); + $operationslog .= '
propertytooverwrite='.$propertytooverwrite.'We set property namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty); } } else { $errorforactions++; @@ -2177,6 +2256,25 @@ class EmailCollector extends CommonObject } if (!$errorforactions && ($idtouseforthirdparty || $emailtouseforthirdparty || $nametouseforthirdparty || $namealiastouseforthirdparty)) { + // We make another search on thirdparty + $operationslog .= '
We have this data to search thirdparty: '.$idtouseforthirdparty.' '.$emailtouseforthirdparty.' '.$nametouseforthirdparty.' '.$namealiastouseforthirdparty; + + $tmpobject = new stdClass(); + $tmpobject->element == 'generic'; + $tmpobject->id = $idtouseforthirdparty; + $tmpobject->name = $nametouseforthirdparty; + $tmpobject->name_alias = $namealiastouseforthirdparty; + $tmpobject->email = $emailtouseforthirdparty; + + $this->overwritePropertiesOfObject($tmpobject, $operation['actionparam'], $messagetext, $subject, $header, $operationslog); + + $idtouseforthirdparty = $tmpobject->id; + $nametouseforthirdparty = $tmpobject->name; + $namealiastouseforthirdparty = $tmpobject->name_alias; + $emailtouseforthirdparty = $tmpobject->email; + + $operationslog .= '
We try to search existing thirdparty with '.$idtouseforthirdparty.' '.$emailtouseforthirdparty.' '.$nametouseforthirdparty.' '.$namealiastouseforthirdparty; + $result = $thirdpartystatic->fetch($idtouseforthirdparty, $nametouseforthirdparty, '', '', '', '', '', '', '', '', $emailtouseforthirdparty, $namealiastouseforthirdparty); if ($result < 0) { $errorforactions++; @@ -2195,6 +2293,7 @@ class EmailCollector extends CommonObject dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." name_alias=".$namealiastouseforthirdparty." was not found. We try to create it."); // Create thirdparty + $thirdpartystatic = new Societe($db); $thirdpartystatic->name = $nametouseforthirdparty; if (!empty($namealiastouseforthirdparty)) { if ($namealiastouseforthirdparty != $nametouseforthirdparty) { @@ -2230,6 +2329,8 @@ class EmailCollector extends CommonObject } } else { dol_syslog("One and only one existing third party has been found"); + + $operationslog .= '
Thirdparty already exists with id = '.dol_escape_htmltag($thirdpartystatic->id); } } } @@ -2726,6 +2827,8 @@ class EmailCollector extends CommonObject } } } else { + dol_syslog("Project already exists for msgid = ".dol_escape_htmltag($msgid).", so we do not recreate it."); + $operationslog .= '
Project already exists for msgid ='.dol_escape_htmltag($msgid); } } elseif ($operation['type'] == 'ticket') { @@ -2995,9 +3098,9 @@ class EmailCollector extends CommonObject // Error for email or not ? if (!$errorforactions) { - if ($targetdir && empty($mode)) { + if (!empty($targetdir) && empty($mode)) { if (empty($conf->global->MAIN_IMAP_USE_PHPIMAP)) { - dol_syslog("EmailCollector::doCollectOneCollector move message ".$imapemail." to ".$connectstringtarget, LOG_DEBUG); + dol_syslog("EmailCollector::doCollectOneCollector move message ".((string) $imapemail)." to ".$connectstringtarget, LOG_DEBUG); $res = imap_mail_move($connection, $imapemail, $targetdir, 0); if ($res == false) { $errorforemail++; @@ -3006,7 +3109,9 @@ class EmailCollector extends CommonObject dol_syslog(imap_last_error()); } } else { - // TODO Move mail using PHP-IMAP + // Move mail using PHP-IMAP + dol_syslog("EmailCollector::doCollectOneCollector move message ".($imapemail->getHeader()->get('subject'))." to ".$targetdir, LOG_DEBUG); + $imapemail->move($targetdir); } } else { if (empty($conf->global->MAIN_IMAP_USE_PHPIMAP)) { @@ -3059,7 +3164,8 @@ class EmailCollector extends CommonObject if (!empty($conf->global->MAIN_IMAP_USE_PHPIMAP)) { $client->disconnect(); } else { - if (empty($mode)) { + if (empty($mode) && empty($error)) { + dol_syslog("Expunge", LOG_DEBUG); imap_expunge($connection); // To validate any move } imap_close($connection); @@ -3088,7 +3194,7 @@ class EmailCollector extends CommonObject $this->update($user); } - dol_syslog("EmailCollector::doCollectOneCollector end", LOG_DEBUG); + dol_syslog("EmailCollector::doCollectOneCollector end", LOG_INFO); return $error ? -1 : 1; } diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index dcc50eff7dc..f2947e9b09f 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -157,10 +157,21 @@ if (empty($reshook)) { $upload_dir = $conf->expedition->dir_output.'/sending'; include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; + // Back to draft + if ($action == 'setdraft' && $user->rights->expedition->creer) { + $object->fetch($id); + $result = $object->setDraft($user, 0); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + } // Reopen if ($action == 'reopen' && $user->rights->expedition->creer) { $object->fetch($id); $result = $object->reOpen(); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } } // Set incoterm @@ -349,6 +360,7 @@ if (empty($reshook)) { if ($totalqty > 0 && !$error) { // There is at least one thing to ship and no error for ($i = 0; $i < $num; $i++) { $qty = "qtyl".$i; + if (!isset($batch_line[$i])) { // not batch mode if (isset($stockLine[$i])) { @@ -400,7 +412,7 @@ if (empty($reshook)) { } if (!$error) { - $ret = $object->create($user); // This create shipment (like Odoo picking) and lines of shipments. Stock movement will be done when validating shipment. + $ret = $object->create($user); // This create shipment (like Odoo picking) and lines of shipments. Stock movement will be done when validating or closing shipment. if ($ret <= 0) { setEventMessages($object->error, $object->errors, 'errors'); $error++; @@ -1735,6 +1747,11 @@ if ($action == 'create') { } $text = $langs->trans("ConfirmValidateSending", $numref); + if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) { + $text .= '
'.$langs->trans("StockMovementWillBeRecorded").'.'; + } elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) { + $text .= '
'.$langs->trans("StockMovementNotYetRecorded").'.'; + } if (isModEnabled('notification')) { require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; @@ -1743,7 +1760,7 @@ if ($action == 'create') { $text .= $notify->confirmMessage('SHIPPING_VALIDATE', $object->socid, $object); } - $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1); + $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1, 250); } // Confirm cancelation if ($action == 'cancel') { @@ -2268,6 +2285,8 @@ if ($action == 'create') { // Qty in other shipments (with shipment and warehouse used) if ($origin && $origin_id > 0) { print ''; + $htmltooltip = ''; + $qtyalreadysent = 0; foreach ($alreadysent as $key => $val) { if ($lines[$i]->fk_origin_line == $key) { $j = 0; @@ -2278,20 +2297,23 @@ if ($action == 'create') { $j++; if ($j > 1) { - print '
'; + $htmltooltip .= '
'; } $shipment_static->fetch($shipmentline_var['shipment_id']); - print $shipment_static->getNomUrl(1); - print ' - '.$shipmentline_var['qty_shipped']; - $htmltext = $langs->trans("DateValidation").' : '.(empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour')); - if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) { + $htmltooltip .= $shipment_static->getNomUrl(1, '', 0, 0, 1); + $htmltooltip .= ' - '.$shipmentline_var['qty_shipped']; + $htmltooltip .= ' - '.$langs->trans("DateValidation").' : '.(empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour')); + /*if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) { $warehousestatic->fetch($shipmentline_var['warehouse']); $htmltext .= '
'.$langs->trans("FromLocation").' : '.$warehousestatic->getNomUrl(1, '', 0, 1); - } - print ' '.$form->textwithpicto('', $htmltext, 1); + }*/ + //print ' '.$form->textwithpicto('', $htmltext, 1); + + $qtyalreadysent += $shipmentline_var['qty_shipped']; } } } + print $form->textwithpicto($qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip'.$lines[$i]->id); print ''; } @@ -2390,7 +2412,7 @@ if ($action == 'create') { if ($detail_entrepot->entrepot_id > 0) { $entrepot = new Entrepot($db); $entrepot->fetch($detail_entrepot->entrepot_id); - $detail .= $langs->trans("DetailWarehouseFormat", $entrepot->libelle, $detail_entrepot->qty_shipped).'
'; + $detail .= $langs->trans("DetailWarehouseFormat", $entrepot->label, $detail_entrepot->qty_shipped).'
'; } } print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"), $detail); @@ -2531,13 +2553,20 @@ if ($action == 'create') { } } - // TODO add alternative status - // 0=draft, 1=validated, 2=billed, we miss a status "delivered" (only available on order) - if ($object->statut == Expedition::STATUS_CLOSED && $user->rights->expedition->creer) { - if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) { // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? - print dolGetButtonAction('', $langs->trans('ClassifyUnbilled'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, ''); - } else { - print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, ''); + // 0=draft, 1=validated/delivered, 2=closed/delivered + // If WORKFLOW_BILL_ON_SHIPMENT: 0=draft, 1=validated, 2=billed (no status delivered) + if ($object->statut == Expedition::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) { + if ($user->hasRight('expedition', 'creer')) { + print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?action=setdraft&token='.newToken().'&id='.$object->id, ''); + } + } + if ($object->statut == Expedition::STATUS_CLOSED) { + if ($user->hasRight('expedition', 'creer')) { + if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) { // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + print dolGetButtonAction('', $langs->trans('ClassifyUnbilled'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, ''); + } else { + print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, ''); + } } } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 0f7bedc19d3..c3ddf973049 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2209,8 +2209,8 @@ class Expedition extends CommonObject $sql = "SELECT cd.fk_product, cd.subprice,"; $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; $sql .= " e.ref,"; - $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; - $sql .= " ,cd.rowid as cdid, ed.rowid as edid"; + $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock,"; + $sql .= " cd.rowid as cdid, ed.rowid as edid"; $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd,"; $sql .= " " . MAIN_DB_PREFIX . "expeditiondet as ed"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; @@ -2264,8 +2264,8 @@ class Expedition extends CommonObject // If some stock lines are now 0, we can remove entry into llx_product_stock, but only if there is no child lines into llx_product_batch (detail of batch, because we can imagine // having a lot1/qty=X and lot2/qty=-X, so 0 but we must not loose repartition of different lot. - $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; - $resql = $this->db->query($sql); + $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; + $resqldelete = $this->db->query($sqldelete); // We do not test error, it can fails if there is child in batch details } } else { @@ -2318,6 +2318,23 @@ class Expedition extends CommonObject } } + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->statut <= self::STATUS_DRAFT) { + return 0; + } + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'SHIPMENT_UNVALIDATE'); + } + /** * Classify the shipping as validated/opened * @@ -2338,7 +2355,7 @@ class Expedition extends CommonObject $oldbilled = $this->billed; - $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut=1'; + $sql = 'UPDATE '.MAIN_DB_PREFIX.'expedition SET fk_statut = 1'; $sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > 0'; $resql = $this->db->query($sql); @@ -2388,7 +2405,7 @@ class Expedition extends CommonObject // line without batch detail // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr", $numref)); + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr", $this->ref)); if ($result < 0) { $this->error = $mouvS->error; $this->errors = $mouvS->errors; @@ -2399,7 +2416,7 @@ class Expedition extends CommonObject // line with batch detail // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr", $numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentUnClassifyCloseddInDolibarr", $this->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); if ($result < 0) { $this->error = $mouvS->error; $this->errors = $mouvS->errors; diff --git a/htdocs/expedition/shipment.php b/htdocs/expedition/shipment.php index 325559882d8..0470da549e5 100644 --- a/htdocs/expedition/shipment.php +++ b/htdocs/expedition/shipment.php @@ -773,7 +773,7 @@ if ($id > 0 || !empty($ref)) { $toBeShippedTotal += $toBeShipped[$objp->fk_product]; print $toBeShipped[$objp->fk_product]; } else { - print '0 ('.$langs->trans("Service").')'; + print '0 ('.$langs->trans("Service").')'; } print ($objp->unit_order ? ' '.$objp->unit_order : '').''; diff --git a/htdocs/expensereport/card.php b/htdocs/expensereport/card.php index 168e7461427..93aa8fcefb3 100644 --- a/htdocs/expensereport/card.php +++ b/htdocs/expensereport/card.php @@ -2031,6 +2031,7 @@ if ($action == 'create') { print ''; print ''; print ''; + print ''; print '
'; print ''; @@ -2049,7 +2050,7 @@ if ($action == 'create') { if (!empty($conf->global->MAIN_USE_EXPENSE_IK)) { print ''; } - print ''; + print ''; print ''; print ''; print ''; @@ -2088,7 +2089,7 @@ if ($action == 'create') { // Project if (isModEnabled('project')) { - print ''; } - print ''; + print ''; print ''; print ''; print ''; @@ -2562,7 +2563,7 @@ if ($action == 'create') { } print ''; print ''; diff --git a/htdocs/fourn/js/lib_dispatch.js.php b/htdocs/fourn/js/lib_dispatch.js.php index ff822543ddb..6bd2d39ce21 100644 --- a/htdocs/fourn/js/lib_dispatch.js.php +++ b/htdocs/fourn/js/lib_dispatch.js.php @@ -69,13 +69,15 @@ function addDispatchLine(index, type, mode) { mode = mode || 'qtymissing' - console.log("fourn/js/lib_dispatch.js.php Split line type="+type+" index="+index+" mode="+mode); var $row0 = $("tr[name='"+type+'_0_'+index+"']"); var $dpopt = $row0.find('.hasDatepicker').first().datepicker('option', 'all'); // get current datepicker options to apply the same to the cloned datepickers var $row = $row0.clone(true); // clone first batch line to jQuery object var nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length; // position of line for batch var qtyOrdered = parseFloat($("#qty_ordered_0_"+index).val()); // Qty ordered is same for all rows var qty = parseFloat($("#qty_"+(nbrTrs - 1)+"_"+index).val()); + + console.log("fourn/js/lib_dispatch.js.php Split line type="+type+" index="+index+" mode="+mode+" qtyOrdered="+qtyOrdered+" qty="+qty); + var qtyDispatched; if (mode === 'lessone') @@ -93,9 +95,17 @@ function addDispatchLine(index, type, mode) } console.log("qtyDispatched="+qtyDispatched+" qtyOrdered="+qtyOrdered); - if (qtyDispatched >= qtyOrdered || qtyOrdered <= 1) { + if (qty <= 1) { window.alert("Remain quantity to dispatch is too low to be split"); - } else if (qtyDispatched < qtyOrdered) { + } else { + oldlineqty = qtyDispatched; + newlineqty = qtyOrdered - qtyDispatched; + if (newlineqty <= 0) { + newlineqty = qty - 1; + oldlineqty = 1; + $("#qty_"+(nbrTrs - 1)+"_"+index).val(oldlineqty); + } + //replace tr suffix nbr $row.html($row.html().replace(/_0_/g,"_"+nbrTrs+"_")); @@ -127,7 +137,7 @@ function addDispatchLine(index, type, mode) /* Suffix of lines are: _ trs.length _ index */ $("#qty_"+nbrTrs+"_"+index).focus(); - $("#qty_dispatched_0_"+index).val(qtyDispatched); + $("#qty_dispatched_0_"+index).val(oldlineqty); //hide all buttons then show only the last one $("tr[name^='"+type+"_'][name$='_"+index+"'] .splitbutton").hide(); @@ -138,7 +148,7 @@ function addDispatchLine(index, type, mode) qty = 1; // keep 1 in old line $("#qty_"+(nbrTrs-1)+"_"+index).val(qty); } - $("#qty_"+nbrTrs+"_"+index).val(qtyOrdered - qtyDispatched); + $("#qty_"+nbrTrs+"_"+index).val(newlineqty); // Store arbitrary data for dispatch qty input field change event $("#qty_"+(nbrTrs-1)+"_"+index).data('qty', qty); $("#qty_"+(nbrTrs-1)+"_"+index).data('type', type); diff --git a/htdocs/includes/webklex/php-imap/vendor/autoload.php b/htdocs/includes/webklex/php-imap/vendor/autoload.php index 298bedf9b9c..12f2cb6cb45 100644 --- a/htdocs/includes/webklex/php-imap/vendor/autoload.php +++ b/htdocs/includes/webklex/php-imap/vendor/autoload.php @@ -17,6 +17,13 @@ return ComposerAutoloaderInit4da13270269c89a28e472e1f7324e6d1::getLoader(); // Add class/method of PHP8 for compatibility with older versions of PHP require_once(__DIR__.'/symfony/polyfill-php80/bootstrap.php'); +//'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', +//'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', +//'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php', +//'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', +//'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', +require_once(__DIR__.'/illuminate/collections/helpers.php'); + spl_autoload_register(function ($class_name) { // Enable this to detect what we need for require_once diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 9fb7a487118..a493b104036 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -573,7 +573,7 @@ Module50Desc=Management of Products Module51Name=Mass mailings Module51Desc=Mass paper mailing management Module52Name=Stocks -Module52Desc=Stock management +Module52Desc=Stock management (stock movement tracking and inventory) Module53Name=Services Module53Desc=Management of Services Module54Name=Contracts/Subscriptions diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index adc9c4177ad..43718271919 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -62,7 +62,7 @@ MemberSubscriptionAddedInDolibarr=Subscription %s for member %s added MemberSubscriptionModifiedInDolibarr=Subscription %s for member %s modified MemberSubscriptionDeletedInDolibarr=Subscription %s for member %s deleted ShipmentValidatedInDolibarr=Shipment %s validated -ShipmentClassifyClosedInDolibarr=Shipment %s classified billed +ShipmentClassifyClosedInDolibarr=Shipment %s classified closed ShipmentUnClassifyCloseddInDolibarr=Shipment %s classified re-open ShipmentBackToDraftInDolibarr=Shipment %s go back to draft status ShipmentDeletedInDolibarr=Shipment %s deleted diff --git a/htdocs/langs/en_US/commercial.lang b/htdocs/langs/en_US/commercial.lang index eba95a8aabb..a2f5c6d21ce 100644 --- a/htdocs/langs/en_US/commercial.lang +++ b/htdocs/langs/en_US/commercial.lang @@ -65,8 +65,8 @@ ActionAC_SUP_ORD=Send purchase order by mail ActionAC_SUP_INV=Send vendor invoice by mail ActionAC_OTH=Other ActionAC_OTH_AUTO=Other auto -ActionAC_MANUAL=Manually inserted events -ActionAC_AUTO=Automatically inserted events +ActionAC_MANUAL=Events inserted manually (by a user) +ActionAC_AUTO=Events inserted automatically ActionAC_OTH_AUTOShort=Other ActionAC_EVENTORGANIZATION=Event organization events Stats=Sales statistics diff --git a/htdocs/langs/en_US/productbatch.lang b/htdocs/langs/en_US/productbatch.lang index a1039e05e62..c51d94b8acd 100644 --- a/htdocs/langs/en_US/productbatch.lang +++ b/htdocs/langs/en_US/productbatch.lang @@ -19,7 +19,7 @@ printSellby=Sell-by: %s printQty=Qty: %d printPlannedWarehouse=Warehouse: %s AddDispatchBatchLine=Add a line for Shelf Life dispatching -WhenProductBatchModuleOnOptionAreForced=When module Lot/Serial is on, automatic stock decrease is forced to 'Decrease real stocks on shipping validation' and automatic increase mode is forced to 'Increase real stocks on manual dispatching into warehouses' and can't be edited. Other options can be defined as you want. +WhenProductBatchModuleOnOptionAreForced=When module Lot/Serial is on, automatic stock decrease is forced to '%s' and automatic increase mode is forced to '%s'. Some choices may be not available. Other options can be defined as you want. ProductDoesNotUseBatchSerial=This product does not use lot/serial number ProductLotSetup=Setup of module lot/serial ShowCurrentStockOfLot=Show current stock for couple product/lot diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 6a8821de833..62ebfc53ef9 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -318,3 +318,5 @@ StockTransferRightRead=Read stocks transfers StockTransferRightCreateUpdate=Create/Update stocks transfers StockTransferRightDelete=Delete stocks transfers BatchNotFound=Lot / serial not found for this product +StockMovementWillBeRecorded=Stock movement will be recorded +StockMovementNotYetRecorded=Stock movement will not be affected by this step \ No newline at end of file diff --git a/htdocs/langs/fr_FR/agenda.lang b/htdocs/langs/fr_FR/agenda.lang index 86e97805dd5..33d925ac777 100644 --- a/htdocs/langs/fr_FR/agenda.lang +++ b/htdocs/langs/fr_FR/agenda.lang @@ -62,7 +62,7 @@ MemberSubscriptionAddedInDolibarr=Cotisation %s pour l'adhérent %s ajoutée MemberSubscriptionModifiedInDolibarr=Cotisation %s pour l'adhérent %s modifié MemberSubscriptionDeletedInDolibarr=Cotisation %s pour l'adhérent %s supprimé ShipmentValidatedInDolibarr=Expédition %s validée -ShipmentClassifyClosedInDolibarr=Expédition %s classée payée +ShipmentClassifyClosedInDolibarr=Expédition %s classée close ShipmentUnClassifyCloseddInDolibarr=Expédition %s réouverte ShipmentBackToDraftInDolibarr=Expédition %s remise au statut brouillon ShipmentDeletedInDolibarr=Expédition %s supprimée diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index ce7a7a9ec8d..8ca8d5e06af 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -2312,7 +2312,9 @@ function top_menu_user($hideloginname = 0, $urllogout = '') } $dropdownBody .= '
'.$langs->trans("VATIntraShort").': '.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').''; $dropdownBody .= '
'.$langs->trans("Country").': '.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').''; - + if (isModEnabled('multicurrency')) { + $dropdownBody .= '
'.$langs->trans("Currency").': '.$conf->currency.''; + } $dropdownBody .= ''; $dropdownBody .= '
'; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 67002e48efb..db5ebf7bf4c 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -871,6 +871,7 @@ class Product extends CommonObject $langs->load("products"); $error++; $this->error = "ErrorProductAlreadyExists"; + dol_syslog(get_class($this)."::Create fails, ref ".$this->ref." already exists"); } } else { $error++; diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php index 3fcbbd73ced..8c655df44ff 100644 --- a/htdocs/product/reassortlot.php +++ b/htdocs/product/reassortlot.php @@ -6,6 +6,7 @@ * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2016 Ferran Marcet * Copyright (C) 2019 Juanjo Menent + * Copyright (C) 2021 Noé Cendrier * * 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 @@ -37,7 +38,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; // Load translation files required by the page -$langs->loadLangs(array('products', 'stocks', 'productbatch')); +$langs->loadLangs(array('products', 'stocks', 'productbatch', 'categories')); $action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ... $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) @@ -48,7 +49,7 @@ $mode = GETPOST('mode', 'aZ'); $sref = GETPOST("sref", 'alpha'); $snom = GETPOST("snom", 'alpha'); -$sall = trim((GETPOST('search_all', 'alphanohtml') != '') ?GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml')); +$search_all = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml')); $type = GETPOSTISSET('type') ? GETPOST('type', 'int') : Product::TYPE_PRODUCT; $search_barcode = GETPOST("search_barcode", 'alpha'); $search_warehouse = GETPOST('search_warehouse', 'alpha'); @@ -82,6 +83,7 @@ if (GETPOSTISSET('catid')) { } else { $search_categ = GETPOST('search_categ', 'int'); } +$search_warehouse_categ = GETPOST('search_warehouse_categ', 'int'); // Fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); @@ -173,11 +175,12 @@ if (empty($reshook)) { $search['eatby_dtend'] = ''; $sref = ""; $snom = ""; - $sall = ""; + $search_all = ""; $tosell = ""; $tobuy = ""; $search_sale = ""; $search_categ = ""; + $search_warehouse_categ = ""; $search_toolowstock = ''; $search_subjecttolotserial = ''; $search_batch = ''; @@ -255,8 +258,24 @@ if (!empty($search_categ) && $search_categ != '-1') { } $sql .= ")"; } -if ($sall) { - $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall); +if (!empty($search_warehouse_categ) && $search_warehouse_categ != '-1') { + $sql .= " AND "; + if ($search_warehouse_categ == -2) { + $sql .= " NOT EXISTS "; + } else { + $sql .= " EXISTS "; + } + $sql .= "("; + $sql .= " SELECT cp.fk_categorie, cp.fk_warehouse"; + $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_warehouse as cp"; + $sql .= " WHERE cp.fk_warehouse = e.rowid"; // Join for the needed table to filter by categ + if ($search_warehouse_categ > 0) { + $sql .= " AND cp.fk_categorie = " . ((int) $search_warehouse_categ); + } + $sql .= ")"; +} +if ($search_all) { + $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $search_all); } // if the type is not 1, we show all products (type = 0,2,3) if (dol_strlen($type)) { @@ -402,7 +421,7 @@ $num = $db->num_rows($resql); $i = 0; -if ($num == 1 && GETPOST('autojumpifoneonly') && ($sall or $snom or $sref)) { +if ($num == 1 && GETPOST('autojumpifoneonly') && ($search_all or $snom or $sref)) { $objp = $db->fetch_object($resql); header("Location: card.php?id=$objp->rowid"); exit; @@ -443,8 +462,8 @@ foreach ($search as $key => $val) { if ($optioncss != '') { $param .= '&optioncss='.urlencode($optioncss); } -if ($sall) { - $param .= "&sall=".urlencode($sall); +if ($search_all) { + $param .= "&search_all=".urlencode($search_all); } if ($tosell) { $param .= "&tosell=".urlencode($tosell); @@ -485,6 +504,9 @@ if ($search_sale) { if (!empty($search_categ) && $search_categ != '-1') { $param .= "&search_categ=".urlencode($search_categ); } +if (!empty($search_warehouse_categ) && $search_warehouse_categ != '-1') { + $param .= "&search_warehouse_categ=".urlencode($search_warehouse_categ); +} if ($search_stock_physique) { $param .= '&search_stock_physique=' . urlencode($search_stock_physique); } @@ -508,7 +530,7 @@ print ''; print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit, 0, 0, 1); - +/* if ($search_categ > 0) { print "
"; $c = new Categorie($db); @@ -517,17 +539,27 @@ if ($search_categ > 0) { print " > ".$ways[0]."
\n"; print "

"; } +*/ // Filter on categories $moreforfilter = ''; if (isModEnabled('categorie')) { $moreforfilter .= '
'; - $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"'); - $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1); + $moreforfilter .= img_picto($langs->trans('ProductsCategoriesShort'), 'category', 'class="pictofixedwidth"'); + $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1, $langs->trans("ProductsCategoryShort"), 'maxwidth400'); $moreforfilter .= '
'; } +// Filter on warehouse categories +if (isModEnabled('categorie')) { + $moreforfilter .= '
'; + $moreforfilter .= img_picto($langs->trans('StockCategoriesShort'), 'category', 'class="pictofixedwidth"'); + $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_WAREHOUSE, $search_warehouse_categ, 'search_warehouse_categ', 1, $langs->trans("StockCategoriesShort"), 'maxwidth400'); + $moreforfilter .= '
'; +} + $moreforfilter.=''; + if (!empty($moreforfilter)) { print '
'; print $moreforfilter; diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 083ea381015..b596ac551b1 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -301,7 +301,9 @@ class MouvementStock extends CommonObject // If not found, we add record $sql = "SELECT pb.rowid, pb.batch, pb.eatby, pb.sellby FROM ".$this->db->prefix()."product_lot as pb"; $sql .= " WHERE pb.fk_product = ".((int) $fk_product)." AND pb.batch = '".$this->db->escape($batch)."'"; + dol_syslog(get_class($this)."::_create scan serial for this product to check if eatby and sellby match", LOG_DEBUG); + $resql = $this->db->query($sql); if ($resql) { $num = $this->db->num_rows($resql); @@ -560,6 +562,10 @@ class MouvementStock extends CommonObject if (!$error && isModEnabled('productbatch') && $product->hasbatch() && !$skip_batch) { if ($id_product_batch > 0) { $result = $this->createBatch($id_product_batch, $qty); + if ($result == -2 && $fk_product_stock > 0) { // The entry for this product batch does not exists anymore, bu we already have a llx_product_stock, so we recreate the batch entry in product_batch + $param_batch = array('fk_product_stock' =>$fk_product_stock, 'batchnumber'=>$batch); + $result = $this->createBatch($param_batch, $qty); + } } else { $param_batch = array('fk_product_stock' =>$fk_product_stock, 'batchnumber'=>$batch); $result = $this->createBatch($param_batch, $qty); @@ -863,10 +869,10 @@ class MouvementStock extends CommonObject * Create or update batch record (update table llx_product_batch). No check is done here, done by parent. * * @param array|int $dluo Could be either - * - int if row id of product_batch table + * - int if row id of product_batch table (for update) * - or complete array('fk_product_stock'=>, 'batchnumber'=>) * @param int $qty Quantity of product with batch number. May be a negative amount. - * @return int <0 if KO, else return productbatch id + * @return int <0 if KO, -2 if we try to update a product_batchid that does not exist, else return productbatch id */ private function createBatch($dluo, $qty) { diff --git a/htdocs/product/stock/movement_list.php b/htdocs/product/stock/movement_list.php index 56d39ae0e88..72f36220185 100644 --- a/htdocs/product/stock/movement_list.php +++ b/htdocs/product/stock/movement_list.php @@ -50,20 +50,23 @@ if (isModEnabled('productbatch')) { $langs->load("productbatch"); } -$id = GETPOST('id', 'int'); -$ref = GETPOST('ref', 'alpha'); -$msid = GETPOST('msid', 'int'); -$product_id = GETPOST("product_id", 'int'); $action = GETPOST('action', 'aZ09'); $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists) $confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation $cancel = GETPOST('cancel', 'alpha'); -$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'movementlist'; +$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list $backtopage = GETPOST("backtopage", "alpha"); +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') +$mode = GETPOST('mode', 'aZ'); // The output mode ('list', 'kanban', 'hierarchy', 'calendar', ...) +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$msid = GETPOST('msid', 'int'); $idproduct = GETPOST('idproduct', 'int'); -$sall = trim((GETPOST('search_all', 'alphanohtml') != '') ?GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml')); +$product_id = GETPOST("product_id", 'int'); + +$search_all = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml')); $search_date_startday = GETPOST('search_date_startday', 'int'); $search_date_startmonth = GETPOST('search_date_startmonth', 'int'); $search_date_startyear = GETPOST('search_date_startyear', 'int'); @@ -83,7 +86,7 @@ $search_batch = trim(GETPOST("search_batch")); $search_qty = trim(GETPOST("search_qty")); $search_type_mouvement = GETPOST('search_type_mouvement', 'int'); $search_fk_projet=GETPOST("search_fk_projet", 'int'); -$optioncss = GETPOST('optioncss', 'alpha'); + $type = GETPOST("type", "int"); // Load variable for pagination @@ -108,15 +111,15 @@ if (!$sortorder) { $pdluoid = GETPOST('pdluoid', 'int'); -// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +// Initialize technical objects $object = new MouvementStock($db); $extrafields = new ExtraFields($db); $diroutputmassaction = $conf->stock->dir_output.'/temp/massgeneration/'.$user->id; -$hookmanager->initHooks(array('movementlist')); +$hookmanager->initHooks(array($contextpage)); // Note that conf->hooks_modules contains array of activated contexes $formfile = new FormFile($db); -// fetch optionals attributes and labels +// Fetch optionals attributes and labels $extrafields->fetch_name_optionals_label($object->table_element); $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); @@ -224,7 +227,7 @@ if (empty($reshook)) { $search_batch = ""; $search_qty = ''; $search_fk_projet=0; - $sall = ""; + $search_all = ""; $toselect = array(); $search_array_options = array(); } @@ -588,18 +591,21 @@ if ($action == "transfert_stock" && !$cancel) { * View */ -$productlot = new ProductLot($db); -$productstatic = new Product($db); -$warehousestatic = new Entrepot($db); -$movement = new MouvementStock($db); -$userstatic = new User($db); $form = new Form($db); $formproduct = new FormProduct($db); if (!empty($conf->project->enabled)) { $formproject = new FormProjets($db); } +$productlot = new ProductLot($db); +$productstatic = new Product($db); +$warehousestatic = new Entrepot($db); +$movement = new MouvementStock($db); +$userstatic = new User($db); + +$now = dol_now(); // Build and execute select +// -------------------------------------------------------------------- $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tosell, p.tobuy, p.tobatch, p.fk_product_type as type, p.entity,"; $sql .= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu, e.fk_parent, e.statut,"; $sql .= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,"; @@ -616,7 +622,7 @@ if (!empty($extrafields->attributes[$object->table_element]['label'])) { } // Add fields from hooks $parameters = array(); -$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; $sql = preg_replace('/,\s*$/', '', $sql); @@ -697,7 +703,7 @@ if ($search_type_mouvement != '' && $search_type_mouvement != '-1') { include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; // Add where from hooks $parameters = array(); -$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; // Count total nb of records @@ -714,7 +720,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { dol_print_error($db); } - if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 + if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0 $page = 0; $offset = 0; } @@ -733,6 +739,9 @@ if (!$resql) { exit; } +$num = $db->num_rows($resql); + + $product = new Product($db); $object = new Entrepot($db); @@ -746,8 +755,6 @@ if ($id > 0 || $ref) { } } -$num = $db->num_rows($resql); - // Output page // -------------------------------------------------------------------- @@ -767,9 +774,11 @@ if ($msid) { } } -llxHeader('', $title, $help_url); -$arrayofselected = is_array($toselect) ? $toselect : array(); +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url); /* * Show tab only if we ask a particular warehouse @@ -939,7 +948,12 @@ if ((empty($action) || $action == 'list') && $id > 0) { print '

'; } +$arrayofselected = is_array($toselect) ? $toselect : array(); + $param = ''; +if (!empty($mode)) { + $param .= '&mode='.urlencode($mode); +} if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) { $param .= '&contextpage='.urlencode($contextpage); } @@ -996,6 +1010,10 @@ if ($idproduct > 0) { } // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; +// Add $param from hooks +$parameters = array(); +$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +$param .= $hookmanager->resPrint; // List of mass actions available $arrayofmassactions = array(); @@ -1023,10 +1041,15 @@ print ''; print ''; print ''; print ''; +print ''; +print ''; if ($id > 0) { print ''; } + +$newcardbutton = ''; + if ($id > 0) { print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'movement', 0, '', '', $limit, 0, 0, 1); } else { @@ -1040,17 +1063,20 @@ $objecttmp = new MouvementStock($db); $trackid = 'mov'.$object->id; include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; -if ($sall) { +if ($search_all) { + $setupstring = ''; foreach ($fieldstosearchall as $key => $val) { $fieldstosearchall[$key] = $langs->trans($val); + $setupstring .= $key."=".$val.";"; } - print '
'.$langs->trans("FilterOnInto", $sall).join(', ', $fieldstosearchall).'
'; + print ''."\n"; + print '
'.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'
'."\n"; } $moreforfilter = ''; $parameters = array('arrayfields'=>&$arrayfields); -$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook if (empty($reshook)) { $moreforfilter .= $hookmanager->resPrint; } else { @@ -1064,7 +1090,7 @@ if (!empty($moreforfilter)) { } $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; -$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields = ($mode != 'kanban' ? $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')) : ''); // This also change content of $arrayfields $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table @@ -1073,6 +1099,13 @@ print '
'.$langs->trans('CarCategory').''.$langs->trans('Description').''.$langs->trans('Description').''.$langs->trans('VAT').''.$langs->trans('PriceUHT').''.$langs->trans('PriceUTTC').''; + print ''; if ($line->fk_project > 0) { $projecttmp->id = $line->fk_project; $projecttmp->ref = $line->projet_ref; @@ -2483,7 +2484,7 @@ if ($action == 'create') { if (!empty($conf->global->MAIN_USE_EXPENSE_IK)) { print ''.$langs->trans('CarCategory').''.$langs->trans('Description').''.$langs->trans('Description').''.$langs->trans('VAT').''.$langs->trans('PriceUHT').''.$langs->trans('PriceUTTC').''; - print $form->buttonsSaveCancel("Add", '', '', 1); + print $form->buttonsSaveCancel("Add", '', '', 1, 'reposition'); print '
'; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} if (!empty($arrayfields['m.rowid']['checked'])) { // Ref print ''; } // Action column -print ''; +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; +} print ''."\n"; +$totalarray = array(); +$totalarray['nbfield'] = 0; // Fields title label // -------------------------------------------------------------------- print ''; +// Action column +if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; + $totalarray['nbfield']++; +} if (!empty($arrayfields['m.rowid']['checked'])) { print_liste_field_titre($arrayfields['m.rowid']['label'], $_SERVER["PHP_SELF"], 'm.rowid', '', $param, '', $sortfield, $sortorder); } @@ -1262,8 +1304,8 @@ if (!empty($arrayfields['m.price']['checked'])) { include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; // Hook fields -$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); -$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder, 'totalarray'=>&$totalarray); +$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; if (!empty($arrayfields['m.datec']['checked'])) { print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap '); @@ -1272,7 +1314,10 @@ if (!empty($arrayfields['m.tms']['checked'])) { print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap '); } // Action column -print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); +if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; + $totalarray['nbfield']++; +} print ''."\n"; @@ -1282,9 +1327,11 @@ $arrayofuniqueproduct = array(); // Loop on record // -------------------------------------------------------------------- $i = 0; +$savnbfield = $totalarray['nbfield']; $totalarray = array(); $totalarray['nbfield'] = 0; -while ($i < ($limit ? min($num, $limit) : $num)) { +$imaxinloop = ($limit ? min($num, $limit) : $num); +while ($i < $imaxinloop) { $obj = $db->fetch_object($resql); if (empty($obj)) { break; // Should not happen @@ -1346,139 +1393,193 @@ while ($i < ($limit ? min($num, $limit) : $num)) { $origin = ''; } - print ''; - // Id movement - if (!empty($arrayfields['m.rowid']['checked'])) { - print ''; // This is primary not movement id - } - if (!empty($arrayfields['m.datem']['checked'])) { - // Date - print ''; - } - if (!empty($arrayfields['p.ref']['checked'])) { - // Product ref - print '\n"; - } - if (!empty($arrayfields['p.label']['checked'])) { - // Product label - print '\n"; - } - if (!empty($arrayfields['m.batch']['checked'])) { - print ''; - } - if (!empty($arrayfields['pl.eatby']['checked'])) { - print ''; - } - if (!empty($arrayfields['pl.sellby']['checked'])) { - print ''; - } - // Warehouse - if (!empty($arrayfields['e.ref']['checked'])) { - print '\n"; - } - // Author - if (!empty($arrayfields['m.fk_user_author']['checked'])) { - print '\n"; - } - if (!empty($arrayfields['m.inventorycode']['checked'])) { - // Inventory code - print ''; - } - if (!empty($arrayfields['m.label']['checked'])) { - // Label of movement - print ''; - } - if (!empty($arrayfields['origin']['checked'])) { - // Origin of movement - print ''; - } - if (!empty($arrayfields['m.fk_projet']['checked'])) { - // fk_project - print ''; - } - if (!empty($arrayfields['m.type_mouvement']['checked'])) { - // Type of movement - print ''; - } - if (!empty($arrayfields['m.value']['checked'])) { - // Qty - print ''; } - print ''; - } - if (!empty($arrayfields['m.price']['checked'])) { - // Price - print ''; + // Action column + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Id movement + if (!empty($arrayfields['m.rowid']['checked'])) { + print ''; // This is primary not movement id + } + if (!empty($arrayfields['m.datem']['checked'])) { + // Date + print ''; + } + if (!empty($arrayfields['p.ref']['checked'])) { + // Product ref + print '\n"; + } + if (!empty($arrayfields['p.label']['checked'])) { + // Product label + print '\n"; + } + if (!empty($arrayfields['m.batch']['checked'])) { + print ''; + } + if (!empty($arrayfields['pl.eatby']['checked'])) { + print ''; + } + if (!empty($arrayfields['pl.sellby']['checked'])) { + print ''; + } + // Warehouse + if (!empty($arrayfields['e.ref']['checked'])) { + print '\n"; + } + // Author + if (!empty($arrayfields['m.fk_user_author']['checked'])) { + print '\n"; + } + if (!empty($arrayfields['m.inventorycode']['checked'])) { + // Inventory code + print ''; + } + if (!empty($arrayfields['m.label']['checked'])) { + // Label of movement + print ''; + } + if (!empty($arrayfields['origin']['checked'])) { + // Origin of movement + print ''; + } + if (!empty($arrayfields['m.fk_projet']['checked'])) { + // fk_project + print ''; + } + if (!empty($arrayfields['m.type_mouvement']['checked'])) { + // Type of movement + print ''; + } + if (!empty($arrayfields['m.value']['checked'])) { + // Qty + print ''; + } + if (!empty($arrayfields['m.price']['checked'])) { + // Price + print ''; } - print ''; - } - // Extra fields - $object = $movement; - include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; - // Fields from hook - $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); - $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; + // Extra fields + $object = $movement; + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; - // Action column - print ''; + if (!$i) { + $totalarray['nbfield']++; + } } - print ''; - } - print ''; - if (!$i) { - $totalarray['nbfield']++; - } - print ''."\n"; + print ''."\n"; + } $i++; } +// If no record found +if ($num == 0) { + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + $db->free($resql); -print "
'; + $searchpicto = $form->showFilterButtons('left'); + print $searchpicto; + print ''; @@ -1185,7 +1218,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; // Fields from hook $parameters = array('arrayfields'=>$arrayfields); -$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; // Date creation if (!empty($arrayfields['m.datec']['checked'])) { @@ -1198,16 +1231,25 @@ if (!empty($arrayfields['m.tms']['checked'])) { print ''; -$searchpicto = $form->showFilterButtons(); -print $searchpicto; -print ''; + $searchpicto = $form->showFilterButtons(); + print $searchpicto; + print '
'; - print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"'); - print $obj->mid; - print ''.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').''; - print $productstatic->getNomUrl(1, 'stock', 16); - print "'; - print $productstatic->label; - print "'; - if ($productlot->id > 0) { - print $productlot->getNomUrl(1); - } else { - print $productlot->batch; // the id may not be defined if movement was entered when lot was not saved or if lot was removed after movement. + if ($mode == 'kanban') { + if ($i == 0) { + print '
'; + print '
'; } - print '
'.dol_print_date($obj->eatby, 'day').''.dol_print_date($obj->sellby, 'day').''; - print $warehousestatic->getNomUrl(1); - print "'; - print $userstatic->getNomUrl(-1); - print "inventorycode.'$').'&search_type_mouvement='.urlencode($obj->type_mouvement).'">'.$obj->inventorycode.''.$obj->label.''.$origin.''; - if ($obj->fk_project != 0) { - print $movement->get_origin($obj->fk_project, 'project'); + // Output Kanban + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($object->id, $arrayofselected)) { + $selected = 1; + } } - print ''; - print $movement->getTypeMovement(); - print ''; - if ($obj->qty > 0) { - print ''; - print '+'; - print $obj->qty; - print ''; - } else { - print ''; - print $obj->qty; - print ''; + print $object->getKanbanView(''); + if ($i == ($imaxinloop - 1)) { + print ''; + print '
'; - if ($obj->price != 0) { - print price($obj->price); + } else { + // Show here line of result + $j = 0; + print '
'; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->mid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print ''; + print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"'); + print $obj->mid; + print ''.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').''; + print $productstatic->getNomUrl(1, 'stock', 16); + print "'; + print $productstatic->label; + print "'; + if ($productlot->id > 0) { + print $productlot->getNomUrl(1); + } else { + print $productlot->batch; // the id may not be defined if movement was entered when lot was not saved or if lot was removed after movement. + } + print ''.dol_print_date($obj->eatby, 'day').''.dol_print_date($obj->sellby, 'day').''; + print $warehousestatic->getNomUrl(1); + print "'; + print $userstatic->getNomUrl(-1); + print "inventorycode.'$').'&search_type_mouvement='.urlencode($obj->type_mouvement).'">'.$obj->inventorycode.''.$obj->label.''.$origin.''; + if ($obj->fk_project != 0) { + print $movement->get_origin($obj->fk_project, 'project'); + } + print ''; + print $movement->getTypeMovement(); + print ''; + if ($obj->qty > 0) { + print ''; + print '+'; + print $obj->qty; + print ''; + } else { + print ''; + print $obj->qty; + print ''; + } + print ''; + if ($obj->price != 0) { + print price($obj->price); + } + print ''; - if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined - $selected = 0; - if (in_array($obj->mid, $arrayofselected)) { - $selected = 1; + // Action column + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected = 0; + if (in_array($obj->mid, $arrayofselected)) { + $selected = 1; + } + print ''; + } + print '
'.$langs->trans("NoRecordFound").'
"; -print '
'; -print "
"; +$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql); +$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print ''."\n"; +print ''."\n"; + +print ''."\n"; // Add number of product when there is a filter on period if (count($arrayofuniqueproduct) == 1 && !empty($year) && is_numeric($year)) { @@ -1527,7 +1628,7 @@ if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $n $genallowed = $permissiontoread; $delallowed = $permissiontoadd; - print $formfile->showdocuments('massfilesarea_mymodule', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); + print $formfile->showdocuments('massfilesarea_'.$object->module, '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); } // End of page diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 42833785c09..2b0ffd51b43 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -1159,11 +1159,14 @@ if ($action == 'create' && $user->rights->projet->creer) { print $form->selectDate($object->date_start ? $object->date_start : -1, 'projectstart', 0, 0, 0, '', 1, 0); print ' '.$langs->trans("to").' '; print $form->selectDate($object->date_end ? $object->date_end : -1, 'projectend', 0, 0, 0, '', 1, 0); - print '     getLinesArray(null, 0); + if (!empty($object->usage_task) && !empty($object->lines)) { + print ' '; } - print '/>'; print ''; if (isModEnabled('eventorganization')) { @@ -1385,6 +1388,11 @@ if ($action == 'create' && $user->rights->projet->creer) { jQuery("#usage_task").prop("checked", true); } }); + + jQuery("#projectstart").change(function() { + console.log("We modify the start date"); + jQuery("#divreportdate").show(); + }); }); '; diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 0b8f48c90e3..8e51f44c6c3 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -291,7 +291,7 @@ class Project extends CommonObject 'date_close' =>array('type'=>'datetime', 'label'=>'DateClosing', 'enabled'=>1, 'visible'=>0, 'position'=>105), 'fk_user_close' =>array('type'=>'integer', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>0, 'position'=>110), 'opp_amount' =>array('type'=>'double(24,8)', 'label'=>'OpportunityAmountShort', 'enabled'=>1, 'visible'=>'getDolGlobalString("PROJECT_USE_OPPORTUNITIES")', 'position'=>115), - 'budget_amount' =>array('type'=>'double(24,8)', 'label'=>'Budget', 'enabled'=>1, 'visible'=>1, 'position'=>119), + 'budget_amount' =>array('type'=>'double(24,8)', 'label'=>'Budget', 'enabled'=>1, 'visible'=>-1, 'position'=>119), 'usage_bill_time' =>array('type'=>'integer', 'label'=>'UsageBillTimeShort', 'enabled'=>1, 'visible'=>-1, 'position'=>130), 'usage_opportunity' =>array('type'=>'integer', 'label'=>'UsageOpportunity', 'enabled'=>1, 'visible'=>-1, 'position'=>135), 'usage_task' =>array('type'=>'integer', 'label'=>'UsageTasks', 'enabled'=>1, 'visible'=>-1, 'position'=>140), @@ -2344,11 +2344,11 @@ class Project extends CommonObject /** - * Create an array of tasks of current project + * Create an array of tasks of current project * - * @param User $user Object user we want project allowed to + * @param User $user Object user we want project allowed to * @param int $loadRoleMode 1= will test Roles on task; 0 used in delete project action - * @return int >0 if OK, <0 if KO + * @return int >0 if OK, <0 if KO */ public function getLinesArray($user, $loadRoleMode = 1) { diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 26119927fda..e7e8cc40b68 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -1858,8 +1858,8 @@ while ($i < $imaxinloop) { } // Email MsgID if (!empty($arrayfields['p.email_msgid']['checked'])) { - print ''; - print $obj->email_msgid; + print ''; + print dol_escape_htmltag($obj->email_msgid); print ''; if (!$i) $totalarray['nbfield']++; } diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index 0cd2eb6de5e..fbec220b671 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -1797,7 +1797,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if ($projectstatic->public) { $contactsofproject = array(); } - print $form->select_dolusers((GETPOST('userid', 'int') ? GETPOST('userid', 'int') : $userid), 'userid', 0, '', 0, '', $contactsofproject, 0, 0, 0, '', 0, $langs->trans("ResourceNotAssignedToProject"), 'maxwidth250'); + print $form->select_dolusers((GETPOST('userid', 'int') ? GETPOST('userid', 'int') : $userid), 'userid', 0, '', 0, '', $contactsofproject, 0, 0, 0, '', 0, $langs->trans("ResourceNotAssignedToProject"), 'maxwidth200'); } else { if ($nboftasks) { print img_error($langs->trans('FirstAddRessourceToAllocateTime')).' '.$langs->trans('FirstAddRessourceToAllocateTime'); @@ -1830,8 +1830,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; if ($conf->service->enabled && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) { - print ''; - print $form->select_produits('', 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500'); + print ''; + print img_picto('', 'product'); + print $form->select_produits('', 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 1, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth150', 0, '', null, 1); print ''; } } @@ -1843,7 +1844,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; $form->buttonsSaveCancel(); - print ''; + print ''; print ''; print ''; @@ -2149,7 +2150,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // Thirdparty if (!empty($arrayfields['p.fk_soc']['checked'])) { - print ''; + print ''; if ($task_time->fk_soc > 0) { if (empty($conf->cache['thridparty'][$task_time->fk_soc])) { $tmpsociete = new Societe($db); @@ -2331,9 +2332,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser } } - //Product + // Product if (!empty($arrayfields['t.fk_product']['checked'])) { - print ''; + print ''; if ($action == 'editline' && $_GET['lineid'] == $task_time->rowid) { $form->select_produits($task_time->fk_product, 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500'); } elseif (!empty($task_time->fk_product)) { @@ -2432,9 +2433,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; if (($action == 'editline' || $action == 'splitline') && GETPOST('lineid', 'int') == $task_time->rowid) { print ''; - print ''; + print ''; print ' '; - print ''; + print ''; } elseif ($user->hasRight('projet', 'time') || $user->hasRight('projet', 'all', 'creer')) { // Read project and enter time consumed on assigned tasks if (in_array($task_time->fk_user, $childids) || $user->hasRight('projet', 'all', 'creer')) { if (getDolGlobalString('MAIN_FEATURES_LEVEL') >= 2) { @@ -2474,6 +2475,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // Add line to split if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) { + print ''; print ''; // Date @@ -2491,6 +2493,18 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } + // Thirdparty + if (!empty($arrayfields['p.fk_soc']['checked'])) { + print ''; + print ''; + } + + // Thirdparty alias + if (!empty($arrayfields['s.name_alias']['checked'])) { + print ''; + print ''; + } + // Project ref if (!empty($allprojectforuser)) { if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task @@ -2522,7 +2536,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // User if (!empty($arrayfields['author']['checked'])) { - print ''; + print ''; if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) { if (empty($object->id)) { $object->fetch($id); @@ -2573,6 +2587,12 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } + // Product + if (!empty($arrayfields['t.fk_product']['checked'])) { + print ''; + print ''; + } + // Value spent if (!empty($arrayfields['value']['checked'])) { print ''; @@ -2612,7 +2632,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser // Line for second dispatching - print ''; + print ''; // Date if (!empty($arrayfields['t.element_date']['checked'])) { @@ -2629,6 +2649,18 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } + // Thirdparty + if (!empty($arrayfields['p.fk_soc']['checked'])) { + print ''; + print ''; + } + + // Thirdparty alias + if (!empty($arrayfields['s.name_alias']['checked'])) { + print ''; + print ''; + } + // Project ref if (!empty($allprojectforuser)) { if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task @@ -2653,14 +2685,14 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser if (!empty($arrayfields['t.element_label']['checked'])) { if ((empty($id) && empty($ref)) || !empty($projectidforalltimes)) { // Not a dedicated task print ''; - print $task_time->label; + print dol_escape_htmltag($task_time->label); print ''; } } // User if (!empty($arrayfields['author']['checked'])) { - print ''; + print ''; if ($action == 'splitline' && GETPOST('lineid', 'int') == $task_time->rowid) { if (empty($object->id)) { $object->fetch($id); @@ -2711,6 +2743,12 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser print ''; } + // Product + if (!empty($arrayfields['t.fk_product']['checked'])) { + print ''; + print ''; + } + // Value spent if (!empty($arrayfields['value']['checked'])) { print ''; diff --git a/test/phpunit/AllTests.php b/test/phpunit/AllTests.php index ba4d743f603..84ea7a42a6e 100644 --- a/test/phpunit/AllTests.php +++ b/test/phpunit/AllTests.php @@ -24,7 +24,7 @@ * \remarks To run this script as CLI: phpunit filename.php */ print "PHP Version: ".phpversion()."\n"; -print "Memory: ". ini_get('memory_limit')."\n"; +print "Memory limit: ". ini_get('memory_limit')."\n"; global $conf,$user,$langs,$db; //define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver diff --git a/test/phpunit/CategorieTest.php b/test/phpunit/CategorieTest.php index 3bd870914e3..1faab723bb2 100644 --- a/test/phpunit/CategorieTest.php +++ b/test/phpunit/CategorieTest.php @@ -259,11 +259,12 @@ class CategorieTest extends PHPUnit\Framework\TestCase $langs=$this->savlangs; $db=$this->savdb; - $localobject->note='New note after update'; + $localobject->note_private ='New note after update'; $result=$localobject->update($user); print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertGreaterThan(0, $result); + return $localobject; } @@ -288,8 +289,6 @@ class CategorieTest extends PHPUnit\Framework\TestCase print __METHOD__." id=".$localobject->id." result=".$result."\n"; $this->assertLessThan($result, 0); */ - $localobject2=new Categorie($db); - $localobject2->initAsSpecimen(); $retarray=$localobject->liste_photos('/'); print __METHOD__." retarray size=".count($retarray)."\n"; diff --git a/test/phpunit/MouvementStockTest.php b/test/phpunit/MouvementStockTest.php index a781ea78e12..d084f50d6e0 100644 --- a/test/phpunit/MouvementStockTest.php +++ b/test/phpunit/MouvementStockTest.php @@ -146,41 +146,44 @@ class MouvementStockTest extends PHPUnit\Framework\TestCase // We create a product for tests $product0=new Product($db); $product0->initAsSpecimen(); - $product0->ref.=' 0'; - $product0->label.=' 0'; + $product0->ref.=' phpunit 0'; + $product0->label.=' phpunit 0'; $product0->status_batch = 1; $product0id=$product0->create($user); + print __METHOD__." product0id=".$product0id."\n"; + $this->assertGreaterThan(0, $product0id, 'Failed to create product'); + $product1=new Product($db); $product1->initAsSpecimen(); - $product1->ref.=' 1'; - $product1->label.=' 1'; + $product1->ref.=' phpunit 1'; + $product1->label.=' phpunit 1'; $product1id=$product1->create($user); $product2=new Product($db); $product2->initAsSpecimen(); - $product2->ref.=' 2'; - $product2->label.=' 2'; + $product2->ref.=' phpunit 2'; + $product2->label.=' phpunit 2'; $product2id=$product2->create($user); // We create a product for tests $warehouse0=new Entrepot($db); $warehouse0->initAsSpecimen(); - $warehouse0->label.=' 0'; - $warehouse0->description.=' 0'; + $warehouse0->label.=' phpunit 0'; + $warehouse0->description.=' phpunit 0'; $warehouse0->statut = 0; $warehouse0id=$warehouse0->create($user); $warehouse1=new Entrepot($db); $warehouse1->initAsSpecimen(); - $warehouse1->label.=' 1'; - $warehouse1->description.=' 1'; + $warehouse1->label.=' phpunit 1'; + $warehouse1->description.=' phpunit 1'; $warehouse1id=$warehouse1->create($user); $warehouse2=new Entrepot($db); $warehouse2->initAsSpecimen(); - $warehouse2->label.=' 2'; - $warehouse2->description.=' 2'; + $warehouse2->label.=' phpunit 2'; + $warehouse2->description.=' phpunit 2'; $warehouse2id=$warehouse2->create($user); $localobject=new MouvementStock($this->savdb); @@ -188,10 +191,10 @@ class MouvementStockTest extends PHPUnit\Framework\TestCase $datetest1 = dol_mktime(0, 0, 0, 1, 1, 2000); $datetest2 = dol_mktime(0, 0, 0, 1, 2, 2000); - // Create an input movement movement (type = 3) with value for eatby date and a lot + // Create an input movement movement (type = 3) with value for eatby date and a lot $datetest1 $result=$localobject->reception($user, $product0id, $warehouse0id, 5, 999, 'Movement for unit test with batch', $datetest1, $datetest1, 'anotyetuselotnumberA', '', 0, 'Inventory Code Test with batch'); print __METHOD__." result=".$result."\n"; - $this->assertGreaterThan(0, $result, 'Failed to create a movement with a lot number of product with status_batch=1'); + $this->assertGreaterThan(0, $result, 'Failed to create a movement with a lot number '.$datetest1.' for product id='.$product0id.' with status_batch=1'); $result=$localobject->reception($user, $product0id, $warehouse0id, 5, 999, 'Movement for unit test with batch', $datetest1, $datetest1, 'anotyetuselotnumberB', '', 0, 'Inventory Code Test with batch'); print __METHOD__." result=".$result."\n"; @@ -250,12 +253,12 @@ class MouvementStockTest extends PHPUnit\Framework\TestCase // Create an output movement (type = 1) of price 9.7 -> should update PMP to 9.9/9.7 = 9.8 $result=$localobject->_create($user, $product1id, $warehouse2id, 1, 0, 0, 'Input from transfer wh 2', 'Transfert X 2'); print __METHOD__." result=".$result."\n"; - $this->assertGreaterThan(0, $result); + $this->assertGreaterThan(0, $result, 'Test create A'); // Create an output movement (type = 1) of price 9.7 -> should update PMP to 9.9/9.7 = 9.8 $result=$localobject->_create($user, $product1id, $warehouse2id, -2, 1, 0, 'Output from transfer wh 2', 'Transfert Y 2'); print __METHOD__." result=".$result."\n"; - $this->assertGreaterThan(0, $result); + $this->assertGreaterThan(0, $result, 'Test create B'); return $localobject; }