Merge remote-tracking branch 'upstream/develop' into 13b1

This commit is contained in:
Alexandre SPANGARO 2020-12-16 04:32:26 +01:00
commit ca6b8176e9
46 changed files with 587 additions and 298 deletions

View File

@ -18,6 +18,7 @@ NEW: Accountancy - change menu disposition
NEW: Accountancy - on transfers, select the periodicity by default
NEW: Accountancy - Add export for Gestinum (v3 & v5)
NEW: new currency rate editor
NEW: Solve blocking feature. Can increase stock of a Kit without changing subproduct stock.
NEW: add a widget to show the customers with outstanding limits reached
NEW: add 2 rules for emailcollector: Message send/not sent from Dolibarr
NEW: add a counter of number of words for pages in website module

View File

@ -642,6 +642,7 @@ if (empty($reshook)) {
$newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param, '', 1, array('morecss' => 'marginleftonly'));
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbysubaccount.php', '', 1, array('morecss' => 'marginleftonly'));
$url = './card.php?action=create';
if (!empty($socid)) $url .= '&socid='.$socid;

View File

@ -39,8 +39,14 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
$langs->loadLangs(array("accountancy", "compta"));
$action = GETPOST('action', 'aZ09');
$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
$search_date_end = dol_mktime(0, 0, 0, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
$search_date_startyear = GETPOST('search_date_startyear', 'int');
$search_date_startmonth = GETPOST('search_date_startmonth', 'int');
$search_date_startday = GETPOST('search_date_startday', 'int');
$search_date_endyear = GETPOST('search_date_endyear', 'int');
$search_date_endmonth = GETPOST('search_date_endmonth', 'int');
$search_date_endday = GETPOST('search_date_endday', 'int');
$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);
$search_date_end = dol_mktime(0, 0, 0, $search_date_endmonth, $search_date_endday, $search_date_endyear);
$search_doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$search_accountancy_code = GETPOST("search_accountancy_code");
@ -126,9 +132,24 @@ $arrayfields = array(
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) unset($arrayfields['t.lettering_code']);
if ($search_date_start && empty($search_date_startyear)) {
$tmparray = dol_getdate($search_date_start);
$search_date_startyear = $tmparray['year'];
$search_date_startmonth = $tmparray['mon'];
$search_date_startday = $tmparray['mday'];
}
if ($search_date_end && empty($search_date_endyear)) {
$tmparray = dol_getdate($search_date_end);
$search_date_endyear = $tmparray['year'];
$search_date_endmonth = $tmparray['mon'];
$search_date_endday = $tmparray['mday'];
}
/*
* Action
*/
if (GETPOST('cancel', 'alpha')) { $action = 'list'; $massaction = ''; }
if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction = ''; }
@ -172,11 +193,11 @@ if (empty($reshook))
if (!empty($search_date_start)) {
$filter['t.doc_date>='] = $search_date_start;
$param .= '&search_date_startmonth='.GETPOST('search_date_startmonth', 'int').'&search_date_startday='.GETPOST('search_date_startday', 'int').'&search_date_startyear='.GETPOST('search_date_startyear', 'int');
$param .= '&search_date_startmonth='.$search_date_startmonth.'&search_date_startday='.$search_date_startday.'&search_date_startyear='.$search_date_startyear;
}
if (!empty($search_date_end)) {
$filter['t.doc_date<='] = $search_date_end;
$param .= '&search_date_endmonth='.GETPOST('search_date_endmonth', 'int').'&search_date_endday='.GETPOST('search_date_endday', 'int').'&search_date_endyear='.GETPOST('search_date_endyear', 'int');
$param .= '&search_date_endmonth='.$search_date_endmonth.'&search_date_endday='.$search_date_endday.'&search_date_endyear='.$search_date_endyear;
}
if (!empty($search_doc_date)) {
$filter['t.doc_date'] = $search_doc_date;
@ -242,7 +263,7 @@ if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->suppri
}
// Make a redirect to avoid to launch the delete later after a back button
header("Location: listbyaccount.php".($param ? '?'.$param : ''));
header("Location: ".$_SERVER["PHP_SELF"].($param ? '?'.$param : ''));
exit;
}
}
@ -267,7 +288,7 @@ if ($action == 'delbookkeepingyearconfirm' && $user->rights->accounting->mouveme
}
// Make a redirect to avoid to launch the delete later after a back button
header("Location: listbyaccount.php".($param ? '?'.$param : ''));
header("Location: ".$_SERVER["PHP_SELF"].($param ? '?'.$param : ''));
exit;
} else {
setEventMessages("NoRecordDeleted", null, 'warnings');
@ -284,7 +305,7 @@ if ($action == 'delmouvconfirm' && $user->rights->accounting->mouvements->suppri
setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs');
}
header("Location: listbyaccount.php?noreset=1".($param ? '&'.$param : ''));
header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : ''));
exit;
}
}
@ -303,7 +324,6 @@ $title_page = $langs->trans("Operations").' - '.$langs->trans("VueByAccountAccou
llxHeader('', $title_page);
// List
$nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
@ -380,10 +400,8 @@ $parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$newcardbutton = dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param);
$newcardbutton .= dolGetButtonTitle($langs->trans('VueBySubAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbysubaccount.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton .= ' &nbsp; ';
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbysubaccount.php', '', 1, array('morecss' => 'marginleftonly'));
$newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?action=create');
}

View File

@ -39,8 +39,14 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
$langs->loadLangs(array("accountancy", "compta"));
$action = GETPOST('action', 'aZ09');
$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
$search_date_end = dol_mktime(0, 0, 0, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
$search_date_startyear = GETPOST('search_date_startyear', 'int');
$search_date_startmonth = GETPOST('search_date_startmonth', 'int');
$search_date_startday = GETPOST('search_date_startday', 'int');
$search_date_endyear = GETPOST('search_date_endyear', 'int');
$search_date_endmonth = GETPOST('search_date_endmonth', 'int');
$search_date_endday = GETPOST('search_date_endday', 'int');
$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);
$search_date_end = dol_mktime(0, 0, 0, $search_date_endmonth, $search_date_endday, $search_date_endyear);
$search_doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$search_accountancy_code = GETPOST("search_accountancy_code");
@ -126,6 +132,20 @@ $arrayfields = array(
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) unset($arrayfields['t.lettering_code']);
if ($search_date_start && empty($search_date_startyear)) {
$tmparray = dol_getdate($search_date_start);
$search_date_startyear = $tmparray['year'];
$search_date_startmonth = $tmparray['mon'];
$search_date_startday = $tmparray['mday'];
}
if ($search_date_end && empty($search_date_endyear)) {
$tmparray = dol_getdate($search_date_end);
$search_date_endyear = $tmparray['year'];
$search_date_endmonth = $tmparray['mon'];
$search_date_endday = $tmparray['mday'];
}
/*
* Action
*/
@ -172,11 +192,11 @@ if (empty($reshook))
if (!empty($search_date_start)) {
$filter['t.doc_date>='] = $search_date_start;
$param .= '&search_date_startmonth='.GETPOST('search_date_startmonth', 'int').'&search_date_startday='.GETPOST('search_date_startday', 'int').'&search_date_startyear='.GETPOST('search_date_startyear', 'int');
$param .= '&search_date_startmonth='.$search_date_startmonth.'&search_date_startday='.$search_date_startday.'&search_date_startyear='.$search_date_startyear;
}
if (!empty($search_date_end)) {
$filter['t.doc_date<='] = $search_date_end;
$param .= '&search_date_endmonth='.GETPOST('search_date_endmonth', 'int').'&search_date_endday='.GETPOST('search_date_endday', 'int').'&search_date_endyear='.GETPOST('search_date_endyear', 'int');
$param .= '&search_date_endmonth='.$search_date_endmonth.'&search_date_endday='.$search_date_endday.'&search_date_endyear='.$search_date_endyear;
}
if (!empty($search_doc_date)) {
$filter['t.doc_date'] = $search_doc_date;
@ -242,7 +262,7 @@ if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->suppri
}
// Make a redirect to avoid to launch the delete later after a back button
header("Location: listbyaccount.php".($param ? '?'.$param : ''));
header("Location: ".$_SERVER["PHP_SELF"].($param ? '?'.$param : ''));
exit;
}
}
@ -380,7 +400,10 @@ print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$newcardbutton = dolGetButtonTitle($langs->trans('ViewAccountList'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php', '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton = dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param);
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php', '', 1, array('morecss' => 'marginleftonly'));
$newcardbutton .= dolGetButtonTitle($langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/listbysubaccount.php', '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?action=create');
}
@ -389,6 +412,8 @@ if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($l
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $result, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit);
print info_admin($langs->trans("WarningRecordWithoutSubledgerAreExcluded"));
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
if ($massactionbutton) $selectedfields .= $form->showCheckAddButtons('checkforselect', 1);
@ -554,8 +579,16 @@ while ($i < min($num, $limit))
// Show the break account
print "<tr>";
print '<td colspan="'.($totalarray['nbfield'] ? $totalarray['nbfield'] : 9).'" style="font-weight:bold; border-bottom: 1pt solid black;">';
if ($line->subledger_account != "" && $line->subledger_account != '-1') print length_accounta($line->subledger_account).' : '.$object->get_compte_desc($line->numero_compte);
else print '<span class="error">'.$langs->trans("Unknown").'</span>';
if ($line->subledger_account != "" && $line->subledger_account != '-1') {
print $object->get_compte_desc($line->numero_compte).' : '.length_accounta($line->subledger_account);
} else {
// Should not happen: subledger account must be null or a non empty value
print '<span class="error">'.$langs->trans("Unknown");
if ($line->subledger_label) print ' ('.$line->subledger_label.')';
$htmltext = 'EmptyStringForSubledgerAccountButSubledgerLabelDefined';
print $form->textwithpicto('', $htmltext);
print '</span>';
}
print '</td>';
print '</tr>';

View File

@ -535,13 +535,14 @@ class Documents extends DolibarrApi
* Test sample for supplier invoice: { "filename": "mynewfile.txt", "modulepart": "supplier_invoice", "ref": "FA1701-001", "subdir": "", "filecontent": "content text", "fileencoding": "", "overwriteifexists": "0" }.
* Test sample for medias file: { "filename": "mynewfile.txt", "modulepart": "medias", "ref": "", "subdir": "image/mywebsite", "filecontent": "Y29udGVudCB0ZXh0Cg==", "fileencoding": "base64", "overwriteifexists": "0" }.
*
* @param string $filename Name of file to create ('FA1705-0123.txt')
* @param string $modulepart Name of module or area concerned by file upload ('facture', 'project', 'project_task', ...)
* @param string $ref Reference of object (This will define subdir automatically and store submited file into it)
* @param string $subdir Subdirectory (Only if ref not provided)
* @param string $filecontent File content (string with file content. An empty file will be created if this parameter is not provided)
* @param string $fileencoding File encoding (''=no encoding, 'base64'=Base 64)
* @param int $overwriteifexists Overwrite file if exists (1 by default)
* @param string $filename Name of file to create ('FA1705-0123.txt')
* @param string $modulepart Name of module or area concerned by file upload ('facture', 'project', 'project_task', ...)
* @param string $ref Reference of object (This will define subdir automatically and store submited file into it)
* @param string $subdir Subdirectory (Only if ref not provided)
* @param string $filecontent File content (string with file content. An empty file will be created if this parameter is not provided)
* @param string $fileencoding File encoding (''=no encoding, 'base64'=Base 64)
* @param int $overwriteifexists Overwrite file if exists (1 by default)
* @param int $createdirifnotexists Create subdirectories if the doesn't exists (1 by default)
* @return string
*
* @throws RestException 400
@ -551,7 +552,7 @@ class Documents extends DolibarrApi
*
* @url POST /upload
*/
public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0)
public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
{
global $db, $conf;
@ -578,6 +579,8 @@ class Documents extends DolibarrApi
// Define $uploadir
$object = null;
$entity = DolibarrApiAccess::$user->entity;
if (empty($entity)) $entity = 1;
if ($ref)
{
$tmpreldir = '';
@ -663,8 +666,7 @@ class Documents extends DolibarrApi
}
}
if (!($object->id > 0))
{
if (!($object->id > 0)) {
throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
}
@ -681,29 +683,32 @@ class Documents extends DolibarrApi
if (empty($upload_dir) || $upload_dir == '/')
{
throw new RestException(500, 'This value of modulepart does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
throw new RestException(500, 'This value of modulepart ('.$modulepart.') does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
}
} else {
if ($modulepart == 'invoice') $modulepart = 'facture';
if ($modulepart == 'member') $modulepart = 'adherent';
$relativefile = $subdir;
$tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
$upload_dir = $tmp['original_file']; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
if (empty($upload_dir) || $upload_dir == '/')
{
throw new RestException(500, 'This value of modulepart does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
if (empty($upload_dir) || $upload_dir == '/') {
if (!empty($tmp['error'])) {
throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
} else {
throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
}
}
}
// $original_file here is still value of filename without any dir.
$upload_dir = dol_sanitizePathName($upload_dir);
if (dol_mkdir($upload_dir) < 0) // needed by products
{
throw new RestException(500, 'Error while trying to create directory.');
if (!empty($createdirifnotexists)) {
if (dol_mkdir($upload_dir) < 0) { // needed by products
throw new RestException(500, 'Error while trying to create directory.');
}
}
$destfile = $upload_dir.'/'.$original_file;
@ -715,8 +720,7 @@ class Documents extends DolibarrApi
throw new RestException(401, 'Directory not exists : '.dirname($destfile));
}
if (!$overwriteifexists && dol_is_file($destfile))
{
if (!$overwriteifexists && dol_is_file($destfile)) {
throw new RestException(500, "File with name '".$original_file."' already exists.");
}

View File

@ -598,6 +598,7 @@ class Propal extends CommonObject
$localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
// Clean vat code
$reg = array();
$vat_src_code = '';
if (preg_match('/\((.*)\)/', $txtva, $reg))
{

View File

@ -492,26 +492,21 @@ class Commande extends CommonOrder
$error++;
}
if (!$error)
{
if (!$error) {
// If stock is incremented on validate order, we must increment it
if ($result >= 0 && !empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
{
if ($result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1) {
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
$langs->load("agenda");
// Loop on each line
$cpt = count($this->lines);
for ($i = 0; $i < $cpt; $i++)
{
if ($this->lines[$i]->fk_product > 0)
{
for ($i = 0; $i < $cpt; $i++) {
if ($this->lines[$i]->fk_product > 0) {
$mouvP = new MouvementStock($this->db);
$mouvP->origin = &$this;
// We decrement stock of product (and sub-products)
$result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("OrderValidatedInDolibarr", $num));
if ($result < 0)
{
if ($result < 0) {
$error++;
$this->error = $mouvP->error;
}
@ -521,16 +516,14 @@ class Commande extends CommonOrder
}
}
if (!$error && !$notrigger)
{
if (!$error && !$notrigger) {
// Call trigger
$result = $this->call_trigger('ORDER_VALIDATE', $user);
if ($result < 0) $error++;
// End call triggers
}
if (!$error)
{
if (!$error) {
$this->oldref = $this->ref;
// Rename directory if dir was a temporary ref

View File

@ -133,7 +133,8 @@ if ($resql) {
print "<center><h2>";
if ($cashcontrol->status != $cashcontrol::STATUS_DRAFT) print $langs->trans("CashControl")." ".$cashcontrol->id;
else print $langs->trans("CashControl")." - ".$langs->trans("Draft");
print "<br>".$langs->trans("DateCreationShort").": ".dol_print_date($cashcontrol->date_creation, 'dayhour')."</h2></center>";
print "<br>".$langs->trans("DateCreationShort").": ".dol_print_date($cashcontrol->date_creation, 'dayhour');
print "</h2></center>";
$invoicetmp = new Facture($db);
@ -156,8 +157,6 @@ if ($resql) {
print_liste_field_titre($arrayfields['b.credit']['label'], $_SERVER['PHP_SELF'], 'b.amount', '', $param, '', $sortfield, $sortorder, 'right ');
print "</tr>\n";
$posconciliatecol = 0;
// Loop on each record
$sign = 1;
$cash = $bank = $cheque = $other = 0;
@ -263,7 +262,7 @@ if ($resql) {
print "</table>";
//$cash = $amountpertype['LIQ'] + $cashcontrol->opening;
$cash = $cash + $cashcontrol->opening;
$cash = price2num($cash + $cashcontrol->opening, 'MT');
print "<div style='text-align: right'><h2>";
print $langs->trans("Cash").": ".price($cash);

View File

@ -261,7 +261,7 @@ if ($action == 'confirm_delete' && !empty($permissiontodelete))
// Remove a line
if ($action == 'confirm_deleteline' && $confirm == 'yes' && !empty($permissiontoadd))
{
if (method_exists('deleteline', $object)) {
if (method_exists($object, 'deleteline')) {
$result = $object->deleteline($user, $lineid); // For backward compatibility
} else {
$result = $object->deleteLine($user, $lineid);

View File

@ -71,7 +71,7 @@ class box_scheduled_jobs extends ModeleBoxes
*/
public function loadBox($max = 5)
{
global $user, $langs, $conf;
global $user, $langs, $conf, $form;
$langs->load("cron");
$this->info_box_head = array('text' => $langs->trans("BoxScheduledJobs", $max));
@ -151,7 +151,7 @@ class box_scheduled_jobs extends ModeleBoxes
);
$this->info_box_contents[$line][] = array(
'td' => 'class="right"',
'textnoformat' => dol_print_date($resultarray[$line][2], "dayhoursec")
'textnoformat' => (empty($resultarray[$line][2]) ? '' : $form->textwithpicto(dol_print_date($resultarray[$line][2], "dayhoursec"), $langs->trans("CurrentTimeZone")))
);
$this->info_box_contents[$line][] = array(
'td' => 'class="right" ',

View File

@ -1215,6 +1215,7 @@ class DolGraph
} else {
$textoflegend = $this->Legend[$i];
}
if ($usecolorvariantforgroupby) {
$newcolor = $this->datacolor[$arrayofgroupslegend[$i]['stacknum']];
// If we change the stack
@ -1243,6 +1244,7 @@ class DolGraph
$bordercolor = 'rgb(' . $newcolor[0] . ', ' . $newcolor[1] . ', ' . $newcolor[2] . ')';
} else { // We do not use a 'group by'
if ($isfunnel) {
$bordercolor == 'null';
if (is_array($this->datacolor[$i])) {
$color = 'rgb(' . $this->datacolor[$i][0] . ', ' . $this->datacolor[$i][1] . ', ' . $this->datacolor[$i][2] . ', 0.9)'; // If datacolor is array(R, G, B)
} else {
@ -1262,9 +1264,9 @@ class DolGraph
if (strpos($tmp, '-') !== false) $bordercolor = '#' . str_replace('-', '', $tmp); // If $val is '-123'
else $bordercolor = 'null'; // If $val is '123' or '#123'
}
$bordercolor == 'null' ? "'rgba(0,0,0,0.2)'" : "'" . $bordercolor . "'";
}
}
$bordercolor == 'null' ? "'rgba(0,0,0,0.2)'" : "'" . $bordercolor . "'";
} else {
$color = 'rgb('.$this->datacolor[$i][0].', '.$this->datacolor[$i][1].', '.$this->datacolor[$i][2].', 0.9)';
$bordercolor = $color;

View File

@ -3611,15 +3611,14 @@ class Form
*
* @param string $selected Id pre-selectionne
* @param string $htmlname Nom de la zone select
* @param string $addjscombo Add js combo
* @return string Code of HTML select to chose tax or not
*/
public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type')
public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
{
global $langs;
$return = '';
$return .= '<select class="flat maxwidth75" id="select_'.$htmlname.'" name="'.$htmlname.'">';
$return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
$options = array(
'HT'=>$langs->trans("HT"),
'TTC'=>$langs->trans("TTC")
@ -3635,6 +3634,7 @@ class Form
$return .= '</option>';
}
$return .= '</select>';
if ($addjscombo) $return .= ajax_combobox('select_'.$htmlname);
return $return;
}

View File

@ -1008,4 +1008,44 @@ class FormCompany extends Form
return $out;
}
/**
* Output html select to select third-party type
*
* @param string $page Page
* @param string $selected Id preselected
* @param string $htmlname Name of HTML select
* @param string $filter optional filters criteras
* @param int $nooutput No print output. Return it only.
* @return void|string
*/
public function formThirdpartyType($page, $selected = '', $htmlname = 'socid', $filter = '', $nooutput = 0)
{
// phpcs:enable
global $langs;
$out = '';
if ($htmlname != "none")
{
$out .= '<form method="post" action="'.$page.'">';
$out .= '<input type="hidden" name="action" value="set_thirdpartytype">';
$out .= '<input type="hidden" name="token" value="'.newToken().'">';
$sortparam = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label.
$out .= $this->selectarray($htmlname, $this->typent_array(0, $filter), $selected, 0, 0, 0, '', 0, 0, 0, $sortparam, '', 1);
$out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
$out .= '</form>';
} else {
if ($selected)
{
$arr = $this->typent_array(0);
$typent = $arr[$selected];
$out .= $typent;
} else {
$out .= "&nbsp;";
}
}
if ($nooutput) return $out;
else print $out;
}
}

View File

@ -2231,7 +2231,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
// Fix modulepart
if ($modulepart == 'users') $modulepart = 'user';
dol_syslog('modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
dol_syslog('dol_check_secure_access_document modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity);
// We define $accessallowed and $sqlprotectagainstexternals
$accessallowed = 0;

View File

@ -33,7 +33,7 @@
* @param string[] $addheaders Array of string to add into header. Example: ('Accept: application/xrds+xml', ....)
* @param string[] $allowedschemes List of schemes that are allowed ('http' + 'https' only by default)
* @param int $localurl 0=Only external URL are possible, 1=Only local URL, 2=Both external and local URL are allowed.
* @return array Returns an associative array containing the response from the server array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
* @return array Returns an associative array containing the response from the server array('content'=>response, 'curl_error_no'=>errno, 'curl_error_msg'=>errmsg...)
*/
function getURLContent($url, $postorget = 'GET', $param = '', $followlocation = 1, $addheaders = array(), $allowedschemes = array('http', 'https'), $localurl = 0)
{

View File

@ -546,16 +546,17 @@ function show_stats_for_company($product, $socid)
* Return translation label of a unit key.
* Function kept for backward compatibility.
*
* @param string $scale Scale of unit: '0', '-3', '6', ...
* @param string $measuring_style Style of unit: weight, volume,...
* @param int $unit ID of unit (rowid in llx_c_units table)
* @param int $use_short_label 1=Use short label ('g' instead of 'gram'). Short labels are not translated.
* @return string Unit string
* @param string $scale Scale of unit: '0', '-3', '6', ...
* @param string $measuring_style Style of unit: weight, volume,...
* @param int $unit ID of unit (rowid in llx_c_units table)
* @param int $use_short_label 1=Use short label ('g' instead of 'gram'). Short labels are not translated.
* @param Translate $outputlangs Language object
* @return string Unit string
* @see measuringUnitString() formproduct->selectMeasuringUnits()
*/
function measuring_units_string($scale = '', $measuring_style = '', $unit = 0, $use_short_label = 0)
function measuring_units_string($scale = '', $measuring_style = '', $unit = 0, $use_short_label = 0, $outputlangs = null)
{
return measuringUnitString($unit, $measuring_style, $scale, $use_short_label);
return measuringUnitString($unit, $measuring_style, $scale, $use_short_label, $outputlangs);
}
/**
@ -565,14 +566,19 @@ function measuring_units_string($scale = '', $measuring_style = '', $unit = 0, $
* @param string $measuring_style Style of unit: 'weight', 'volume', ..., '' = 'net_measure' for option PRODUCT_ADD_NET_MEASURE
* @param string $scale Scale of unit: '0', '-3', '6', ...
* @param int $use_short_label 1=Use short label ('g' instead of 'gram'). Short labels are not translated.
* @param Translate $outputlangs Language object
* @return string Unit string
* @see formproduct->selectMeasuringUnits()
*/
function measuringUnitString($unit, $measuring_style = '', $scale = '', $use_short_label = 0)
function measuringUnitString($unit, $measuring_style = '', $scale = '', $use_short_label = 0, $outputlangs = null)
{
global $langs, $db;
global $measuring_unit_cache;
if (empty($outputlangs)) {
$outputlangs = $langs;
}
if (empty($measuring_unit_cache[$unit.'_'.$measuring_style.'_'.$scale.'_'.$use_short_label]))
{
require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
@ -605,7 +611,7 @@ function measuringUnitString($unit, $measuring_style = '', $scale = '', $use_sho
} else {
if (is_array($measuringUnits->records) && count($measuringUnits->records) > 0) {
if ($use_short_label) $labeltoreturn = $measuringUnits->records[key($measuringUnits->records)]->short_label;
else $labeltoreturn = $langs->transnoentitiesnoconv($measuringUnits->records[key($measuringUnits->records)]->label);
else $labeltoreturn = $outputlangs->transnoentitiesnoconv($measuringUnits->records[key($measuringUnits->records)]->label);
} else {
$labeltoreturn = '';
}

View File

@ -265,7 +265,7 @@ class pdf_standard extends ModelePDFProduct
$tab_height = 130;
$tab_height_newpage = 150;
//
// Label of product
$pdf->SetFont('', 'B', $default_font_size);
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $tab_top, dol_htmlentitiesbr($object->label), 0, 1);
$nexY = $pdf->GetY();
@ -276,29 +276,34 @@ class pdf_standard extends ModelePDFProduct
$nexY += 5;
$outputlangs->load("other");
if ($object->weight)
{
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $langs->trans("Weight").': '.dol_htmlentitiesbr($object->weight), 0, 1);
$texttoshow = $langs->trans("Weight").': '.dol_htmlentitiesbr($object->weight);
if (isset($object->weight_units)) $texttoshow .= ' '.measuring_units_string($object->weight_units, 'weight', 0, 0, $outputlangs);
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $texttoshow, 0, 1);
$nexY = $pdf->GetY();
}
if ($object->weight)
{
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").': '.($object->length != '' ? $object->length : '?').' x '.($object->width != '' ? $object->width : '?').' x '.($object->height != '' ? $object->height : '?'), 0, 1);
$texttoshow = $langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").': '.($object->length != '' ? $object->length : '?').' x '.($object->width != '' ? $object->width : '?').' x '.($object->height != '' ? $object->height : '?');
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $texttoshow, 0, 1);
$nexY = $pdf->GetY();
}
if ($object->surface)
{
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $langs->trans("Area").': '.dol_htmlentitiesbr($object->surface), 0, 1);
$texttoshow = $langs->trans("Area").': '.dol_htmlentitiesbr($object->surface);
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $texttoshow, 0, 1);
$nexY = $pdf->GetY();
}
if ($object->volume)
{
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $langs->trans("Volume").': '.dol_htmlentitiesbr($object->volume), 0, 1);
$texttoshow = $langs->trans("Volume").': '.dol_htmlentitiesbr($object->volume);
$pdf->writeHTMLCell(190, 3, $this->marge_gauche, $nexY, $texttoshow, 0, 1);
$nexY = $pdf->GetY();
}
// Affiche notes
// Show notes
// TODO There is no public note on product yet
$notetoshow = empty($object->note_public) ? '' : $object->note_public;
if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE))

View File

@ -623,12 +623,12 @@ if (($action == "create") || ($action == "edit"))
print '<tr><td>';
print $langs->trans('CronDtStart')."</td><td>";
if (!empty($object->datestart)) {print dol_print_date($object->datestart, 'dayhoursec'); }
if (!empty($object->datestart)) {print $form->textwithpicto(dol_print_date($object->datestart, 'dayhoursec'), $langs->trans("CurrentTimeZone")); }
print "</td></tr>";
print "<tr><td>";
print $langs->trans('CronDtEnd')."</td><td>";
if (!empty($object->dateend)) {print dol_print_date($object->dateend, 'dayhoursec'); }
if (!empty($object->dateend)) {print $form->textwithpicto(dol_print_date($object->dateend, 'dayhoursec'), $langs->trans("CurrentTimeZone")); }
print "</td></tr>";
print "<tr><td>";
@ -653,7 +653,7 @@ if (($action == "create") || ($action == "edit"))
print ' ('.$langs->trans('CronFrom').')';
print "</td><td>";
if (!$object->status) print $langs->trans("Disabled");
elseif (!empty($object->datenextrun)) { print img_picto('', 'object_calendarday').' '.dol_print_date($object->datenextrun, 'dayhoursec'); } else { print $langs->trans('CronNone'); }
elseif (!empty($object->datenextrun)) { print img_picto('', 'object_calendarday').' '.$form->textwithpicto(dol_print_date($object->datenextrun, 'dayhoursec'), $langs->trans("CurrentTimeZone")); } else { print $langs->trans('CronNone'); }
if ($object->status == Cronjob::STATUS_ENABLED)
{
if ($object->maxrun && $object->nbrun >= $object->maxrun) print img_warning($langs->trans("MaxRunReached"));
@ -672,12 +672,12 @@ if (($action == "create") || ($action == "edit"))
print '<tr><td class="titlefield">';
print $langs->trans('CronDtLastLaunch')."</td><td>";
if (!empty($object->datelastrun)) {print dol_print_date($object->datelastrun, 'dayhoursec'); } else {print $langs->trans('CronNone'); }
if (!empty($object->datelastrun)) {print $form->textwithpicto(dol_print_date($object->datelastrun, 'dayhoursec'), $langs->trans("CurrentTimeZone")); } else {print $langs->trans('CronNone'); }
print "</td></tr>";
print '<tr><td>';
print $langs->trans('CronDtLastResult')."</td><td>";
if (!empty($object->datelastresult)) {print dol_print_date($object->datelastresult, 'dayhoursec'); } else {print $langs->trans('CronNone'); }
if (!empty($object->datelastresult)) {print $form->textwithpicto(dol_print_date($object->datelastresult, 'dayhoursec'), $langs->trans("CurrentTimeZone")); } else {print $langs->trans('CronNone'); }
print "</td></tr>";
print '<tr><td>';

View File

@ -27,28 +27,41 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
require_once DOL_DOCUMENT_ROOT.'/intracommreport/class/intracommreport.class.php';
$langs->loadLangs(array("intracommreport"));
var_dump($_POST);
$action = GETPOST('action');
$exporttype = GETPOST('exporttype'); // DEB ou DES
if (empty($exporttype)) {
$exporttype = 'deb';
}
$form = new Form($db);
$formother = new FormOther($db);
$year = GETPOST('year');
$month = GETPOST('month');
$exporttype = GETPOSTISSET('exporttype') ? GETPOST('exporttype', 'alphanohtml') : 'deb'; // DEB ou DES
$year = GETPOSTINT('year');
$month = GETPOSTINT('month');
$label = (string) GETPOST('label', 'alphanohtml');
$type_declaration = GETPOSTINT('type');
$type_declaration = (string) GETPOST('type_declaration', 'alphanohtml');
$backtopage = GETPOST('backtopage', 'alpha');
$declaration = array(
"deb" => $langs->trans("DEB"),
"des" => $langs->trans("DES"),
);
$typeOfDeclaration = array(
"introduction" => $langs->trans("Introduction"),
"expedition" => $langs->trans("Expedition"),
);
$object = new IntracommReport($db);
if ($id > 0) {
$object->fetch($id);
}
$form = new Form($db);
$formother = new FormOther($db);
// Initialize technical object to manage hooks. Note that conf->hooks_modules contains array
$hookmanager->initHooks(array('intracommcard', 'globalcard'));
/*
* Actions
*/
$parameters = array('id' => $id);
// Note that $action and $object may have been modified by some hooks
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action);
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if ($user->rights->intracommreport->delete && $action == 'confirm_delete' && $confirm == 'yes') {
$result = $object->delete($id, $user);
@ -72,16 +85,16 @@ if ($action == 'add' && $user->rights->intracommreport->write) {
$object->subscription = (int) $subscription;
// Fill array 'array_options' with data from add form
$ret = $extrafields->setOptionalsFromPost($extralabels, $object);
if ($ret < 0) {
$error++;
}
// $ret = $extrafields->setOptionalsFromPost($extralabels, $object);
// if ($ret < 0) {
// $error++;
// }
if (empty($object->label)) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors');
} else {
$sql = "SELECT libelle FROM ".MAIN_DB_PREFIX."adherent_type WHERE libelle='".$db->escape($object->label)."'";
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."intracommreport WHERE ref='".$db->escape($object->label)."'";
$result = $db->query($sql);
if ($result) {
$num = $db->num_rows($result);
@ -96,7 +109,7 @@ if ($action == 'add' && $user->rights->intracommreport->write) {
if (!$error) {
$id = $object->create($user);
if ($id > 0) {
header("Location: ".$_SERVER["PHP_SELF"]);
header("Location: ".$_SERVER["PHP_SELF"].'?id='.$id);
exit;
} else {
setEventMessages($object->error, $object->errors, 'errors');
@ -145,10 +158,8 @@ if ($action == 'create') {
print '</tr>';
// Type of declaration
$typeOfDeclaration["introduction"] = $langs->trans("Introduction");
$typeOfDeclaration["expedition"] = $langs->trans("Expedition");
print '<tr><td class="fieldrequired">'.$langs->trans("TypeOfDeclaration")."</td><td>\n";
print $form->selectarray("type_declaration", $typeOfDeclaration, GETPOST('type_declaration', 'alpha') ?GETPOST('type_declaration', 'alpha') : $object->type_declaration, 0);
print $form->selectarray("type_declaration", $typeOfDeclaration, GETPOST('type_declaration', 'alpha') ? GETPOST('type_declaration', 'alpha') : $object->type_declaration, 0);
print "</td>\n";
print '</table>';
@ -177,9 +188,9 @@ if ($id > 0 && $action != 'edit') {
/*
* Show tabs
*/
$head = intracommreport_prepare_head($object);
//$head = intracommreport_prepare_head($object);
print dol_get_fiche_head($head, 'general', $langs->trans("IntracommReport"), -1, 'user');
print dol_get_fiche_head("", 'general', $langs->trans("IntracommReport"), -1, 'user');
// Confirm remove report
if ($action == 'delete') {

View File

@ -81,13 +81,46 @@ class IntracommReport extends CommonObject
$this->exporttype = 'deb';
}
/**
* Fonction create
* @param User $user User
* @param int $notrigger notrigger
* @return int
*/
public function create($user, $notrigger = 0)
{
return 1;
}
/**
* Fonction fetch
* @param int $id object ID
* @return int
*/
public function fetch($id)
{
return 1;
}
/**
* Fonction delete
* @param int $id object ID
* @param User $user User
* @param int $notrigger notrigger
* @return int
*/
public function delete($id, $user, $notrigger = 0)
{
return 1;
}
/**
* Generate XML file
*
* @param int $mode O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation)
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param string $period_reference Period of reference
* @return void
* @param int $mode O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation)
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param string $period_reference Period of reference
* @return SimpleXMLElement|int
*/
public function getXML($mode = 'O', $type = 'introduction', $period_reference = '')
{
@ -149,7 +182,7 @@ class IntracommReport extends CommonObject
* @param int $period_year Year of declaration
* @param int $period_month Month of declaration
* @param string $type_declaration Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @return void
* @return SimpleXMLElement|int
*/
public function getXMLDes($period_year, $period_month, $type_declaration = 'expedition')
{
@ -246,7 +279,7 @@ class IntracommReport extends CommonObject
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param int $period_reference Reference declaration
* @param string $exporttype deb=DEB, des=DES
* @return int <0 if KO, >0 if OK
* @return string <0 if KO, >0 if OK
*/
public function getSQLFactLines($type, $period_reference, $exporttype = 'deb')
{
@ -325,7 +358,7 @@ class IntracommReport extends CommonObject
* Add item for DES
*
* @param SimpleXMLElement $declaration Reference declaration
* @param esurce $res Result of request SQL
* @param Resource $res Result of request SQL
* @param int $i Line Id
* @return void
*/

View File

@ -121,8 +121,8 @@ $isInEEC = isInEEC($mysoc);
// Definition of fields for lists
$arrayfields = array(
'i.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
'i.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
'i.ref' => array('label'=>$langs->trans("Ref"), 'checked'=>1),
'i.label' => array('label'=>$langs->trans("Label"), 'checked'=>1),
'i.fk_product_type'=>array('label'=>$langs->trans("Type"), 'checked'=>0, 'enabled'=>(!empty($conf->produit->enabled) && !empty($conf->service->enabled))),
);
/*

View File

@ -108,7 +108,7 @@ FillWithLastServiceDates=Fill with last service line dates
MultiPricesAbility=Multiple price segments per product/service (each customer is in one price segment)
MultiPricesNumPrices=Number of prices
DefaultPriceType=Base of prices per default (with versus without tax) when adding new sale prices
AssociatedProductsAbility=Activate kits (virtual products)
AssociatedProductsAbility=Enable Kits (set of other products)
AssociatedProducts=Kits
AssociatedProductsNumber=Number of products composing this kit
ParentProductsNumber=Number of parent packaging product

View File

@ -208,7 +208,8 @@ JournalLabel=Journal label
NumPiece=Piece number
TransactionNumShort=Num. transaction
AccountingCategory=Personalized groups
GroupByAccountAccounting=Group by accounting account
GroupByAccountAccounting=Group by general ledger account
GroupBySubAccountAccounting=Group by subledger account
AccountingAccountGroupsDesc=You can define here some groups of accounting account. They will be used for personalized accounting reports.
ByAccounts=By accounts
ByPredefinedAccountGroups=By predefined groups
@ -295,6 +296,7 @@ Accounted=Accounted in ledger
NotYetAccounted=Not yet accounted in ledger
ShowTutorial=Show Tutorial
NotReconciled=Not reconciled
WarningRecordWithoutSubledgerAreExcluded=Warning, all operations without subledger account defined are filtered and excluded from this view
## Admin
BindingOptions=Binding options

View File

@ -56,6 +56,8 @@ GUISetup=Display
SetupArea=Setup
UploadNewTemplate=Upload new template(s)
FormToTestFileUploadForm=Form to test file upload (according to setup)
ModuleMustBeEnabled=The module/application <b>%s</b> must be enabled
ModuleIsEnabled=The module/application <b>%s</b> has been enabled
IfModuleEnabled=Note: yes is effective only if module <b>%s</b> is enabled
RemoveLock=Remove/rename file <b>%s</b> if it exists, to allow usage of the Update/Install tool.
RestoreLock=Restore file <b>%s</b>, with read permission only, to disable any further use of the Update/Install tool.

View File

@ -358,7 +358,7 @@ VATIntraCheckableOnEUSite=Check the intra-Community VAT ID on the European Commi
VATIntraManualCheck=You can also check manually on the European Commission website <a href="%s" target="_blank">%s</a>
ErrorVATCheckMS_UNAVAILABLE=Check not possible. Check service is not provided by the member state (%s).
NorProspectNorCustomer=Not prospect, nor customer
JuridicalStatus=Legal Entity Type
JuridicalStatus=Business entity type
Workforce=Workforce
Staff=Employees
ProspectLevelShort=Potential

View File

@ -29,6 +29,7 @@ AvailableVariables=Available substitution variables
NoTranslation=No translation
Translation=Translation
EmptySearchString=Enter non empty search criterias
EnterADateCriteria=Enter a date criteria
NoRecordFound=No record found
NoRecordDeleted=No record deleted
NotEnoughDataYet=Not enough data

View File

@ -126,7 +126,6 @@ UseSpecificEditorURL = Use a specific editor URL
UseSpecificFamily = Use a specific family
UseSpecificAuthor = Use a specific author
UseSpecificVersion = Use a specific initial version
ModuleMustBeEnabled=The module/application must be enabled first
IncludeRefGeneration=The reference of object must be generated automatically
IncludeRefGenerationHelp=Check this if you want to include code to manage the generation automatically of the reference
IncludeDocGeneration=I want to generate some documents from the object

View File

@ -138,7 +138,7 @@ Right=Right
CalculatedWeight=Calculated weight
CalculatedVolume=Calculated volume
Weight=Weight
WeightUnitton=tonne
WeightUnitton=ton
WeightUnitkg=kg
WeightUnitg=g
WeightUnitmg=mg

View File

@ -108,7 +108,8 @@ FillWithLastServiceDates=Fill with last service line dates
MultiPricesAbility=Multiple price segments per product/service (each customer is in one price segment)
MultiPricesNumPrices=Number of prices
DefaultPriceType=Base of prices per default (with versus without tax) when adding new sale prices
AssociatedProductsAbility=Activate kits (virtual products)
AssociatedProductsAbility=Enable Kits (set of other products)
VariantsAbility=Enable Variants (variations of products, for example color, size)
AssociatedProducts=Kits
AssociatedProductsNumber=Number of products composing this kit
ParentProductsNumber=Number of parent packaging product

View File

@ -240,3 +240,4 @@ InventoryRealQtyHelp=Set value to 0 to reset qty<br>Keep field empty, or remove
UpdateByScaning=Update by scaning
UpdateByScaningProductBarcode=Update by scan (product barcode)
UpdateByScaningLot=Update by scan (lot|serial barcode)
DisableStockChangeOfSubProduct=Deactivate the stock change for all the subproducts of this Kit during this movement.

View File

@ -2385,7 +2385,7 @@ if ($module == 'initmodule')
print ' &nbsp; ';
if (empty($conf->global->$const_name)) // If module is not activated
{
print '<a href="#" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled").'"><strike>'.$langs->trans("GoToApiExplorer").'</strike></a>';
print '<a href="#" target="apiexplorer" title="'.$langs->trans("ModuleMustBeEnabled", $module).'"><strike>'.$langs->trans("GoToApiExplorer").'</strike></a>';
} else {
print '<a href="'.DOL_URL_ROOT.'/api/index.php/explorer/" target="apiexplorer">'.$langs->trans("GoToApiExplorer").'</a>';
}

View File

@ -127,8 +127,8 @@ if ($action == 'other')
$value = GETPOST('price_base_type', 'alpha');
$res = dolibarr_set_const($db, "PRODUCT_PRICE_BASE_TYPE", $value, 'chaine', 0, '', $conf->entity);
$value = GETPOST('PRODUIT_SOUSPRODUITS', 'alpha');
$res = dolibarr_set_const($db, "PRODUIT_SOUSPRODUITS", $value, 'chaine', 0, '', $conf->entity);
/*$value = GETPOST('PRODUIT_SOUSPRODUITS', 'alpha');
$res = dolibarr_set_const($db, "PRODUIT_SOUSPRODUITS", $value, 'chaine', 0, '', $conf->entity);*/
$value = GETPOST('activate_viewProdDescInForm', 'alpha');
$res = dolibarr_set_const($db, "PRODUIT_DESC_IN_FORM", $value, 'chaine', 0, '', $conf->entity);
@ -312,7 +312,6 @@ print ' <td class="center" width="80">'.$langs->trans("Status").'</td>';
print ' <td class="center" width="60">'.$langs->trans("ShortInfo").'</td>';
print "</tr>\n";
$var = true;
foreach ($dirproduct as $dirroot)
{
$dir = dol_buildpath($dirroot, 0);
@ -340,7 +339,6 @@ foreach ($dirproduct as $dirroot)
if ($modCodeProduct->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
if ($modCodeProduct->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue;
$var = !$var;
print '<tr class="oddeven">'."\n";
print '<td width="140">'.$modCodeProduct->name.'</td>'."\n";
print '<td>'.$modCodeProduct->info($langs).'</td>'."\n";
@ -537,17 +535,35 @@ print '<td class="right" width="60">'.$langs->trans("Value").'</td>'."\n";
print '</tr>'."\n";
/*
* Other parameters
*/
// Enable kits (subproducts)
$rowspan = 4;
if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $rowspan++;
if (empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) $rowspan++;
if (!empty($conf->global->MAIN_MULTILANGS)) $rowspan++;
if (!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) $rowspan++;
print '<tr class="oddeven">';
print '<td>'.$langs->trans("AssociatedProductsAbility").'</td>';
print '<td class="right">';
print ajax_constantonoff("PRODUIT_SOUSPRODUITS", array(), $conf->entity, 0, 0, 1, 0);
//print $form->selectyesno("PRODUIT_SOUSPRODUITS", $conf->global->PRODUIT_SOUSPRODUITS, 1);
print '</td>';
print '</tr>';
// Enable variants
print '<tr class="oddeven">';
print '<td>'.$langs->trans("VariantsAbility").'</td>';
print '<td class="right">';
//print ajax_constantonoff("PRODUIT_SOUSPRODUITS", array(), $conf->entity, 0, 0, 1, 0);
//print $form->selectyesno("PRODUIT_SOUSPRODUITS", $conf->global->PRODUIT_SOUSPRODUITS, 1);
if (empty($conf->variants->enabled)) {
print '<span class="opacitymedium">'.$langs->trans("ModuleMustBeEnabled", $langs->transnoentitiesnoconv("Module610Name")).'</span>';
} else {
print yn(1).' <span class="opacitymedium">('.$langs->trans("ModuleIsEnabled", $langs->transnoentitiesnoconv("Module610Name")).')</span>';
}
print '</td>';
print '</tr>';
// Rule for price
print '<tr class="oddeven">';
if (empty($conf->multicompany->enabled))
{
@ -575,24 +591,15 @@ if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_
print '</tr>';
}
//Default product price base type
// Default product price base type
print '<tr class="oddeven">';
print '<td>'.$langs->trans("DefaultPriceType").'</td>';
print '<td width="60" class="right">';
print '<td class="right">';
print $form->selectPriceBaseType($conf->global->PRODUCT_PRICE_BASE_TYPE, "price_base_type");
print '</td>';
print '</tr>';
// sousproduits activation/desactivation
print '<tr class="oddeven">';
print '<td>'.$langs->trans("AssociatedProductsAbility").'</td>';
print '<td class="right">';
print $form->selectyesno("PRODUIT_SOUSPRODUITS", $conf->global->PRODUIT_SOUSPRODUITS, 1);
print '</td>';
print '</tr>';
// Utilisation formulaire Ajax sur choix produit
// Use Ajax form to select a product
print '<tr class="oddeven">';
print '<td>'.$form->textwithpicto($langs->trans("UseSearchToSelectProduct"), $langs->trans('UseSearchToSelectProductTooltip'), 1).'</td>';

View File

@ -280,20 +280,20 @@ class Product extends CommonObject
//! Metric of products
public $weight;
public $weight_units;
public $weight_units; // scale -3, 0, 3, 6
public $length;
public $length_units;
public $length_units; // scale -3, 0, 3, 6
public $width;
public $width_units;
public $width_units; // scale -3, 0, 3, 6
public $height;
public $height_units;
public $height_units; // scale -3, 0, 3, 6
public $surface;
public $surface_units;
public $surface_units; // scale -3, 0, 3, 6
public $volume;
public $volume_units;
public $volume_units; // scale -3, 0, 3, 6
public $net_measure;
public $net_measure_units;
public $net_measure_units; // scale -3, 0, 3, 6
public $accountancy_code_sell;
public $accountancy_code_sell_intra;
@ -4229,9 +4229,9 @@ class Product extends CommonObject
// phpcs:enable
$this->res = array();
if (isset($this->sousprods) && is_array($this->sousprods)) {
foreach ($this->sousprods as $prod_name => $desc_product)
{
if (is_array($desc_product)) { $this->fetch_prod_arbo($desc_product, "", $multiply, 1, $this->id);
foreach ($this->sousprods as $prod_name => $desc_product) {
if (is_array($desc_product)) {
$this->fetch_prod_arbo($desc_product, "", $multiply, 1, $this->id);
}
}
}
@ -4777,9 +4777,10 @@ class Product extends CommonObject
* @param string $inventorycode Inventory code
* @param string $origin_element Origin element type
* @param int $origin_id Origin id of element
* @param int $disablestockchangeforsubproduct Disable stock change for sub-products of kit (usefull only if product is a subproduct)
* @return int <0 if KO, >0 if OK
*/
public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label = '', $price = 0, $inventorycode = '', $origin_element = '', $origin_id = null)
public function correct_stock($user, $id_entrepot, $nbpiece, $movement, $label = '', $price = 0, $inventorycode = '', $origin_element = '', $origin_id = null, $disablestockchangeforsubproduct = 0)
{
// phpcs:enable
if ($id_entrepot) {
@ -4792,7 +4793,7 @@ class Product extends CommonObject
$movementstock = new MouvementStock($this->db);
$movementstock->setOrigin($origin_element, $origin_id); // Set ->origin and ->origin->id
$result = $movementstock->_create($user, $this->id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode);
$result = $movementstock->_create($user, $this->id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode, '', '', '', '', false, 0, $disablestockchangeforsubproduct);
if ($result >= 0) {
$this->db->commit();
@ -4823,9 +4824,10 @@ class Product extends CommonObject
* @param string $inventorycode Inventory code
* @param string $origin_element Origin element type
* @param int $origin_id Origin id of element
* @param int $disablestockchangeforsubproduct Disable stock change for sub-products of kit (usefull only if product is a subproduct)
* @return int <0 if KO, >0 if OK
*/
public function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label = '', $price = 0, $dlc = '', $dluo = '', $lot = '', $inventorycode = '', $origin_element = '', $origin_id = null)
public function correct_stock_batch($user, $id_entrepot, $nbpiece, $movement, $label = '', $price = 0, $dlc = '', $dluo = '', $lot = '', $inventorycode = '', $origin_element = '', $origin_id = null, $disablestockchangeforsubproduct = 0)
{
// phpcs:enable
if ($id_entrepot) {
@ -4838,7 +4840,7 @@ class Product extends CommonObject
$movementstock = new MouvementStock($this->db);
$movementstock->setOrigin($origin_element, $origin_id);
$result = $movementstock->_create($user, $this->id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode, '', $dlc, $dluo, $lot);
$result = $movementstock->_create($user, $this->id, $id_entrepot, $op[$movement], $movement, $price, $label, $inventorycode, '', $dlc, $dluo, $lot, false, 0, $disablestockchangeforsubproduct);
if ($result >= 0) {
$this->db->commit();
@ -5387,19 +5389,19 @@ class Product extends CommonObject
$this->date_modification = $now;
$this->weight = 4;
$this->weight_unit = 1;
$this->weight_units = 3;
$this->length = 5;
$this->length_unit = 1;
$this->length_units = 1;
$this->width = 6;
$this->width_unit = 0;
$this->width_units = 0;
$this->height = null;
$this->height_unit = null;
$this->height_units = null;
$this->surface = 30;
$this->surface_unit = 0;
$this->surface_units = 0;
$this->volume = 300;
$this->volume_unit = 0;
$this->volume_units = 0;
$this->barcode = -1; // Create barcode automatically
}

View File

@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005-2018 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
@ -137,7 +137,7 @@ if ($action == 'search')
$current_lang = $langs->getDefaultLang();
$sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.fk_product_type as type, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
$sql .= ' p.fk_product_type, p.tms as datem';
$sql .= ' p.fk_product_type, p.tms as datem, p.tobatch';
if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= ', pl.label as labelm, pl.description as descriptionm';
$sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product as cp ON p.rowid = cp.fk_product';
@ -204,7 +204,7 @@ if ($id > 0 || !empty($ref))
dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref', '', '', '', 0, '', '', 0);
if ($object->type != Product::TYPE_SERVICE || empty($conf->global->PRODUIT_MULTIPRICES))
if ($object->type != Product::TYPE_SERVICE || !empty($conf->global->STOCK_SUPPORTS_SERVICES) || empty($conf->global->PRODUIT_MULTIPRICES))
{
print '<div class="fichecenter">';
print '<div class="underbanner clearboth"></div>';
@ -320,14 +320,11 @@ if ($id > 0 || !empty($ref))
print '</tr>'."\n";
$totalsell = 0;
if (count($prods_arbo))
{
foreach ($prods_arbo as $value)
{
if (count($prods_arbo)) {
foreach ($prods_arbo as $value) {
$productstatic->fetch($value['id']);
if ($value['level'] <= 1)
{
if ($value['level'] <= 1) {
print '<tr class="oddeven">';
$notdefined = 0;
@ -380,7 +377,7 @@ if ($id > 0 || !empty($ref))
// Qty + IncDec
if ($user->rights->produit->creer || $user->rights->service->creer)
{
print '<td class="center"><input type="text" value="'.$nb_of_subproduct.'" name="TProduct['.$productstatic->id.'][qty]" size="4" /></td>';
print '<td class="center"><input type="text" value="'.$nb_of_subproduct.'" name="TProduct['.$productstatic->id.'][qty]" size="4" class="right" /></td>';
print '<td class="center"><input type="checkbox" name="TProduct['.$productstatic->id.'][incdec]" value="1" '.($value['incdec'] == 1 ? 'checked' : '').' /></td>';
} else {
print '<td>'.$nb_of_subproduct.'</td>';
@ -566,6 +563,7 @@ if ($id > 0 || !empty($ref))
$productstatic->label = $objp->label;
$productstatic->type = $objp->type;
$productstatic->entity = $objp->entity;
$productstatic->status_batch = $objp->tobatch;
print '<td>'.$productstatic->getNomUrl(1, '', 24).'</td>';
$labeltoshow = $objp->label;

View File

@ -128,26 +128,27 @@ class MouvementStock extends CommonObject
* Add a movement of stock (in one direction only).
* $this->origin can be also be set to save the source object of movement.
*
* @param User $user User object
* @param int $fk_product Id of product
* @param int $entrepot_id Id of warehouse
* @param int $qty Qty of movement (can be <0 or >0 depending on parameter type)
* @param int $type Direction of movement:
* 0=input (stock increase by a stock transfer), 1=output (stock decrease by a stock transfer),
* 2=output (stock decrease), 3=input (stock increase)
* Note that qty should be > 0 with 0 or 3, < 0 with 1 or 2.
* @param int $price Unit price HT of product, used to calculate average weighted price (AWP or PMP in french). If 0, average weighted price is not changed.
* @param string $label Label of stock movement
* @param string $inventorycode Inventory code
* @param string $datem Force date of movement
* @param integer $eatby eat-by date. Will be used if lot does not exists yet and will be created.
* @param integer $sellby sell-by date. Will be used if lot does not exists yet and will be created.
* @param string $batch batch number
* @param boolean $skip_batch If set to true, stock movement is done without impacting batch record
* @param User $user User object
* @param int $fk_product Id of product
* @param int $entrepot_id Id of warehouse
* @param int $qty Qty of movement (can be <0 or >0 depending on parameter type)
* @param int $type Direction of movement:
* 0=input (stock increase by a stock transfer), 1=output (stock decrease by a stock transfer),
* 2=output (stock decrease), 3=input (stock increase)
* Note that qty should be > 0 with 0 or 3, < 0 with 1 or 2.
* @param int $price Unit price HT of product, used to calculate average weighted price (AWP or PMP in french). If 0, average weighted price is not changed.
* @param string $label Label of stock movement
* @param string $inventorycode Inventory code
* @param string $datem Force date of movement
* @param integer $eatby eat-by date. Will be used if lot does not exists yet and will be created.
* @param integer $sellby sell-by date. Will be used if lot does not exists yet and will be created.
* @param string $batch batch number
* @param boolean $skip_batch If set to true, stock movement is done without impacting batch record
* @param int $id_product_batch Id product_batch (when skip_batch is false and we already know which record of product_batch to use)
* @return int <0 if KO, 0 if fk_product is null or product id does not exists, >0 if OK
* @param int $disablestockchangeforsubproduct Disable stock change for sub-products of kit (usefull only if product is a subproduct)
* @return int <0 if KO, 0 if fk_product is null or product id does not exists, >0 if OK
*/
public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = 0, $label = '', $inventorycode = '', $datem = '', $eatby = '', $sellby = '', $batch = '', $skip_batch = false, $id_product_batch = 0)
public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = 0, $label = '', $inventorycode = '', $datem = '', $eatby = '', $sellby = '', $batch = '', $skip_batch = false, $id_product_batch = 0, $disablestockchangeforsubproduct = 0)
{
// phpcs:disable
global $conf, $langs;
@ -571,9 +572,9 @@ class MouvementStock extends CommonObject
}
// Add movement for sub products (recursive call)
if (!$error && !empty($conf->global->PRODUIT_SOUSPRODUITS) && empty($conf->global->INDEPENDANT_SUBPRODUCT_STOCK))
if (!$error && !empty($conf->global->PRODUIT_SOUSPRODUITS) && empty($conf->global->INDEPENDANT_SUBPRODUCT_STOCK) && empty($disablestockchangeforsubproduct))
{
$error = $this->_createSubProduct($user, $fk_product, $entrepot_id, $qty, $type, 0, $label, $inventorycode); // we use 0 as price, because pmp is not changed for subproduct
$error = $this->_createSubProduct($user, $fk_product, $entrepot_id, $qty, $type, 0, $label, $inventorycode); // we use 0 as price, because AWP must not change for subproduct
}
if ($movestock && !$error)

View File

@ -108,6 +108,8 @@ if (!empty($canvas))
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$hookmanager->initHooks(array('stockproductcard', 'globalcard'));
$error = 0;
/*
* Actions
@ -221,17 +223,14 @@ if ($action == "correct_stock" && !$cancel)
}
}
if (!$error)
{
if (!$error) {
$priceunit = price2num(GETPOST("unitprice"));
$nbpiece = price2num(GETPOST("nbpiece", 'alphanohtml'));
if (is_numeric($nbpiece) && $nbpiece != 0 && $id)
{
if (is_numeric($nbpiece) && $nbpiece != 0 && $id) {
$origin_element = '';
$origin_id = null;
if (GETPOST('projectid', 'int'))
{
if (GETPOST('projectid', 'int')) {
$origin_element = 'project';
$origin_id = GETPOST('projectid', 'int');
}
@ -240,8 +239,13 @@ if ($action == "correct_stock" && !$cancel)
$object = new Product($db);
$result = $object->fetch($id);
}
if ($object->hasbatch())
{
$disablestockchangeforsubproduct = 0;
if (GETPOST('disablesubproductstockchange')) {
$disablestockchangeforsubproduct = 1;
}
if ($object->hasbatch()) {
$result = $object->correct_stock_batch(
$user,
GETPOST("id_entrepot", 'int'),
@ -254,7 +258,8 @@ if ($action == "correct_stock" && !$cancel)
$batchnumber,
GETPOST('inventorycode', 'alphanohtml'),
$origin_element,
$origin_id
$origin_id,
$disablestockchangeforsubproduct
); // We do not change value of stock for a correction
} else {
$result = $object->correct_stock(
@ -266,14 +271,13 @@ if ($action == "correct_stock" && !$cancel)
$priceunit,
GETPOST('inventorycode', 'alphanohtml'),
$origin_element,
$origin_id
$origin_id,
$disablestockchangeforsubproduct
); // We do not change value of stock for a correction
}
if ($result > 0)
{
if ($backtopage)
{
if ($result > 0) {
if ($backtopage) {
header("Location: ".$backtopage);
exit;
} else {
@ -535,12 +539,14 @@ if ($id > 0 || $ref)
dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
print '<div class="fichecenter">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield" width="100%">';
if (!$variants) {
print '<div class="fichecenter">';
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield centpercent">';
if ($conf->productbatch->enabled) {
print '<tr><td class="titlefield">'.$langs->trans("ManageLotSerial").'</td><td>';
print $object->getLibStatut(0, 2);
@ -604,16 +610,23 @@ if ($id > 0 || $ref)
print '</td></tr>';
}
// Stock alert threshold
print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1), 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer).'</td><td>';
print $form->editfieldval("StockLimit", 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer, 'string');
print '</td></tr>';
// Hook formObject
$parameters = array();
$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print '</table>';
print '</div>';
print '<div class="fichehalfright"><div class="ficheaddleft"><div class="underbanner clearboth"></div>';
print '<table class="border tableforfield centpercent">';
// Stock alert threshold
print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1), 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer).'</td><td>';
print $form->editfieldval("StockLimit", 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer, 'string');
print '</td></tr>';
// Desired stock
print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1), 'desiredstock', $object->desiredstock, $object, $user->rights->produit->creer);
print '</td><td>';
@ -727,11 +740,15 @@ if ($id > 0 || $ref)
}
print "</td></tr>";
}
}
print "</table>";
print '</div>';
print '<div style="clear:both"></div>';
print "</table>";
print '</div>';
print '</div>';
print '</div>';
print '<div style="clear:both"></div>';
}
print dol_get_fiche_end();
}

View File

@ -347,10 +347,14 @@ print '<input type="hidden" name="mode" value="'.$mode.'">';
print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
print '<span class="fieldrequired">'.$langs->trans('Date').'</span> '.$form->selectDate(($date ? $date : -1), 'date');
print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddinrightonly">&nbsp;</span> '.$langs->trans('Product').'</span> ';
print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddinrightonly">&nbsp;</span> ';
print img_picto('', 'product').' ';
print $langs->trans('Product').'</span> ';
$form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, '1', 0, 'maxwidth300');
print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddinrightonly">&nbsp;</span> '.$langs->trans('Warehouse').'</span> ';
print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddinrightonly">&nbsp;</span> ';
print img_picto('', 'stock').' ';
print $langs->trans('Warehouse').'</span> ';
print $formproduct->selectWarehouses((GETPOSTISSET('fk_warehouse') ? $fk_warehouse : 'ifone'), 'fk_warehouse', '', 1);
print '</div>';
@ -558,7 +562,7 @@ print $hookmanager->resPrint;
if (empty($date) || ! $dateIsValid) {
$colspan = 6;
if ($mode == 'future') $colspan++;
print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EmptySearchString").'</span></td></tr>';
print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
}
print '</table>';

View File

@ -70,7 +70,7 @@ if ($object->element == 'product') {
print '<td>';
$ident = (GETPOST("dwid") ?GETPOST("dwid", 'int') : (GETPOST('id_entrepot') ? GETPOST('id_entrepot', 'int') : ($object->element == 'product' && $object->fk_default_warehouse ? $object->fk_default_warehouse : 'ifone')));
if (empty($ident) && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) $ident = $conf->global->MAIN_DEFAULT_WAREHOUSE;
print $formproduct->selectWarehouses($ident, 'id_entrepot', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'minwidth100');
print img_picto('', 'stock').$formproduct->selectWarehouses($ident, 'id_entrepot', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'minwidth100');
print ' &nbsp; <select class="button buttongen" name="mouvement" id="mouvement">';
print '<option value="0">'.$langs->trans("Add").'</option>';
print '<option value="1"'.(GETPOST('mouvement') ? ' selected="selected"' : '').'>'.$langs->trans("Delete").'</option>';
@ -80,6 +80,7 @@ if ($object->element == 'product') {
if ($object->element == 'stock') {
print '<td class="fieldrequired">'.$langs->trans("Product").'</td>';
print '<td>';
print img_picto('', 'product');
$form->select_produits(GETPOST('product_id', 'int'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES) ? '0' : ''), 0, 0, -1, 2, '', 0, null, 0, 1, 0, 'maxwidth500');
print ' &nbsp; <select class="button buttongen" name="mouvement" id="mouvement">';
print '<option value="0">'.$langs->trans("Add").'</option>';
@ -91,6 +92,17 @@ print '<td class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td>';
print '<td><input name="nbpiece" id="nbpiece" class="maxwidth75" value="'.GETPOST("nbpiece").'"></td>';
print '</tr>';
// If product is a Kit, we ask if we must disable stock change of subproducts
if (!empty($conf->global->PRODUIT_SOUSPRODUITS) && $object->element == 'product' && $object->hasFatherOrChild(1)) {
print '<tr>';
print '<td></td>';
print '<td colspan="3">';
print '<input type="checkbox" name="disablesubproductstockchange" id="disablesubproductstockchange" value="1"'.(GETPOST('disablesubproductstockchange') ? ' checked="checked"' : '').'">';
print ' <label for="disablesubproductstockchange">'.$langs->trans("DisableStockChangeOfSubProduct").'</label>';
print '</td>';
print '</tr>';
}
// Serial / Eat-by date
if (!empty($conf->productbatch->enabled) &&
(($object->element == 'product' && $object->hasbatch())
@ -126,6 +138,7 @@ if (!empty($conf->projet->enabled))
{
print '<td>'.$langs->trans('Project').'</td>';
print '<td>';
print img_picto('', 'project');
$formproject->select_projects(-1, '', 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 0, 0, 'maxwidth300');
print '</td>';
}

View File

@ -71,18 +71,19 @@ print '<tr>';
if ($object->element == 'product') {
print '<td class="fieldrequired">'.$langs->trans("WarehouseSource").'</td>';
print '<td>';
print $formproduct->selectWarehouses((GETPOST("dwid") ?GETPOST("dwid", 'int') : (GETPOST('id_entrepot') ?GETPOST('id_entrepot', 'int') : ($object->element == 'product' && $object->fk_default_warehouse ? $object->fk_default_warehouse : 'ifone'))), 'id_entrepot', 'warehouseopen,warehouseinternal', 1);
print img_picto('', 'stock').$formproduct->selectWarehouses((GETPOST("dwid") ?GETPOST("dwid", 'int') : (GETPOST('id_entrepot') ?GETPOST('id_entrepot', 'int') : ($object->element == 'product' && $object->fk_default_warehouse ? $object->fk_default_warehouse : 'ifone'))), 'id_entrepot', 'warehouseopen,warehouseinternal', 1);
print '</td>';
}
if ($object->element == 'stock') {
print '<td class="fieldrequired">'.$langs->trans("Product").'</td>';
print '<td>';
print img_picto('', 'product');
$form->select_produits(GETPOST('product_id', 'int'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES) ? '0' : ''), 0, 0, -1, 2, '', 0, null, 0, 1, 0, 'maxwidth500');
print '</td>';
}
print '<td class="fieldrequired">'.$langs->trans("WarehouseTarget").'</td><td>';
print $formproduct->selectWarehouses(GETPOST('id_entrepot_destination'), 'id_entrepot_destination', 'warehouseopen,warehouseinternal', 1);
print img_picto('', 'stock').$formproduct->selectWarehouses(GETPOST('id_entrepot_destination'), 'id_entrepot_destination', 'warehouseopen,warehouseinternal', 1);
print '</td></tr>';
print '<tr><td class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td colspan="3"><input type="text" name="nbpiece" size="10" value="'.dol_escape_htmltag(GETPOST("nbpiece")).'"></td>';
print '</tr>';

View File

@ -631,26 +631,32 @@ if (empty($reshook))
$errors[] = "ErrorFilePartiallyUploaded";
break;
}
}
// Gestion du logo de la société
}
} else {
if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') // TODO Sometime errors on duplicate on profid and not on code, so we must manage this case
if ($result == -3 && in_array('ErrorCustomerCodeAlreadyUsed', $object->errors))
{
$duplicate_code_error = true;
$object->code_client = null;
}
if ($result == -3 && in_array('ErrorSupplierCodeAlreadyUsed', $object->errors))
{
$duplicate_code_error = true;
$object->code_fournisseur = null;
$object->code_client = null;
}
if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { // TODO Sometime errors on duplicate on profid and not on code, so we must manage this case
$duplicate_code_error = true;
}
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
if ($result >= 0 && !$error)
{
if ($result >= 0 && !$error) {
$db->commit();
if (!empty($backtopage))
{
if (!empty($backtopage)) {
$backtopage = preg_replace('/--IDFORBACKTOPAGE--/', $object->id, $backtopage); // New method to autoselect project after a New on another form object creation
if (preg_match('/\?/', $backtopage)) $backtopage .= '&socid='.$object->id; // Old method
header("Location: ".$backtopage);
@ -838,18 +844,25 @@ if (empty($reshook))
}
}
// Set third-party type
if ($action == 'set_thirdpartytype' && $user->rights->societe->creer)
{
$object->fetch($socid);
$result = $object->setThirdpartyType(GETPOST('typent_id', 'int'));
}
// Set incoterm
if ($action == 'set_incoterms' && $user->rights->societe->creer && !empty($conf->incoterm->enabled))
{
$object->fetch($socid);
$result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
}
// Set parent company
if ($action == 'set_thirdparty' && $user->rights->societe->creer)
{
$object->fetch($socid);
$result = $object->set_parent(GETPOST('editparentcompany', 'int'));
}
// Set incoterm
if ($action == 'set_incoterms' && !empty($conf->incoterm->enabled))
{
$object->fetch($socid);
$result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
$result = $object->set_parent(GETPOST('parent_id', 'int'));
}
// Set sales representatives
@ -2455,18 +2468,24 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
} else {
print '&nbsp;';
}
print '</td>';
print '</tr>';
print '</td></tr>';
// Type + Workforce/Staff
$arr = $formcompany->typent_array(1);
$object->typent = $arr[$object->typent_code];
print '<tr><td>'.$langs->trans("ThirdPartyType").'</td><td>'.$object->typent.'</td>';
// Third-Party Type
print '<tr><td>';
print '<table class="nobordernopadding" width="100%"><tr><td>'.$langs->trans('ThirdPartyType').'</td>';
if ($action != 'editthirdpartytype' && $user->rights->societe->creer) print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editthirdpartytype&amp;socid='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a></td>';
print '</tr></table>';
print '</td><td>';
$html_name = ($action == 'editthirdpartytype') ? 'typent_id' : 'none';
$formcompany->formThirdpartyType($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->typent_id, $html_name, '');
print '</td></tr>';
// Workforce/Staff
print '<tr><td>'.$langs->trans("Workforce").'</td><td>'.$object->effectif.'</td></tr>';
print '</table>';
print '</div>';
print '<div class="fichehalfright"><div class="ficheaddleft">';
print '<div class="underbanner clearboth"></div>';
@ -2518,14 +2537,10 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
if (!empty($conf->incoterm->enabled))
{
print '<tr><td>';
print '<table width="100%" class="nobordernopadding"><tr><td>';
print $langs->trans('IncotermLabel');
print '<td><td class="right">';
if ($user->rights->societe->creer) print '<a class="editfielda" href="'.DOL_URL_ROOT.'/societe/card.php?socid='.$object->id.'&action=editincoterm">'.img_edit('', 1).'</a>';
else print '&nbsp;';
print '</td></tr></table>';
print '</td>';
print '<td colspan="3">';
print '<table width="100%" class="nobordernopadding"><tr><td>'.$langs->trans('IncotermLabel').'</td>';
if ($action != 'editincoterm' && $user->rights->societe->creer) print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?socid='.$object->id.'&action=editincoterm">'.img_edit('', 1).'</a></td>';
print '</tr></table>';
print '</td><td colspan="3">';
if ($action != 'editincoterm')
{
print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
@ -2553,20 +2568,13 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
if (empty($conf->global->SOCIETE_DISABLE_PARENTCOMPANY))
{
print '<tr><td>';
print '<table class="nobordernopadding" width="100%"><tr><td>';
print $langs->trans('ParentCompany');
print '</td>';
if ($action != 'editparentcompany') print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editparentcompany&amp;socid='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a></td>';
print '<table class="nobordernopadding" width="100%"><tr><td>'.$langs->trans('ParentCompany').'</td>';
if ($action != 'editparentcompany' && $user->rights->societe->creer) print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editparentcompany&amp;socid='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a></td>';
print '</tr></table>';
print '</td><td>';
if ($action == 'editparentcompany')
{
$form->form_thirdparty($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->parent, 'editparentcompany', 's.rowid <> '.$object->id, 1);
} else {
$form->form_thirdparty($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->parent, 'none', 's.rowid <> '.$object->id, 1);
}
print '</td>';
print '</tr>';
$html_name = ($action == 'editparentcompany') ? 'parent_id' : 'none';
$form->form_thirdparty($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->parent, $html_name, 's.rowid <> '.$object->id, 1);
print '</td></tr>';
}
// Sales representative
@ -2587,8 +2595,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
} else {
print '<span class="opacitymedium">'.$langs->trans("ThirdpartyNotLinkedToMember").'</span>';
}
print '</td>';
print "</tr>\n";
print "</td></tr>\n";
}
// Webservices url/key

View File

@ -4355,6 +4355,31 @@ class Societe extends CommonObject
return $error ? -1 : 1;
}
/**
* Define third-party type of current company
*
* @param int $typent_id third party type rowid in llx_c_typent
* @return int <0 if KO, >0 if OK
*/
public function setThirdpartyType($typent_id)
{
if ($this->id)
{
$sql = "UPDATE ".MAIN_DB_PREFIX."societe";
$sql .= " SET fk_typent = ".($typent_id > 0 ? $typent_id : "null");
$sql .= " WHERE rowid = ".$this->id;
dol_syslog(get_class($this).'::setThirdpartyType', LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql)
{
$this->typent_id = $typent_id;
$this->typent_code = dol_getIdFromCode($db, $this->$typent_id, 'c_typent', 'id', 'code');
return 1;
} else {
return -1;
}
} else return -1;
}
/**
* Function used to replace a thirdparty id with another one.

View File

@ -547,8 +547,8 @@ class SupplierProposal extends CommonObject
$this->line->tva_tx = $txtva;
$this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
$this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
$this->line->localtax1_type = $localtaxes_type[0];
$this->line->localtax2_type = $localtaxes_type[2];
$this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
$this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
$this->line->fk_product = $fk_product;
$this->line->remise_percent = $remise_percent;
$this->line->subprice = $pu_ht;
@ -593,8 +593,8 @@ class SupplierProposal extends CommonObject
// Mise en option de la ligne
if (empty($qty) && empty($special_code)) $this->line->special_code = 3;
if (is_array($array_option) && count($array_option) > 0) {
$this->line->array_options = $array_option;
if (is_array($array_options) && count($array_options) > 0) {
$this->line->array_options = $array_options;
}
$result = $this->line->insert();
@ -736,8 +736,8 @@ class SupplierProposal extends CommonObject
$this->line->tva_tx = $txtva;
$this->line->localtax1_tx = $txlocaltax1;
$this->line->localtax2_tx = $txlocaltax2;
$this->line->localtax1_type = $localtaxes_type[0];
$this->line->localtax2_type = $localtaxes_type[2];
$this->line->localtax1_type = empty($localtaxes_type[0]) ? '' : $localtaxes_type[0];
$this->line->localtax2_type = empty($localtaxes_type[2]) ? '' : $localtaxes_type[2];
$this->line->remise_percent = $remise_percent;
$this->line->subprice = $pu;
$this->line->info_bits = $info_bits;

View File

@ -396,6 +396,13 @@ input.pageplusone {
color: #000;
}
.vmirror {
transform: scale(1, -1);
}
.hmirror {
transform: scale(-1, 1);
}
select:invalid {
color: gray;
}

View File

@ -528,6 +528,13 @@ input.pageplusone {
color: #000;
}
.vmirror {
transform: scale(1, -1);
}
.hmirror {
transform: scale(-1, 1);
}
select:invalid {
color: gray;
}

View File

@ -216,6 +216,8 @@ class AllTests
require_once dirname(__FILE__).'/RestAPIUserTest.php';
$suite->addTestSuite('RestAPIUserTest');
require_once dirname(__FILE__).'/RestAPIDocumentTest.php';
$suite->addTestSuite('RestAPIDocumentTest');
// Test only with php7.2 or less
//if ((float) phpversion() < 7.3)

View File

@ -152,35 +152,43 @@ class RestAPIDocumentTest extends PHPUnit\Framework\TestCase
{
global $conf,$user,$langs,$db;
$url = $this->api_url.'/documents/?api_key='.$this->api_key;
$url = $this->api_url.'/documents/upload?api_key='.$this->api_key;
echo __METHOD__.' Request POST url='.$url."\n";
// Send to non existent directory
dol_delete_dir_recursive(DOL_DATA_ROOT.'/medias/tmpphpunit');
dol_delete_dir_recursive(DOL_DATA_ROOT.'/medias/tmpphpunit/tmpphpunit1');
//$data = '{ "filename": "mynewfile.txt", "modulepart": "medias", "ref": "", "subdir": "mysubdir1/mysubdir2", "filecontent": "content text", "fileencoding": "" }';
$data = array(
'filename'=>"mynewfile.txt",
'modulepart'=>"medias",
'ref'=>"",
'subdir'=>"tmpphpunit/tmpphpunit2",
'subdir'=>"tmpphpunit/tmpphpunit1",
'filecontent'=>"content text",
'fileencoding'=>""
'fileencoding'=>"",
'overwriteifexists'=>0,
'createdirifnotexists'=>0
);
$result = getURLContent($url, 'POST', $data, 1, array(), array('http', 'https'), 2);
$param = '';
foreach($data as $key => $val) {
$param .= '&'.$key.'='.urlencode($val);
}
$result = getURLContent($url, 'POST', $param, 1, array(), array('http', 'https'), 2);
echo __METHOD__.' Result for sending document: '.var_export($result, true)."\n";
echo __METHOD__.' curl_error_no: '.$result['curl_error_no']."\n";
$object = json_decode($result['content'], true);
$this->assertNotNull($object, 'Parsing of json result must no be null');
$this->assertEquals('401', $object['error']['code']);
$this->assertNotNull($object, 'Parsing of json result must not be null');
$this->assertEquals('401', $result['http_code'], 'Return code is not 401');
$this->assertEquals('401', empty($object['error']['code']) ? '' : $object['error']['code'], 'Error code is not 401');
// Send to existent directory
dol_delete_dir_recursive(DOL_DATA_ROOT.'/medias/tmpphpunit/tmpphpunit2');
dol_mkdir(DOL_DATA_ROOT.'/medias/tmpphpunit/tmpphpunit2');
$data = array(
@ -189,16 +197,53 @@ class RestAPIDocumentTest extends PHPUnit\Framework\TestCase
'ref'=>"",
'subdir'=>"tmpphpunit/tmpphpunit2",
'filecontent'=>"content text",
'fileencoding'=>""
'fileencoding'=>"",
'overwriteifexists'=>0,
'createdirifnotexists'=>0
);
$result2 = getURLContent($url, 'POST', $data, 1, array(), array('http', 'https'), 2);
$param = '';
foreach($data as $key => $val) {
$param .= '&'.$key.'='.urlencode($val);
}
$result2 = getURLContent($url, 'POST', $param, 1, array(), array('http', 'https'), 2);
echo __METHOD__.' Result for sending document: '.var_export($result2, true)."\n";
echo __METHOD__.' curl_error_no: '.$result2['curl_error_no']."\n";
$object2 = json_decode($result2['content'], true);
$this->assertNotNull($object2, 'Parsing of json result must no be null');
//$this->assertNotNull($object2, 'Parsing of json result must not be null');
$this->assertEquals('200', $result2['http_code'], 'Return code must be 200');
$this->assertEquals($result2['curl_error_no'], '');
$this->assertEquals($result2['content'], 'true');
$this->assertEquals($object2, 'mynewfile.txt', 'Must contains basename of file');
dol_delete_dir_recursive(DOL_DATA_ROOT.'/medias/tmpphpunit/tmpphpunit3');
$data = array(
'filename'=>"mynewfile.txt",
'modulepart'=>"medias",
'ref'=>"",
'subdir'=>"tmpphpunit/tmpphpunit3",
'filecontent'=>"content text",
'fileencoding'=>"",
'overwriteifexists'=>0,
'createdirifnotexists'=>1
);
$param = '';
foreach($data as $key => $val) {
$param .= '&'.$key.'='.urlencode($val);
}
$result3 = getURLContent($url, 'POST', $param, 1, array(), array('http', 'https'), 2);
echo __METHOD__.' Result for sending document: '.var_export($result3, true)."\n";
echo __METHOD__.' curl_error_no: '.$result3['curl_error_no']."\n";
$object3 = json_decode($result3['content'], true);
//$this->assertNotNull($object2, 'Parsing of json result must not be null');
$this->assertEquals('200', $result3['http_code'], 'Return code must be 200');
$this->assertEquals($result3['curl_error_no'], '');
$this->assertEquals($object3, 'mynewfile.txt', 'Must contains basename of file');
dol_delete_dir_recursive(DOL_DATA_ROOT.'/medias/tmpphpunit');
}