Merge remote-tracking branch 'upstream/develop' into 18a5

This commit is contained in:
Alexandre SPANGARO 2023-04-12 11:26:16 +02:00
commit 1ee7a525f1
41 changed files with 775 additions and 352 deletions

View File

@ -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

View File

@ -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)<br>";
print "admin/modules.php Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)<br>";
}
} catch (Exception $e) {
dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR);

View File

@ -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 '<br>';
//}
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
@ -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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module30Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module25Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module80Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).'</span>';
}
print "</td>\n</tr>\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 '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")).'</span>';
}
print "</td>\n</tr>\n";
$found++;

View File

@ -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;

View File

@ -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';
}

View File

@ -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;
}
}

View File

@ -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)
|| (

View File

@ -5087,21 +5087,21 @@ class Form
* print '});'."\n";
* print '</script>'."\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 <form> 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 <form> 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')
{

View File

@ -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)) {

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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");

View File

@ -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.'<br>'."\n";

View File

@ -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 '<th class="linecolmargin1 margininfos right" style="width: 80px">'.$langs->trans('BuyingPrice').'</th>';
print '<th class="linecolmargin1 margininfos right width75">'.$langs->trans('BuyingPrice').'</th>';
} else {
print '<th class="linecolmargin1 margininfos right" style="width: 80px">'.$langs->trans('CostPrice').'</th>';
print '<th class="linecolmargin1 margininfos right width75">'.$langs->trans('CostPrice').'</th>';
}
}
if (!empty($conf->global->DISPLAY_MARGIN_RATES) && $user->rights->margins->liretous) {
print '<th class="linecolmargin2 margininfos right" style="width: 50px">'.$langs->trans('MarginRate');
print '<th class="linecolmargin2 margininfos right width75">'.$langs->trans('MarginRate');
if ($user->hasRight("propal", "creer")) {
print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?mode=marginforalllines&id='.$object->id.'">'.img_edit($langs->trans("UpdateForAllLines"), 0, 'class="clickmarginforalllines opacitymedium paddingleft cursorpointer"').'</a>';
if (GETPOST('mode', 'aZ09') == 'marginforalllines') {
@ -154,7 +154,7 @@ if ($usemargins && isModEnabled('margin') && empty($user->socid)) {
print '</th>';
}
if (!empty($conf->global->DISPLAY_MARK_RATES) && $user->rights->margins->liretous) {
print '<th class="linecolmargin2 margininfos right" style="width: 50px">'.$langs->trans('MarkRate').'</th>';
print '<th class="linecolmargin2 margininfos right width75">'.$langs->trans('MarkRate').'</th>';
}
}

View File

@ -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 .= '<br>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 .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/'.dol_escape_htmltag($regexoptions).' into '.strtolower($sourcefield).' -> found '.dol_escape_htmltag(dol_trunc($object->$tmpproperty, 128));
} else {
$operationslog .= '<br>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 .= '<br>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 .= '<br>Set value '.dol_escape_htmltag($valuetouse).' into variable '.dol_escape_htmltag($tmpproperty);
$operationslog .= '<br>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 .= '<br>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 .= '<br>* 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 .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found idtouseforthirdparty='.dol_escape_htmltag($idtouseforthirdparty);
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found emailtouseforthirdparty='.dol_escape_htmltag($emailtouseforthirdparty);
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
$operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.' Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Found namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
} else {
$operationslog .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> We discard this, not used to search existing thirdparty';
$operationslog .= '<br>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 .= '<br>Regex /'.dol_escape_htmltag($regexstring).'/ms into '.strtoupper($sourcefield).' -> Not found';
$operationslog .= '<br>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 .= '<br>We set property idtouseforthrdparty='.dol_escape_htmltag($idtouseforthirdparty);
$operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.'We set property idtouseforthrdparty='.dol_escape_htmltag($idtouseforthirdparty);
} elseif ($propertytooverwrite == 'email') {
$emailtouseforthirdparty = $reg[2];
$operationslog .= '<br>We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty);
$operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.'We set property emailtouseforthrdparty='.dol_escape_htmltag($emailtouseforthirdparty);
} elseif ($propertytooverwrite == 'name') {
$nametouseforthirdparty = $reg[2];
$operationslog .= '<br>We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
$operationslog .= '<br>propertytooverwrite='.$propertytooverwrite.'We set property nametouseforthirdparty='.dol_escape_htmltag($nametouseforthirdparty);
} elseif ($propertytooverwrite == 'name_alias') {
$namealiastouseforthirdparty = $reg[2];
$operationslog .= '<br>We set property namealiastouseforthirdparty='.dol_escape_htmltag($namealiastouseforthirdparty);
$operationslog .= '<br>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 .= '<br>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 .= '<br>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 .= '<br>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 .= '<br>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;
}

View File

@ -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 .= '<br>'.$langs->trans("StockMovementWillBeRecorded").'.';
} elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
$text .= '<br>'.$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 '<td class="linecolqtyinothershipments center nowrap">';
$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 '<br>';
$htmltooltip .= '<br>';
}
$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 .= '<br>'.$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 '</td>';
}
@ -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).'<br>';
$detail .= $langs->trans("DetailWarehouseFormat", $entrepot->label, $detail_entrepot->qty_shipped).'<br>';
}
}
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, '');
}
}
}

View File

@ -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;

View File

@ -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 <span class="opacitymedium">('.$langs->trans("Service").')</span>';
}
print ($objp->unit_order ? ' '.$objp->unit_order : '').'</td>';

View File

@ -2031,6 +2031,7 @@ if ($action == 'create') {
print '<input type="hidden" name="id" value="'.$object->id.'">';
print '<input type="hidden" name="fk_expensereport" value="'.$object->id.'" />';
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
print '<input type="hidden" name="page_y" value="">';
print '<div class="div-table-responsive-no-min">';
print '<table id="tablelines" class="noborder centpercent">';
@ -2049,7 +2050,7 @@ if ($action == 'create') {
if (!empty($conf->global->MAIN_USE_EXPENSE_IK)) {
print '<td class="center linecolcarcategory">'.$langs->trans('CarCategory').'</td>';
}
print '<td class="center linecoldescription">'.$langs->trans('Description').'</td>';
print '<td class="linecoldescription">'.$langs->trans('Description').'</td>';
print '<td class="right linecolvat">'.$langs->trans('VAT').'</td>';
print '<td class="right linecolpriceuht">'.$langs->trans('PriceUHT').'</td>';
print '<td class="right linecolpriceuttc">'.$langs->trans('PriceUTTC').'</td>';
@ -2088,7 +2089,7 @@ if ($action == 'create') {
// Project
if (isModEnabled('project')) {
print '<td class="center dateproject">';
print '<td class="lineproject">';
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 '<td>'.$langs->trans('CarCategory').'</td>';
}
print '<td class="right expensereportcreatedescription">'.$langs->trans('Description').'</td>';
print '<td class="expensereportcreatedescription">'.$langs->trans('Description').'</td>';
print '<td class="right expensereportcreatevat">'.$langs->trans('VAT').'</td>';
print '<td class="right expensereportcreatepriceuth">'.$langs->trans('PriceUHT').'</td>';
print '<td class="right expensereportcreatepricettc">'.$langs->trans('PriceUTTC').'</td>';
@ -2562,7 +2563,7 @@ if ($action == 'create') {
}
print '<td class="center inputbuttons">';
print $form->buttonsSaveCancel("Add", '', '', 1);
print $form->buttonsSaveCancel("Add", '', '', 1, 'reposition');
print '</td>';
print '</tr>';

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2312,7 +2312,9 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
}
$dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
$dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
if (isModEnabled('multicurrency')) {
$dropdownBody .= '<br><b>'.$langs->trans("Currency").'</b>: <span>'.$conf->currency.'</span>';
}
$dropdownBody .= '</div>';
$dropdownBody .= '<br>';

View File

@ -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++;

View File

@ -6,6 +6,7 @@
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2019 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2021 Noé Cendrier <noe.cendrier@altairis.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -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 '<input type="hidden" name="mode" value="'.$mode.'">';
print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit, 0, 0, 1);
/*
if ($search_categ > 0) {
print "<div id='ways'>";
$c = new Categorie($db);
@ -517,17 +539,27 @@ if ($search_categ > 0) {
print " &gt; ".$ways[0]."<br>\n";
print "</div><br>";
}
*/
// Filter on categories
$moreforfilter = '';
if (isModEnabled('categorie')) {
$moreforfilter .= '<div class="divsearchfield">';
$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 .= '</div>';
}
// Filter on warehouse categories
if (isModEnabled('categorie')) {
$moreforfilter .= '<div class="divsearchfield">';
$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 .= '</div>';
}
$moreforfilter.='<label for="search_subjecttolotserial">'.$langs->trans("SubjectToLotSerialOnly").' </label><input type="checkbox" id="search_subjecttolotserial" name="search_subjecttolotserial" value="1"'.($search_subjecttolotserial?' checked':'').'>';
if (!empty($moreforfilter)) {
print '<div class="liste_titre liste_titre_bydiv centpercent">';
print $moreforfilter;

View File

@ -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)
{

View File

@ -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 '</div><br>';
}
$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 '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<input type="hidden" name="type" value="'.$type.'">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
print '<input type="hidden" name="page_y" value="">';
print '<input type="hidden" name="mode" value="'.$mode.'">';
if ($id > 0) {
print '<input type="hidden" name="id" value="'.$id.'">';
}
$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 '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall).join(', ', $fieldstosearchall).'</div>';
print '<!-- Search done like if STOCK_QUICKSEARCH_ON_FIELDS = '.$setupstring.' -->'."\n";
print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'</div>'."\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 '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
@ -1073,6 +1099,13 @@ print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwit
// Fields title search
// --------------------------------------------------------------------
print '<tr class="liste_titre">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center maxwidthsearch">';
$searchpicto = $form->showFilterButtons('left');
print $searchpicto;
print '</td>';
}
if (!empty($arrayfields['m.rowid']['checked'])) {
// Ref
print '<td class="liste_titre left">';
@ -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 '</td>';
}
// Action column
print '<td class="liste_titre maxwidthsearch">';
$searchpicto = $form->showFilterButtons();
print $searchpicto;
print '</td>';
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center maxwidthsearch">';
$searchpicto = $form->showFilterButtons();
print $searchpicto;
print '</td>';
}
print '</tr>'."\n";
$totalarray = array();
$totalarray['nbfield'] = 0;
// Fields title label
// --------------------------------------------------------------------
print '<tr class="liste_titre">';
// 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 '</tr>'."\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 '<tr class="oddeven">';
// Id movement
if (!empty($arrayfields['m.rowid']['checked'])) {
print '<td class="nowraponall">';
print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
print $obj->mid;
print '</td>'; // This is primary not movement id
}
if (!empty($arrayfields['m.datem']['checked'])) {
// Date
print '<td class="nowraponall center">'.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').'</td>';
}
if (!empty($arrayfields['p.ref']['checked'])) {
// Product ref
print '<td class="nowraponall">';
print $productstatic->getNomUrl(1, 'stock', 16);
print "</td>\n";
}
if (!empty($arrayfields['p.label']['checked'])) {
// Product label
print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($productstatic->label).'">';
print $productstatic->label;
print "</td>\n";
}
if (!empty($arrayfields['m.batch']['checked'])) {
print '<td class="center nowraponall">';
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 '<tr><td colspan="'.$savnbfield.'">';
print '<div class="box-flex-container kanban">';
}
print '</td>';
}
if (!empty($arrayfields['pl.eatby']['checked'])) {
print '<td class="center">'.dol_print_date($obj->eatby, 'day').'</td>';
}
if (!empty($arrayfields['pl.sellby']['checked'])) {
print '<td class="center">'.dol_print_date($obj->sellby, 'day').'</td>';
}
// Warehouse
if (!empty($arrayfields['e.ref']['checked'])) {
print '<td class="tdoverflowmax100">';
print $warehousestatic->getNomUrl(1);
print "</td>\n";
}
// Author
if (!empty($arrayfields['m.fk_user_author']['checked'])) {
print '<td class="tdoverflowmax100">';
print $userstatic->getNomUrl(-1);
print "</td>\n";
}
if (!empty($arrayfields['m.inventorycode']['checked'])) {
// Inventory code
print '<td><a href="'.$_SERVER["PHP_SELF"].'?search_inventorycode='.urlencode('^'.$obj->inventorycode.'$').'&search_type_mouvement='.urlencode($obj->type_mouvement).'">'.$obj->inventorycode.'</a></td>';
}
if (!empty($arrayfields['m.label']['checked'])) {
// Label of movement
print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($obj->label).'">'.$obj->label.'</td>';
}
if (!empty($arrayfields['origin']['checked'])) {
// Origin of movement
print '<td class="nowraponall">'.$origin.'</td>';
}
if (!empty($arrayfields['m.fk_projet']['checked'])) {
// fk_project
print '<td>';
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 '</td>';
}
if (!empty($arrayfields['m.type_mouvement']['checked'])) {
// Type of movement
print '<td class="center">';
print $movement->getTypeMovement();
print '</td>';
}
if (!empty($arrayfields['m.value']['checked'])) {
// Qty
print '<td class="right">';
if ($obj->qty > 0) {
print '<span class="stockmovemententry">';
print '+';
print $obj->qty;
print '</span>';
} else {
print '<span class="stockmovementexit">';
print $obj->qty;
print '</span>';
print $object->getKanbanView('');
if ($i == ($imaxinloop - 1)) {
print '</div>';
print '</td></tr>';
}
print '</td>';
}
if (!empty($arrayfields['m.price']['checked'])) {
// Price
print '<td class="right">';
if ($obj->price != 0) {
print price($obj->price);
} else {
// Show here line of result
$j = 0;
print '<tr data-rowid="'.$object->id.'" class="oddeven">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="nowrap center">';
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 '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
}
print '</td>';
if (!$i) {
$totalarray['nbfield']++;
}
}
// Id movement
if (!empty($arrayfields['m.rowid']['checked'])) {
print '<td class="nowraponall">';
print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
print $obj->mid;
print '</td>'; // This is primary not movement id
}
if (!empty($arrayfields['m.datem']['checked'])) {
// Date
print '<td class="nowraponall center">'.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').'</td>';
}
if (!empty($arrayfields['p.ref']['checked'])) {
// Product ref
print '<td class="nowraponall">';
print $productstatic->getNomUrl(1, 'stock', 16);
print "</td>\n";
}
if (!empty($arrayfields['p.label']['checked'])) {
// Product label
print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($productstatic->label).'">';
print $productstatic->label;
print "</td>\n";
}
if (!empty($arrayfields['m.batch']['checked'])) {
print '<td class="center nowraponall">';
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 '</td>';
}
if (!empty($arrayfields['pl.eatby']['checked'])) {
print '<td class="center">'.dol_print_date($obj->eatby, 'day').'</td>';
}
if (!empty($arrayfields['pl.sellby']['checked'])) {
print '<td class="center">'.dol_print_date($obj->sellby, 'day').'</td>';
}
// Warehouse
if (!empty($arrayfields['e.ref']['checked'])) {
print '<td class="tdoverflowmax100">';
print $warehousestatic->getNomUrl(1);
print "</td>\n";
}
// Author
if (!empty($arrayfields['m.fk_user_author']['checked'])) {
print '<td class="tdoverflowmax100">';
print $userstatic->getNomUrl(-1);
print "</td>\n";
}
if (!empty($arrayfields['m.inventorycode']['checked'])) {
// Inventory code
print '<td><a href="'.$_SERVER["PHP_SELF"].'?search_inventorycode='.urlencode('^'.$obj->inventorycode.'$').'&search_type_mouvement='.urlencode($obj->type_mouvement).'">'.$obj->inventorycode.'</a></td>';
}
if (!empty($arrayfields['m.label']['checked'])) {
// Label of movement
print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($obj->label).'">'.$obj->label.'</td>';
}
if (!empty($arrayfields['origin']['checked'])) {
// Origin of movement
print '<td class="nowraponall">'.$origin.'</td>';
}
if (!empty($arrayfields['m.fk_projet']['checked'])) {
// fk_project
print '<td>';
if ($obj->fk_project != 0) {
print $movement->get_origin($obj->fk_project, 'project');
}
print '</td>';
}
if (!empty($arrayfields['m.type_mouvement']['checked'])) {
// Type of movement
print '<td class="center">';
print $movement->getTypeMovement();
print '</td>';
}
if (!empty($arrayfields['m.value']['checked'])) {
// Qty
print '<td class="right">';
if ($obj->qty > 0) {
print '<span class="stockmovemententry">';
print '+';
print $obj->qty;
print '</span>';
} else {
print '<span class="stockmovementexit">';
print $obj->qty;
print '</span>';
}
print '</td>';
}
if (!empty($arrayfields['m.price']['checked'])) {
// Price
print '<td class="right">';
if ($obj->price != 0) {
print price($obj->price);
}
print '</td>';
}
print '</td>';
}
// 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 '<td class="nowrap center">';
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 '<td class="nowrap center">';
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 '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
}
print '</td>';
if (!$i) {
$totalarray['nbfield']++;
}
}
print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
}
print '</td>';
if (!$i) {
$totalarray['nbfield']++;
}
print '</tr>'."\n";
print '</tr>'."\n";
}
$i++;
}
// If no record found
if ($num == 0) {
$colspan = 1;
foreach ($arrayfields as $key => $val) {
if (!empty($val['checked'])) {
$colspan++;
}
}
print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
}
$db->free($resql);
print "</table>";
print '</div>';
print "</form>";
$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 '</table>'."\n";
print '</div>'."\n";
print '</form>'."\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

View File

@ -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 ' <span class="opacitymedium"> '.$langs->trans("to").' </span> ';
print $form->selectDate($object->date_end ? $object->date_end : -1, 'projectend', 0, 0, 0, '', 1, 0);
print ' &nbsp; &nbsp; <input type="checkbox" class="valignmiddle" id="reportdate" name="reportdate" value="yes" ';
if ($comefromclone) {
print ' checked ';
$object->getLinesArray(null, 0);
if (!empty($object->usage_task) && !empty($object->lines)) {
print ' <span id="divreportdate" class="hidden">&nbsp; &nbsp; <input type="checkbox" class="valignmiddle" id="reportdate" name="reportdate" value="yes" ';
if ($comefromclone) {
print 'checked ';
}
print '/><label for="reportdate" class="valignmiddle opacitymedium">'.$langs->trans("ProjectReportDate").'</label></span>';
}
print '/><label for="reportdate" class="opacitymedium">'.$langs->trans("ProjectReportDate").'</label>';
print '</td></tr>';
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();
});
});
</script>';

View File

@ -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)
{

View File

@ -1858,8 +1858,8 @@ while ($i < $imaxinloop) {
}
// Email MsgID
if (!empty($arrayfields['p.email_msgid']['checked'])) {
print '<td class="center">';
print $obj->email_msgid;
print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($obj->email_msgid).'">';
print dol_escape_htmltag($obj->email_msgid);
print '</td>';
if (!$i) $totalarray['nbfield']++;
}

View File

@ -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 '</td>';
if ($conf->service->enabled && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
print '<td class="nowrap">';
print $form->select_produits('', 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
print '<td class="nowraponall">';
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 '</td>';
}
}
@ -1843,7 +1844,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
print '<td class="center">';
$form->buttonsSaveCancel();
print '<input type="submit" name="save" class="button buttongen marginleftonly margintoponlyshort marginbottomonlyshort button-add" value="'.$langs->trans("Add").'">';
print '<input type="submit" name="save" class="button buttongen marginleftonly margintoponlyshort marginbottomonlyshort button-add reposition" value="'.$langs->trans("Add").'">';
print '<input type="submit" name="cancel" class="button buttongen marginleftonly margintoponlyshort marginbottomonlyshort button-cancel" value="'.$langs->trans("Cancel").'">';
print '</td></tr>';
@ -2149,7 +2150,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
// Thirdparty
if (!empty($arrayfields['p.fk_soc']['checked'])) {
print '<td class="nowrap tdoverflowmax150">';
print '<td class="tdoverflowmax125">';
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 '<td class="nowraponall">';
print '<td class="nowraponall tdoverflowmax125">';
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 '<td class="center nowraponall">';
if (($action == 'editline' || $action == 'splitline') && GETPOST('lineid', 'int') == $task_time->rowid) {
print '<input type="hidden" name="lineid" value="'.GETPOST('lineid', 'int').'">';
print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-save" name="save" value="'.$langs->trans("Save").'">';
print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-save small" name="save" value="'.$langs->trans("Save").'">';
print ' ';
print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
print '<input type="submit" class="button buttongen margintoponlyshort marginbottomonlyshort button-cancel small" name="cancel" value="'.$langs->trans("Cancel").'">';
} 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 '<!-- first line -->';
print '<tr class="oddeven">';
// Date
@ -2491,6 +2493,18 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
print '</td>';
}
// Thirdparty
if (!empty($arrayfields['p.fk_soc']['checked'])) {
print '<td class="nowrap">';
print '</td>';
}
// Thirdparty alias
if (!empty($arrayfields['s.name_alias']['checked'])) {
print '<td class="nowrap">';
print '</td>';
}
// 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 '<td>';
print '<td class="nowraponall">';
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 '</td>';
}
// Product
if (!empty($arrayfields['t.fk_product']['checked'])) {
print '<td class="nowraponall tdoverflowmax125">';
print '</td>';
}
// Value spent
if (!empty($arrayfields['value']['checked'])) {
print '<td class="right">';
@ -2612,7 +2632,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
// Line for second dispatching
print '<tr class="oddeven">';
print '<!-- second line --><tr class="oddeven">';
// Date
if (!empty($arrayfields['t.element_date']['checked'])) {
@ -2629,6 +2649,18 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
print '</td>';
}
// Thirdparty
if (!empty($arrayfields['p.fk_soc']['checked'])) {
print '<td class="nowrap">';
print '</td>';
}
// Thirdparty alias
if (!empty($arrayfields['s.name_alias']['checked'])) {
print '<td class="nowrap">';
print '</td>';
}
// 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 '<td class="nowrap">';
print $task_time->label;
print dol_escape_htmltag($task_time->label);
print '</td>';
}
}
// User
if (!empty($arrayfields['author']['checked'])) {
print '<td>';
print '<td class="nowraponall">';
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 '</td>';
}
// Product
if (!empty($arrayfields['t.fk_product']['checked'])) {
print '<td class="nowraponall tdoverflowmax125">';
print '</td>';
}
// Value spent
if (!empty($arrayfields['value']['checked'])) {
print '<td class="right">';

View File

@ -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

View File

@ -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";

View File

@ -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;
}