Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into

develop
This commit is contained in:
Laurent Destailleur 2023-01-23 11:57:28 +01:00
commit 1d6b105503
26 changed files with 1373 additions and 823 deletions

136
ChangeLog
View File

@ -24,10 +24,10 @@ For users:
---------------
NEW: Minimal PHP version is now PHP 7.0 instead of PHP 5.6
NEW: #21780 Add pid field to Cronjob class and store PID on job execution
NEW: #19680 Add option PRODUCT_ALLOW_EXTERNAL_DOWNLOAD to automatically have uploaded files shared publicly by a link
NEW: #20650 can move the checkbox column on left (experimental option MAIN_CHECKBOX_LEFT_COLUMN)
NEW: #21000 Added columns 'alias_name' on project, supplier invoice, supplier order, supplier proposals and task list
NEW: #21780 Add pid field to Cronjob class and store PID on job execution
NEW: #21395 Added option for dark theme mode in display - color and theme
NEW: #21397 added option to auto define barcode numbers for third-parties in barcode module setup
NEW: #21399
@ -46,15 +46,11 @@ NEW: #22676 massaction for updating product prices
NEW: #22735 Massaction to affect users on projects
NEW: #25594 can chose if VAT ID is unique or not for third parties
NEW: #4482 adding js to hide/show advanced option on the export data page
NEW: Add a constant to disallow modification of the product reference.
NEW: Add a method doAutoRenewContracts that can be used as a cron task.
NEW: Add " as enclosure by default for CSV export. Keep removing CR/LF.
NEW: add attached file in presend email form of thirdparty card
NEW: Add a way to enter LICENSE file content in property of website
NEW: add constant PROPAL_BYPASS_VALIDATED_STATUS
NEW: Add employment anniversary in birthday box
NEW: Add fail2ban rules examples to limit access to /public pages
NEW: Add filter "Product subject to lot/Serial" in stock per lot/serial
NEW: Add hidden option MAIN_EMAIL_SUPPORT_ACK to restore Email ack checkbox (feature abandonned by mailers)
NEW: Add link to create an element from the category page
NEW: Add max size send for "backup and link to mail" option
@ -63,43 +59,58 @@ NEW: Add more advices into the Setup security page
NEW: Add new global variable for keeping the previous signature information on proposale (case of reopen a proposale)
NEW: Add objectLink on expedition
NEW: Add oldcopy to Ticket so triggers intercepting TICKET_MODIFY have access to old values of the updated properties
NEW: Add option FICHINTER_ALLOW_EXTERNAL_DOWNLOAD
NEW: Add option --force on CLI cron_run_jobs.php
NEW: Add option "Show price on the generated documents for receptions"
NEW: Add performance index (name for company and contact) and llx_bank_url(url_id)
NEW: Add picto property on sub-module for password generation
NEW: invoice export : add accounting affectation
NEW: label on products categories filter
NEW: manage no email with thirdparties (better for GDPR)
NEW: Manage VAT on all lines on purchases cycle
NEW: On a bank reconciled line, we can modify the bank receipt
NEW: parent company column and filter in invoice and order list
NEW: possibility to select scopes with checkbox for Oauth tokens
NEW: private and public note on user, thirdparty and contact list
NEW: Public counters feature
NEW: Saved token of OAUTH module are now encrypted into llx_oauth_token
NEW: Save one click to select on delivery ack, on emails.
NEW: scheduled job to send unpaid invoice reminder can now use the cc and bcc from email template
NEW: experimental SMTP using PhpImap allowing OAuth2 authentication (need to add option MAIN_IMAP_USE_PHPIMAP)
NEW: can substitue project title in mail template
NEW: The purge of files can purge only if older than a number of seconds
NEW: Update ActionComm type_code on email message ticket
NEW: Finance - VAT - Admin - Add information on deadline day for submission of VAT declaration
NEW: Add the target to select attendees of event for emailings
NEW: add redirect on action confirm addconsumedline and addproduceline
NEW: Add a new advanced permission "read price"
NEW: Add substitution key __SENDEREMAIL_SIGNATURE__
NEW: Add the referrer-policy to "same-origin" by default on all public pages.
NEW: Add the SMTP header References on ticket email created by email
NEW: Add trigger to record the event of sending an email from a project #20912
NEW: Allow download link option in module configuration (propal,invoice,supplier proposal, order)
NEW: Can enter the unit price including the vat
NEW: Allow download link option in module configuration (propal, order, invoice, supplier proposal)
NEW: Can enter the unit price including the VAT
NEW: Can invoice task time per different services
NEW: Can join several files by default on email form
NEW: Can set a commercial discount by entering amount including VAT
NEW: Can set a monthly frequency (or multiple) in cron tasks.
NEW: Can set start and end dates and comment on button "Activate all services"
NEW: can sort and preselected best supplier price
NEW: Can use products categories to make inventory
NEW: Change filter type on tickets list into a multiselect combo
NEW: show date delivery planned on orders linked to company and product
NEW: Encrypt all sensitive constants in llx_const
NEW: filter on reception dates (from / to) in cheque paiement card
NEW: Accountancy - Add a graphic option to enable lettering function - FPC21
NEW: Accountancy - Add a way to clean some words when you generate thirdparty accounting account
NEW: Accountancy - Added an option during export to export or not the lettering FPC21
NEW: Accountancy - Manage supplier deposit with specific account
NEW: Accountancy - Model Digitaria - Add a way to clean some words when you generate thirdparty accounting account FPC22
NEW: Agenda - start a simple support of recurrent events on agenda
NEW: Bank - add salaries & VAT in tab planned entries
NEW: Contracts - Default template of contract is not mandatory
NEW: Contracts - add a method doAutoRenewContracts that can be used as a cron task
NEW: Contracts - default template of contract is not mandatory
NEW: Contracts - Manage Position (Rank) on Contract Lines
NEW: EMail - can copy/paste images into emails sent
NEW: EMail - can edit label of an emailing even once sent
NEW: EMail - can join several files by default on email form
NEW: EMail - can send an email on scheduled job error
NEW: EMail - on a form to send an email, we show all emails of all contacts of object
NEW: EMail - add the SMTP header References on ticket email created by email
NEW: EMail - add substitution key __SENDEREMAIL_SIGNATURE__
NEW: EMail-Collector - add IMAP port setting
NEW: EMail-Collector - add a button "Test collect"
NEW: Export - Add " as enclosure by default for CSV export. Keep removing CR/LF.
NEW: Event-Organization - add date event (!= date project) and location on event organization
NEW: Extrafields - add badge in admin extrafields setup
NEW: Extrafields - can edit property css, cssview, csslist on extrafields
@ -111,8 +122,10 @@ NEW: Invoice - Add french mention on pdf when vat debit option is on
NEW: Members - default_lang for members
NEW: Members - Table of membership types
NEW: Members - add free membership amounts at the membership type level
NEW: Orders - resize parent company column in order list
NEW: Products supplier price - autofill default supplier VAT
NEW: Projects - add author on list
NEW: Projects - add the thirdparty column to the time list (projet/tasks/time.php)
NEW: Projects - add thirdparty column to the time list (projet/tasks/time.php)
NEW: Proposals - show delivery mode on PDF for proposals
NEW: Proposals - skip accept/refuse process for proposals (option PROPAL_SKIP_ACCEPT_REFUSE)
NEW: Reception - add a from/to on search on date field
@ -120,64 +133,55 @@ NEW: Stock - page for mass stock transfer can be used with no source stock
NEW: Stock - product categories filter on inventory list
NEW: Stock - show product label on inventory
NEW: Stock - manage virtual stock at a future date
NEW: Stock Inventory - add filter "Product subject to lot/Serial" in stock per lot/serial
NEW: Stock Inventory - can use products categories to make inventory
NEW: Supplier Order List - add column private and public note
NEW: TakePOS - add margin infos to TakePOS invoice lines
NEW: TakePOS - display currency in TakePOS menu
NEW: TakePOS - Header Scroll in TakePOS
NEW: TakePOS - add price to product box in TakePOS
NEW: TakePOS - add setup parameters, can setup terminal name
NEW: TakePOS - support of Stripe Terminal with TakePOS
NEW: TakePOS - Receipt preview in TakePOS setup
NEW: TakePOS - different product list on smartphone
NEW: TakePOS - display currency in TakePOS menu
NEW: TakePOS - Header Scroll in TakePOS
NEW: TakePOS - Receipt preview in TakePOS setup
NEW: TakePOS - support of Stripe Terminal with TakePOS
NEW: Thirdparty - set thirdparty type with company modify trigger
NEW: Tickets - change filter type on tickets list into a multiselect combo
NEW: Website - can delete a whole website if disabled
NEW: Website - can remove a website template
NEW: Website - can set header "Strict-Transport-Security" in web sites.
NEW: Website - can switch status of website and page from the website toolbar
NEW: Website - Templates of websites are now directories and not zip into core repo
NEW: Website - add 4 other templates in website module
NEW: General - Bulk action to remove a category in list/search website pages
NEW: General - If we select another view list mode, we keep it
NEW: General - Introduce dolEncrypt and dolDecrypt to be able to encrypt data in db
NEW: invoice export : add accounting affectation
NEW: label on products categories filter
NEW: The link "add to bookmark" is always on top in the bookmark popup
NEW: manage no email with thirdparties (better for GDPR)
NEW: Manage VAT on all lines on purchases cycle
NEW: On a bank reconciled line, we can modify the bank receipt
NEW: On a form to send an email, we show all emails of all contacts of object
NEW: parent company column and filter in invoice and order list
NEW: Add show "Sales rep" option for PDF
NEW: Picto for shared link is clickable
NEW: possibility to select scopes with checkbox for Oauth tokens
NEW: private and public note on user, thirdparty and contact list
NEW: Product supplier price: autofill default supplier VAT
NEW: Public counters feature
NEW: Start a simple support of recurrent events on agenda
NEW: Resize parent company column in order list
NEW: Saved token of OAUTH module are now encrypted into llx_oauth_token
NEW: Save one click to select on delivery ack, on emails.
NEW: scheduled job to send unpaid invoice reminder can now use the cc and bcc from email template
NEW: Show also scheduled task never finished in scheduled task widget
NEW: show badge with number of extrafields in setup
NEW: show category tree in sellist and chkbxlst for common object
NEW: Show picto and color into combo for selection of tags
NEW: show sell-by and eat-by dates only if not empty
NEW: show SellBy/EatBy dates for each batch product in shipment card
NEW: experimental SMTP using PhpImap allowing OAuth2 authentication (need to add option MAIN_IMAP_USE_PHPIMAP)
NEW: can substitue project title in mail template
NEW: Supplier order list - Add column private and public note
NEW: The purge of files can purge only if older than a number of seconds
NEW: Update ActionComm type_code on email message ticket
NEW: VAT - Admin - Add information on deadline day for submission of VAT declaration
NEW: expand/collapse permissions on user permission page
NEW: Add the target to select attendees of event for emailings
General:
NEW: Actions: Bulk action to remove a category in list/search website pages
NEW: Cronjobs: can set a monthly frequency (or multiple) in cron tasks
NEW: Database: Encrypt all sensitive constants in llx_const
NEW: Database: Add performance index (name for company and contact) and llx_bank_url(url_id)
NEW: Database: Introduce dolEncrypt and dolDecrypt to be able to encrypt data in db
NEW: GUI: If we select another view list mode, we keep it
NEW: GUI: the link "add to bookmark" is always on top in the bookmark popup
NEW: GUI: Picto for shared link is clickable
NEW: GUI: add picto property on sub-module for password generation
NEW: GUI: show also scheduled task never finished in scheduled task widget
NEW: GUI: show badge with number of extrafields in setup
NEW: GUI: show category tree in sellist and chkbxlst for common object
NEW: GUI: show picto and color into combo for selection of tags
NEW: GUI: show sell-by and eat-by dates only if not empty
NEW: GUI: show SellBy/EatBy dates for each batch product in shipment card
NEW: GUI/Permissions: expand/collapse permissions on user permission page
NEW: Permissions: add a new advanced permission "read price"
NEW: Print: add show "Sales rep" option for PDF
NEW: Security: add fail2ban rules examples to limit access to /public pages
Option / Const for System:
NEW: MAIN_SEARCH_CATEGORY_PRODUCT_ON_LISTS const to show category customer filter
NEW: PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT showing warehouse on PDF
NEW: PRODUIT_DESC_IN_FORM accept (desktop only or +smartphone)
NEW: FICHINTER_ALLOW_EXTERNAL_DOWNLOAD
NEW: MAIN_SEARCH_CATEGORY_PRODUCT_ON_LISTS - const to show category customer filter
NEW: PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT - showing warehouse on PDF
NEW: PRODUIT_DESC_IN_FORM accept - desktop only or +smartphone
NEW: PROPAL_BYPASS_VALIDATED_STATUS
NEW: PROPAL_NEW_AS_SIGNED
NEW: TIMESPENT_ALWAYS_UPDATE_THM, when it's on we always check current thm of user to update it in task time line
NEW: TIMESPENT_ALWAYS_UPDATE_THM - when it's on we always check current thm of user to update it in task time line
Localisation:
NEW: adding JAPAN Chart-of-Account and regions/departments
@ -207,7 +211,7 @@ NEW: support multilang in Civilities API
Hooks:
NEW: Actioncomm - add new hooks for actioncomm
NEW: Actioncomm - hook formConfirm on action comm card
NEW: Actioncomm - hook formConfirm on actioncomm card
NEW: Agenda - hook on agenda pages
NEW: Help - hook "changeHelpURL" to modify target of the help button
NEW: Product - add hook to show virtual stock details on product stock card

View File

@ -48,6 +48,8 @@ $action = GETPOST('action', 'aZ09');
$provider = GETPOST('provider', 'aZ09');
$label = GETPOST('label', 'aZ09');
$servicetoeditname = GETPOST('servicetoeditname', 'aZ09');
$error = 0;
@ -72,15 +74,24 @@ if ($action == 'update') {
foreach ($conf->global as $key => $val) {
if (!empty($val) && preg_match('/^OAUTH_.+_ID$/', $key)) {
$constvalue = str_replace('_ID', '', $key);
if (!dolibarr_set_const($db, $constvalue.'_ID', GETPOST($constvalue.'_ID'), 'chaine', 0, '', $conf->entity)) {
$error++;
$newconstvalue = $constvalue;
if (GETPOSTISSET($constvalue.'_NAME')) {
$newconstvalue = preg_replace('/-.*$/', '', $constvalue).'-'.GETPOST($constvalue.'_NAME');
}
if (GETPOSTISSET($constvalue.'_ID')) {
if (!dolibarr_set_const($db, $newconstvalue.'_ID', GETPOST($constvalue.'_ID'), 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
// If we reset this provider, we also remove the secret
if (!dolibarr_set_const($db, $constvalue.'_SECRET', GETPOST($constvalue.'_ID') ? GETPOST($constvalue.'_SECRET') : '', 'chaine', 0, '', $conf->entity)) {
$error++;
if (GETPOSTISSET($constvalue.'_SECRET')) {
if (!dolibarr_set_const($db, $newconstvalue.'_SECRET', GETPOST($constvalue.'_ID') ? GETPOST($constvalue.'_SECRET') : '', 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
if (GETPOSTISSET($constvalue.'_URLAUTHORIZE')) {
if (!dolibarr_set_const($db, $constvalue.'_URLAUTHORIZE', GETPOST($constvalue.'_URLAUTHORIZE'), 'chaine', 0, '', $conf->entity)) {
if (!dolibarr_set_const($db, $newconstvalue.'_URLAUTHORIZE', GETPOST($constvalue.'_URLAUTHORIZE'), 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
@ -90,14 +101,46 @@ if ($action == 'update') {
} else {
$scopestring = GETPOST($constvalue.'_SCOPE');
}
if (!dolibarr_set_const($db, $constvalue.'_SCOPE', $scopestring, 'chaine', 0, '', $conf->entity)) {
if (!dolibarr_set_const($db, $newconstvalue.'_SCOPE', $scopestring, 'chaine', 0, '', $conf->entity)) {
$error++;
}
} else {
if (!dolibarr_set_const($db, $constvalue.'_SCOPE', '', 'chaine', 0, '', $conf->entity)) {
} elseif ($newconstvalue !== $constvalue) {
if (!dolibarr_set_const($db, $newconstvalue.'_SCOPE', '', 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
// If name changed, we have to delete old const and proceed few other changes
if ($constvalue !== $newconstvalue) {
dolibarr_del_const($db, $constvalue.'_ID', $conf->entity);
dolibarr_del_const($db, $constvalue.'_SECRET', $conf->entity);
dolibarr_del_const($db, $constvalue.'_URLAUTHORIZE', $conf->entity);
dolibarr_del_const($db, $constvalue.'_SCOPE', $conf->entity);
// Update name of token
$oldname = preg_replace('/^OAUTH_/', '', $constvalue);
$oldprovider = ucfirst(strtolower(preg_replace('/-.*$/', '', $oldname)));
$oldlabel = preg_replace('/^.*-/', '', $oldname);
$newlabel = preg_replace('/^.*-/', '', $newconstvalue);
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
$sql.= " SET service = '".$db->escape($oldprovider."-".$newlabel)."'";
$sql.= " WHERE service = '".$db->escape($oldprovider."-".$oldlabel)."'";
$resql = $db->query($sql);
if (!$resql) {
$error++;
}
// Update const where the token was used, might not be exhaustive
if (getDolGlobalString('MAIN_MAIL_SMTPS_OAUTH_SERVICE') == $oldname) {
if (!dolibarr_set_const($db, 'MAIN_MAIL_SMTPS_OAUTH_SERVICE', strtoupper($oldprovider).'-'.$newlabel, 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
}
}
}
@ -270,11 +313,16 @@ if (count($listinsetup) > 0) {
} else {
print $label;
}
if ($keyforprovider) {
if ($servicetoeditname == $key[0]) {
print ' (<input style="width: 20%" type="text" name="'.$key[0].'" value="'.$keyforprovider.'" >)';
} elseif ($keyforprovider) {
print ' (<b>'.$keyforprovider.'</b>)';
} else {
print ' (<b>'.$langs->trans("NoName").'</b>)';
}
if (!($servicetoeditname == $key[0])) {
print '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?token='.newToken().'&servicetoeditname='.urlencode($key[0]).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a>';
}
print '</td>';
print '<td>';
if (!empty($supportedoauth2array[$keyforsupportedoauth2array]['urlforcredentials'])) {

View File

@ -1682,6 +1682,68 @@ class Setup extends DolibarrApi
return $list;
}
/**
* Get the list of incoterms.
*
* @param string $sortfield Sort field
* @param string $sortorder Sort order
* @param int $limit Number of items per page
* @param int $page Page number (starting from zero)
* @param int $active Payment term is active or not {@min 0} {@max 1}
* @param string $lang Code of the language the label of the type must be translated to
* @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
* @return array List of incoterm types
*
* @url GET dictionary/incoterms
*
* @throws RestException
*/
public function getListOfIncoterms($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
{
$list = array();
$sql = "SELECT rowid, code, active";
$sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms as t";
$sql .= " WHERE 1=1";
// Add sql filters
if ($sqlfilters) {
$errormessage = '';
if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
}
$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}
$sql .= $this->db->order($sortfield, $sortorder);
if ($limit) {
if ($page < 0) {
$page = 0;
}
$offset = $limit * $page;
$sql .= $this->db->plimit($limit, $offset);
}
$result = $this->db->query($sql);
if ($result) {
$num = $this->db->num_rows($result);
$min = min($num, ($limit <= 0 ? $num : $limit));
for ($i = 0; $i < $min; $i++) {
$type =$this->db->fetch_object($result);
$list[] = $type;
}
} else {
throw new RestException(503, 'Error when retrieving list of incoterm types : '.$this->db->lasterror());
}
return $list;
}
/**
* Get properties of company
*

View File

@ -226,7 +226,7 @@ if ($action == 'builddoc') {
'code'=>$code,
'encoding'=>$encoding,
'is2d'=>$is2d,
'photo'=>$barcodeimage // Photo must be a file that exists with format supported by TCPDF
'photo'=>!empty($barcodeimage) ? $barcodeimage : '' // Photo must be a file that exists with format supported by TCPDF
);
}
} else {

View File

@ -358,11 +358,11 @@ if (empty($reshook)) {
// Confirmation to delete
if ($action == 'delete') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteBillOfMaterials'), $langs->trans('ConfirmDeleteBillOfMaterials'), 'confirm_delete', '', 0, 1);
}
// Confirmation to delete line
if ($action == 'deleteline') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
}
// Confirmation of validation
@ -393,13 +393,13 @@ if (empty($reshook)) {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
}
// Confirmation of closing
@ -421,13 +421,13 @@ if (empty($reshook)) {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('Close'), $text, 'confirm_close', $formquestion, 0, 1, 220);
}
// Confirmation of reopen
@ -444,26 +444,26 @@ if (empty($reshook)) {
$formquestion = array();
if (isModEnabled('bom')) {
$langs->load("mrp");
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
$forcecombo = 0;
if ($conf->browser->name == 'ie') {
$forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ReOpen'), $text, 'confirm_reopen', $formquestion, 0, 1, 220);
}
// Clone confirmation
if ($action == 'clone') {
// Create an array for form
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneBillOfMaterials', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
}
// Confirmation of action xxxx
@ -471,7 +471,7 @@ if (empty($reshook)) {
$text = $langs->trans('ConfirmSetToDraft', $object->ref);
$formquestion = array();
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('SetToDraft'), $text, 'confirm_setdraft', $formquestion, 0, 1, 220);
}
// Call Hook formConfirm
@ -489,7 +489,7 @@ if (empty($reshook)) {
// Object card
// ------------------------------------------------------------
$linkback = '<a href="'.DOL_URL_ROOT.'/bom/bom_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
$linkback = '<a href="' . DOL_URL_ROOT . '/bom/bom_list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
$morehtmlref = '<div class="refidno">';
/*
@ -538,17 +538,17 @@ if (empty($reshook)) {
print '<div class="fichecenter">';
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border centpercent tableforfield">'."\n";
print '<table class="border centpercent tableforfield">' . "\n";
// Common attributes
$keyforbreak = 'duration';
include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php';
$object->calculateCosts();
print '<tr><td>'.$form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")).'</td><td><span class="amount">'.price($object->total_cost).'</span></td></tr>';
print '<tr><td>'.$langs->trans("UnitCost").'</td><td>'.price($object->unit_cost).'</td></tr>';
print '<tr><td>' . $form->textwithpicto($langs->trans("TotalCost"), $langs->trans("BOMTotalCost")) . '</td><td><span class="amount">' . price($object->total_cost) . '</span></td></tr>';
print '<tr><td>' . $langs->trans("UnitCost") . '</td><td>' . price($object->unit_cost) . '</td></tr>';
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
print '</table>';
print '</div>';
@ -559,7 +559,6 @@ if (empty($reshook)) {
print dol_get_fiche_end();
/*
* Lines
*/
@ -580,7 +579,7 @@ if (empty($reshook)) {
';
if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
}
print '<div class="div-table-responsive-no-min">';
@ -602,7 +601,7 @@ if (empty($reshook)) {
$reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
if (empty($reshook))
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
}
}
@ -652,7 +651,7 @@ if (empty($reshook)) {
$reshook = $hookmanager->executeHooks('formAddObjectServiceLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
if (empty($reshook))
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
$object->formAddObjectLine(1, $mysoc, null, '/bom/tpl');
}
}
}
@ -665,146 +664,146 @@ if (empty($reshook)) {
print "</form>\n";
mrpCollapseBomManagement();
}
$res = $object->fetchLines();
$res = $object->fetchLines();
// Buttons for actions
// Buttons for actions
if ($action != 'presend' && $action != 'editline') {
print '<div class="tabsAction">'."\n";
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if (empty($reshook)) {
// Send
//if (empty($user->socid)) {
// print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
//}
// Back to draft
if ($object->status == $object::STATUS_VALIDATED) {
if ($permissiontoadd) {
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=setdraft&token='.newToken().'">'.$langs->trans("SetToDraft").'</a>'."\n";
}
if ($action != 'presend' && $action != 'editline') {
print '<div class="tabsAction">' . "\n";
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
// Modify
if ($object->status == $object::STATUS_DRAFT) {
if ($permissiontoadd) {
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>'."\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
}
}
if (empty($reshook)) {
// Send
//if (empty($user->socid)) {
// print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
//}
// Validate
if ($object->status == $object::STATUS_DRAFT) {
if ($permissiontoadd) {
if (is_array($object->lines) && count($object->lines) > 0) {
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;action=validate&amp;token='.newToken().'">'.$langs->trans("Validate").'</a>'."\n";
} else {
$langs->load("errors");
print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>'."\n";
// Back to draft
if ($object->status == $object::STATUS_VALIDATED) {
if ($permissiontoadd) {
print '<a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=setdraft&token=' . newToken() . '">' . $langs->trans("SetToDraft") . '</a>' . "\n";
}
}
}
// Re-open
if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken().'">'.$langs->trans("ReOpen").'</a>'."\n";
}
// Create MO
if (isModEnabled('mrp')) {
if ($object->status == $object::STATUS_VALIDATED && !empty($user->rights->mrp->write)) {
print '<a class="butAction" href="'.DOL_URL_ROOT.'/mrp/mo_card.php?action=create&fk_bom='.$object->id.'&token='.newToken().'&backtopageforcancel='.urlencode($_SERVER["PHP_SELF"].'?id='.$object->id).'">'.$langs->trans("CreateMO").'</a>'."\n";
// Modify
if ($object->status == $object::STATUS_DRAFT) {
if ($permissiontoadd) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=edit&token=' . newToken() . '">' . $langs->trans("Modify") . '</a>' . "\n";
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="' . dol_escape_htmltag($langs->trans("NotEnoughPermissions")) . '">' . $langs->trans('Modify') . '</a>' . "\n";
}
}
}
// Clone
if ($permissiontoadd) {
print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : "").'&action=clone&object=bom', 'clone', $permissiontoadd);
}
// Validate
if ($object->status == $object::STATUS_DRAFT) {
if ($permissiontoadd) {
if (is_array($object->lines) && count($object->lines) > 0) {
print '<a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&amp;action=validate&amp;token=' . newToken() . '">' . $langs->trans("Validate") . '</a>' . "\n";
} else {
$langs->load("errors");
print '<a class="butActionRefused" href="" title="' . $langs->trans("ErrorAddAtLeastOneLineFirst") . '">' . $langs->trans("Validate") . '</a>' . "\n";
}
}
}
// Close / Cancel
if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
}
// Re-open
if ($permissiontoadd && $object->status == $object::STATUS_CANCELED) {
print '<a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=reopen&token=' . newToken() . '">' . $langs->trans("ReOpen") . '</a>' . "\n";
}
/*
if ($user->rights->bom->write)
{
if ($object->status == 1)
{
print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=disable&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
}
else
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=enable&token='.newToken().'">'.$langs->trans("Enable").'</a>'."\n";
}
}
*/
// Create MO
if (isModEnabled('mrp')) {
if ($object->status == $object::STATUS_VALIDATED && !empty($user->rights->mrp->write)) {
print '<a class="butAction" href="' . DOL_URL_ROOT . '/mrp/mo_card.php?action=create&fk_bom=' . $object->id . '&token=' . newToken() . '&backtopageforcancel=' . urlencode($_SERVER["PHP_SELF"] . '?id=' . $object->id) . '">' . $langs->trans("CreateMO") . '</a>' . "\n";
}
}
// Delete
print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
// Clone
if ($permissiontoadd) {
print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . (!empty($object->socid) ? '&socid=' . $object->socid : "") . '&action=clone&object=bom', 'clone', $permissiontoadd);
}
// Close / Cancel
if ($permissiontoadd && $object->status == $object::STATUS_VALIDATED) {
print '<a class="butActionDelete" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=close&token=' . newToken() . '">' . $langs->trans("Disable") . '</a>' . "\n";
}
/*
if ($user->rights->bom->write)
{
if ($object->status == 1)
{
print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=disable&token='.newToken().'">'.$langs->trans("Disable").'</a>'."\n";
}
else
{
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=enable&token='.newToken().'">'.$langs->trans("Enable").'</a>'."\n";
}
}
*/
// Delete
print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete&token=' . newToken(), 'delete', $permissiontodelete);
}
print '</div>' . "\n";
}
print '</div>'."\n";
// Select mail models is same action as presend
if (GETPOST('modelselected')) {
$action = 'presend';
}
if ($action != 'presend') {
print '<div class="fichecenter"><div class="fichehalfleft">';
print '<a name="builddoc"></a>'; // ancre
// Documents
$objref = dol_sanitizeFileName($object->ref);
$relativepath = $objref . '/' . $objref . '.pdf';
$filedir = $conf->bom->dir_output . '/' . $objref;
$urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
$genallowed = $user->rights->bom->read; // If you can read, you can build the PDF to read content
$delallowed = $user->rights->bom->write; // If you can create/edit, you can remove a file on card
print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
// Show links to link elements
$linktoelem = $form->showLinkToObjectBlock($object, null, array('bom'));
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
print '</div><div class="fichehalfright">';
$MAXEVENT = 10;
$morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT . '/bom/bom_agenda.php?id=' . $object->id);
// List of actions on element
include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
$formactions = new FormActions($db);
$somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
print '</div></div>';
}
//Select mail models is same action as presend
if (GETPOST('modelselected')) {
$action = 'presend';
}
// Presend form
$modelmail = 'bom';
$defaulttopic = 'InformationMessage';
$diroutput = $conf->bom->dir_output;
$trackid = 'bom' . $object->id;
include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
}
// Select mail models is same action as presend
if (GETPOST('modelselected')) {
$action = 'presend';
}
if ($action != 'presend') {
print '<div class="fichecenter"><div class="fichehalfleft">';
print '<a name="builddoc"></a>'; // ancre
// Documents
$objref = dol_sanitizeFileName($object->ref);
$relativepath = $objref.'/'.$objref.'.pdf';
$filedir = $conf->bom->dir_output.'/'.$objref;
$urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
$genallowed = $user->rights->bom->read; // If you can read, you can build the PDF to read content
$delallowed = $user->rights->bom->write; // If you can create/edit, you can remove a file on card
print $formfile->showdocuments('bom', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
// Show links to link elements
$linktoelem = $form->showLinkToObjectBlock($object, null, array('bom'));
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
print '</div><div class="fichehalfright">';
$MAXEVENT = 10;
$morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/bom/bom_agenda.php?id='.$object->id);
// List of actions on element
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
$formactions = new FormActions($db);
$somethingshown = $formactions->showactions($object, $object->element, 0, 1, '', $MAXEVENT, '', $morehtmlcenter);
print '</div></div>';
}
//Select mail models is same action as presend
if (GETPOST('modelselected')) {
$action = 'presend';
}
// Presend form
$modelmail = 'bom';
$defaulttopic = 'InformationMessage';
$diroutput = $conf->bom->dir_output;
$trackid = 'bom'.$object->id;
include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
}
// End of page

View File

@ -2048,7 +2048,7 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
}
}
if (!empty($contact_id) && $contact_id > 0) {
if (!is_object($cachecontacts[$contact_id])) {
if (empty($cachecontacts[$contact_id]) || !is_object($cachecontacts[$contact_id])) {
$contact = new Contact($db);
$contact->fetch($contact_id);
$cachecontacts[$contact_id] = $contact;

View File

@ -65,7 +65,7 @@ $max = $conf->global->MAIN_SIZE_SHORTLIST_LIMIT;
$now = dol_now();
// Security check
$socid = GETPOST("socid", 'int');
//$socid = GETPOST("socid", 'int');
if ($user->socid > 0) {
$action = '';
$id = $user->socid;

View File

@ -675,7 +675,7 @@ if ($object->fetch($id) >= 0) {
// Date last update
print '<td class="center nowraponall">';
print dol_print_date($obj->tms, 'dayhour');
print dol_print_date(dol_stringtotime($obj->tms), 'dayhour');
print '</td>';
// Status of recipient sending email (Warning != status of emailing)

View File

@ -101,7 +101,7 @@ if (is_resource($handle)) {
$qualified = 1;
foreach ($mailmodule->require_module as $key) {
if (!$conf->$key->enabled || (!$user->admin && $mailmodule->require_admin)) {
if (empty($conf->$key->enabled) || (!$user->admin && $mailmodule->require_admin)) {
$qualified = 0;
//print "Les pr<70>requis d'activation du module mailing ne sont pas respect<63>s. Il ne sera pas actif";
break;
@ -176,7 +176,7 @@ if ($result) {
print '<tr class="oddeven">';
print '<td class="nowrap">'.$mailstatic->getNomUrl(1).'</td>';
print '<td>'.dol_trunc($obj->title, 38).'</td>';
print '<td>'.(!empty($obj->title) ? dol_trunc($obj->title, 38) : '').'</td>';
print '<td class="center">'.dol_print_date($db->jdate($obj->date_creat), 'day').'</td>';
print '<td class="center">'.($obj->nbemail ? $obj->nbemail : "0").'</td>';
print '<td class="right">'.$mailstatic->LibStatut($obj->statut, 5).'</td>';

View File

@ -2,7 +2,7 @@
/* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2015-2019 Frederic France <frederic.france@netlogic.fr>
* Copyright (C) 2015-2023 Frederic France <frederic.france@netlogic.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
@ -115,7 +115,7 @@ class box_birthdays_members extends ModeleBoxes
$this->info_box_contents[$line][] = array(
'td' => 'class="center nowraponall"',
'text' => dol_print_date($dateb, "day", 'gmt').' - '.$age.' '.$langs->trans('DurationYears')
'text' => dol_print_date($dateb, "day", 'tzserver').' - '.$age.' '.$langs->trans('DurationYears')
);
/*$this->info_box_contents[$line][] = array(

View File

@ -120,7 +120,7 @@ class box_graph_nb_ticket_last_x_days extends ModeleBoxes
while ($i < $num) {
$objp = $this->db->fetch_object($resql);
while ($minimumdatecformated < $objp->datec) {
$dataseries[] = array('label' => dol_print_date($minimumdatecformated, 'day'), 'data' => 0);
$dataseries[] = array('label' => dol_print_date($minimumdatec, 'day'), 'data' => 0);
$minimumdatec = dol_time_plus_duree($minimumdatec, $intervaltoadd, 'd');
$minimumdatecformated = dol_print_date($minimumdatec, 'dayrfc');
}
@ -130,7 +130,7 @@ class box_graph_nb_ticket_last_x_days extends ModeleBoxes
$i++;
}
while (count($dataseries) < $days) {
$dataseries[] = array('label' => dol_print_date($minimumdatecformated, 'day'), 'data' => 0);
$dataseries[] = array('label' => dol_print_date($minimumdatec, 'day'), 'data' => 0);
$minimumdatec = dol_time_plus_duree($minimumdatec, $intervaltoadd, 'd');
$minimumdatecformated = dol_print_date($minimumdatec, 'dayrfc');
$i++;

View File

@ -1397,6 +1397,7 @@ abstract class CommonObject
$transkey = "TypeContact_".$obj->element."_".$obj->source."_".$obj->code;
$libelle_type = ($langs->trans($transkey) != $transkey ? $langs->trans($transkey) : $obj->libelle);
$tab[$i] = array(
'parentId' => $this->id,
'source' => $obj->source,
'socid' => $obj->socid,
'id' => $obj->id,

View File

@ -288,6 +288,155 @@ class SupplierOrders extends DolibarrApi
return false;
}
/**
* Get contacts of given supplier order
*
* Return an array with contact informations
*
* @param int $id ID of supplier order
* @param string $source Source of the contact (internal, external, all).
* @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER, SALESREPFOLL, ...)
* @return Object Object with cleaned properties
*
* @url GET {id}/contacts
*
* @throws RestException
*/
public function getContacts($id, $source, $type = '')
{
if (!DolibarrApiAccess::$user->rights->fournisseur->commande->lire) {
throw new RestException(401);
}
$result = $this->order->fetch($id);
if (!$result) {
throw new RestException(404, 'Supplier order not found');
}
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$contacts = array();
if ($source == 'all' || $source == 'external') {
$tmpContacts = $this->order->liste_contact(-1, 'external', 0, $type);
$contacts = array_merge($contacts, $tmpContacts);
}
if ($source == 'all' || $source == 'internal') {
$tmpContacts = $this->order->liste_contact(-1, 'internal', 0, $type);
$contacts = array_merge($contacts, $tmpContacts);
}
return $this->_cleanObjectDatas($contacts);
}
/**
* Add a contact type of given supplier order
*
* @param int $id Id of supplier order to update
* @param int $contactid Id of contact/user to add
* @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER, SALESREPFOLL, ...)
* @param string $source Source of the contact (external, internal)
* @return array
*
* @url POST {id}/contact/{contactid}/{type}/{source}
*
* @throws RestException 401
* @throws RestException 404
*/
public function postContact($id, $contactid, $type, $source)
{
if (!DolibarrApiAccess::$user->rights->fournisseur->commande->creer) {
throw new RestException(401);
}
$result = $this->order->fetch($id);
if (!$result) {
throw new RestException(404, 'Supplier order not found');
}
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$result = $this->order->add_contact($contactid, $type, $source);
if ($result < 0) {
throw new RestException(500, 'Error when added the contact');
}
if ($result == 0) {
throw new RestException(304, 'contact already added');
}
return array(
'success' => array(
'code' => 200,
'message' => 'Contact linked to the order'
)
);
}
/**
* Unlink a contact type of given supplier order
*
* @param int $id Id of supplier order to update
* @param int $contactid Id of contact/user to add
* @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER, SALESREPFOLL, ...).
* @param string $source Source of the contact (internal, external).
*
* @url DELETE {id}/contact/{contactid}/{type}/{source}
*
* @return array
*
* @throws RestException 401
* @throws RestException 404
* @throws RestException 500 System error
*/
public function deleteContact($id, $contactid, $type, $source)
{
if (!DolibarrApiAccess::$user->rights->fournisseur->commande->creer) {
throw new RestException(401);
}
$result = $this->order->fetch($id);
if (!$result) {
throw new RestException(404, 'Supplier order not found');
}
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
$contacts = $this->order->liste_contact(-1, $source, 0, $type);
$contactToUnlink = 0;
foreach ($contacts as $contact) {
if ($contact['id'] == $contactid && $contact['code'] == $type) {
$contactToUnlink = $contact['rowid'];
break;
}
}
if ($contactToUnlink == 0) {
throw new RestException(404, 'Linked contact not found');
}
$result = $this->order->delete_contact($contact['rowid']);
if (!$result) {
throw new RestException(500, 'Error when deleted the contact');
}
return array(
'success' => array(
'code' => 200,
'message' => 'Contact unlinked from supplier order'
)
);
}
/**
* Delete supplier order
*

View File

@ -2008,15 +2008,93 @@ if ($action == 'create') {
$projectid = (!empty($objectsrc->fk_project) ? $objectsrc->fk_project : '');
//$ref_client = (!empty($objectsrc->ref_client)?$object->ref_client:'');
$soc = $objectsrc->thirdparty;
$cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_supplier_id) ? $soc->cond_reglement_supplier_id : 0)); // TODO maybe add default value option
$mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_supplier_id) ? $soc->mode_reglement_supplier_id : 0));
$fk_account = (!empty($objectsrc->fk_account) ? $objectsrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0));
$remise_percent = (!empty($objectsrc->remise_percent) ? $objectsrc->remise_percent : (!empty($soc->remise_supplier_percent) ? $soc->remise_supplier_percent : 0));
$remise_absolue = (!empty($objectsrc->remise_absolue) ? $objectsrc->remise_absolue : (!empty($soc->remise_absolue) ? $soc->remise_absolue : 0));
$dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '';
$transport_mode_id = (!empty($objectsrc->transport_mode_id) ? $objectsrc->transport_mode_id : (!empty($soc->transport_mode_id) ? $soc->transport_mode_id : 0));
$cond_reglement_id = 0;
$mode_reglement_id = 0;
$fk_account = 0;
$remise_percent = 0;
$remise_absolue = 0;
$transport_mode_id = 0;
// set from object source
if (!empty($objectsrc->cond_reglement_id)) {
$cond_reglement_id = $objectsrc->cond_reglement_id;
}
if (!empty($objectsrc->mode_reglement_id)) {
$mode_reglement_id = $objectsrc->mode_reglement_id;
}
if (!empty($objectsrc->fk_account)) {
$fk_account = $objectsrc->fk_account;
}
if (!empty($objectsrc->remise_percent)) {
$remise_percent = $objectsrc->remise_percent;
}
if (!empty($objectsrc->remise_absolue)) {
$remise_absolue = $objectsrc->remise_absolue;
}
if (!empty($objectsrc->transport_mode_id)) {
$transport_mode_id = $objectsrc->transport_mode_id;
}
if (empty($cond_reglement_id)
|| empty($mode_reglement_id)
|| empty($fk_account)
|| empty($remise_percent)
|| empty($remise_absolue)
|| empty($transport_mode_id)
) {
if ($origin == 'reception') {
// try to get from source of reception (supplier order)
if (!isset($objectsrc->supplier_order)) {
$objectsrc->fetch_origin();
}
if (!empty($objectsrc->commandeFournisseur)) {
$supplierOrder = $objectsrc->commandeFournisseur;
if (empty($cond_reglement_id) && !empty($supplierOrder->cond_reglement_id)) {
$cond_reglement_id = $supplierOrder->cond_reglement_id;
}
if (empty($mode_reglement_id) && !empty($supplierOrder->mode_reglement_id)) {
$mode_reglement_id = $supplierOrder->mode_reglement_id;
}
if (empty($fk_account) && !empty($supplierOrder->fk_account)) {
$fk_account = $supplierOrder->fk_account;
}
if (empty($remise_percent) && !empty($supplierOrder->remise_percent)) {
$remise_percent = $supplierOrder->remise_percent;
}
if (empty($remise_absolue) && !empty($supplierOrder->remise_absolue)) {
$remise_absolue = $supplierOrder->remise_absolue;
}
if (empty($transport_mode_id) && !empty($supplierOrder->transport_mode_id)) {
$transport_mode_id = $supplierOrder->transport_mode_id;
}
}
}
// try to get from third-party of source object
if (!empty($soc)) {
if (empty($cond_reglement_id) && !empty($soc->cond_reglement_supplier_id)) {
$cond_reglement_id = $soc->cond_reglement_supplier_id;
}
if (empty($mode_reglement_id) && !empty($soc->mode_reglement_supplier_id)) {
$mode_reglement_id = $soc->mode_reglement_supplier_id;
}
if (empty($fk_account) && !empty($soc->fk_account)) {
$fk_account = $soc->fk_account;
}
if (empty($remise_percent) && !empty($soc->remise_supplier_percent)) {
$remise_percent = $soc->remise_supplier_percent;
}
if (empty($remise_absolue) && !empty($soc->remise_absolue)) {
$remise_absolue = $soc->remise_absolue;
}
if (empty($transport_mode_id) && !empty($soc->transport_mode_id)) {
$transport_mode_id = $soc->transport_mode_id;
}
}
}
if (isModEnabled("multicurrency")) {
if (!empty($objectsrc->multicurrency_code)) {
@ -2028,7 +2106,7 @@ if ($action == 'create') {
}
$datetmp = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
$dateinvoice = ($datetmp == '' ? (empty($conf->global->MAIN_AUTOFILL_DATE) ?-1 : '') : $datetmp);
$dateinvoice = ($datetmp == '' ? (empty($conf->global->MAIN_AUTOFILL_DATE) ? -1 : '') : $datetmp);
$datetmp = dol_mktime(12, 0, 0, GETPOST('echmonth', 'int'), GETPOST('echday', 'int'), GETPOST('echyear', 'int'));
$datedue = ($datetmp == '' ?-1 : $datetmp);

View File

@ -395,10 +395,10 @@ class Position extends CommonObject
foreach ($filter as $key => $value) {
if ($key == 't.rowid') {
$sqlwhere[] = $key . '=' . $value;
} elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
$sqlwhere[] = $key . ' = \'' . $this->db->idate($value) . '\'';
} elseif ($key == 'customsql') {
$sqlwhere[] = $value;
} elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
$sqlwhere[] = $key . ' = \'' . $this->db->idate($value) . '\'';
} elseif (strpos($value, '%') === false) {
$sqlwhere[] = $key . ' IN (' . $this->db->sanitize($this->db->escape($value)) . ')';
} else {

View File

@ -6,7 +6,7 @@
* Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
* Copyright (C) 2009 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2012 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.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
@ -128,6 +128,7 @@ class MailmanSpip
{
global $conf;
require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
//Patterns that are going to be replaced with their original value
$patterns = array(
'%LISTE%',
@ -139,7 +140,7 @@ class MailmanSpip
$list,
$object->email,
$object->pass,
$conf->global->ADHERENT_MAILMAN_ADMIN_PASSWORD
getDolGlobalString('ADHERENT_MAILMAN_ADMIN_PASSWORD')
);
$curl_url = str_replace($patterns, $replace, $url);

View File

@ -3739,7 +3739,7 @@ if ($module == 'initmodule') {
print '</td>';
print '<td>';
print dol_escape_htmltag($menu['leftmenu']);
print !empty($menu['leftmenu']) ? dol_escape_htmltag($menu['leftmenu']) : '';
print '</td>';
print '<td class="tdoverflowmax300" title="'.dol_escape_htmltag($menu['url']).'">';

View File

@ -874,6 +874,7 @@ class MyObject extends CommonObject
*/
public function getKanbanView($option = '', $arraydata = null)
{
global $conf, $langs;
$return = '<div class="box-flex-item box-flex-grow-zero">';
$return .= '<div class="info-box info-box-sm">';
$return .= '<span class="info-box-icon bg-infobox-action">';

View File

@ -6303,6 +6303,59 @@ class Product extends CommonObject
return $prodDurationHours;
}
/**
* Return clicable link of object (with eventually picto)
*
* @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
* @return string HTML Code for Kanban thumb.
*/
public function getKanbanView($option = '')
{
global $langs,$conf;
$return = '<div class="box-flex-item box-flex-grow-zero">';
$return .= '<div class="info-box info-box-sm">';
$return .= '<div class="info-box-img">';
$label = '';
if ($this->is_photo_available($conf->product->multidir_output[$this->entity])) {
$label .= $this->show_photos('product', $conf->product->multidir_output[$this->entity]);
$return .= $label;
} else {
if ($this->type == Product::TYPE_PRODUCT) {
$label .= img_picto('', 'product');
} elseif ($this->type == Product::TYPE_SERVICE) {
$label .= img_picto('', 'service');
}
$return .= $label;
}
$return .= '</div>';
$return .= '<div class="info-box-content">';
$return .= '<span class="info-box-ref">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
if (property_exists($this, 'label')) {
$return .= '<br><span class="info-box-label opacitymedium">'.$this->label.'</span>';
}
if (property_exists($this, 'price') && property_exists($this, 'price_ttc')) {
if ($this->price_base_type == 'TTC') {
$return .= '<br><span class="info-box-status amount">'.price($this->price_ttc).' '.$langs->trans("TTC").'</span>';
} else {
if ($this->status) {
$return .= '<br><span class="info-box-status amount">'.price($this->price).' '.$langs->trans("HT").'</span>';
}
}
}
if (property_exists($this, 'stock_reel')) {
$return .= '<br><span class="info-box-status opacitymedium">'.$langs->trans('PhysicalStock').' : <span class="bold">'.$this->stock_reel.'</span></span>';
}
if (method_exists($this, 'getLibStatut')) {
$return .='<br><span class="info-box-status margintoponly">'.$this->getLibStatut(5, 1).' '.$this->getLibStatut(5, 0).'</span>';
}
$return .= '</div>';
$return .= '</div>';
$return .= '</div>';
return $return;
}
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -133,6 +133,7 @@ $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
$form = new Form($db);
$htmlother = new FormOther($db);
if ($objp->stock_physique < 0) { print '<span class="warning">'; }
$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
$sql .= ' p.fk_product_type, p.tms as datem,';
@ -406,8 +407,8 @@ if ($resql) {
}
print '</tr>';
//Line for column titles
print "<tr class=\"liste_titre\">";
// Line for column titles
print '<tr class="liste_titre">';
// Action column
if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
print_liste_field_titre('');
@ -480,14 +481,20 @@ if ($resql) {
print '</td>';
}
//print '<td class="right">'.$objp->stock_theorique.'</td>';
print '<td class="right">'.$objp->seuil_stock_alerte.'</td>';
print '<td class="right">'.$objp->desiredstock.'</td>';
print '<td class="right">';
print $objp->seuil_stock_alerte;
print '</td>';
print '<td class="right">';
print $objp->desiredstock;
print '</td>';
// Real stock
print '<td class="right">';
if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $objp->seuil_stock_alerte)) {
print img_warning($langs->trans("StockTooLow")).' ';
print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
}
if ($objp->stock_physique < 0) { print '<span class="warning">'; }
print price2num($objp->stock_physique, 'MS');
if ($objp->stock_physique < 0) { print '</span>'; }
print '</td>';
// Details per warehouse
@ -505,14 +512,16 @@ if ($resql) {
if ($virtualdiffersfromphysical) {
print '<td class="right">';
if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < $objp->seuil_stock_alerte)) {
print img_warning($langs->trans("StockTooLow")).' ';
print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
}
if ($objp->stock_physique < 0) { print '<span class="warning">'; }
print price2num($product->stock_theorique, 'MS');
if ($objp->stock_physique < 0) { print '</span>'; }
print '</td>';
}
// Units
if (!empty($conf->global->PRODUCT_USE_UNITS)) {
print '<td class="left">'.$objp->unit_short.'</td>';
print '<td class="left">'.dol_escape_htmltag($objp->unit_short).'</td>';
}
print '<td class="center">';
print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');

View File

@ -716,8 +716,9 @@ while ($i < $imaxinloop) {
}
print '<td class="right">';
//if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
if ($objp->stock_physique < 0) { print '<span class="warning">'; }
print $objp->stock_physique;
if ($objp->stock_physique < 0) { print '</span>'; }
print '</td>';
print '<td class="right">';

View File

@ -252,15 +252,98 @@ if (empty($reshook)) {
}
}
} else {
$cond_reglement_id = 0;
$mode_reglement_id = 0;
$fk_account = 0;
$remise_percent = 0;
$remise_absolue = 0;
$transport_mode_id = 0;
if (!empty($rcp->cond_reglement_id)) {
$cond_reglement_id = $rcp->cond_reglement_id;
}
if (!empty($rcp->mode_reglement_id)) {
$mode_reglement_id = $rcp->mode_reglement_id;
}
if (!empty($rcp->fk_account)) {
$fk_account = $rcp->fk_account;
}
if (!empty($rcp->remise_percent)) {
$remise_percent = $rcp->remise_percent;
}
if (!empty($rcp->remise_absolue)) {
$remise_absolue = $rcp->remise_absolue;
}
if (!empty($rcp->transport_mode_id)) {
$transport_mode_id = $rcp->transport_mode_id;
}
if (empty($cond_reglement_id)
|| empty($mode_reglement_id)
|| empty($fk_account)
|| empty($remise_percent)
|| empty($remise_absolue)
|| empty($transport_mode_id)
) {
if (!isset($rcp->supplier_order)) {
$rcp->fetch_origin();
}
// try to get from source of reception (supplier order)
if (!empty($rcp->commandeFournisseur)) {
$supplierOrder = $rcp->commandeFournisseur;
if (empty($cond_reglement_id) && !empty($supplierOrder->cond_reglement_id)) {
$cond_reglement_id = $supplierOrder->cond_reglement_id;
}
if (empty($mode_reglement_id) && !empty($supplierOrder->mode_reglement_id)) {
$mode_reglement_id = $supplierOrder->mode_reglement_id;
}
if (empty($fk_account) && !empty($supplierOrder->fk_account)) {
$fk_account = $supplierOrder->fk_account;
}
if (empty($remise_percent) && !empty($supplierOrder->remise_percent)) {
$remise_percent = $supplierOrder->remise_percent;
}
if (empty($remise_absolue) && !empty($supplierOrder->remise_absolue)) {
$remise_absolue = $supplierOrder->remise_absolue;
}
if (empty($transport_mode_id) && !empty($supplierOrder->transport_mode_id)) {
$transport_mode_id = $supplierOrder->transport_mode_id;
}
}
// try get from third-party of reception
if (!empty($rcp->thirdparty)) {
$soc = $rcp->thirdparty;
if (empty($cond_reglement_id) && !empty($soc->cond_reglement_supplier_id)) {
$cond_reglement_id = $soc->cond_reglement_supplier_id;
}
if (empty($mode_reglement_id) && !empty($soc->mode_reglement_supplier_id)) {
$mode_reglement_id = $soc->mode_reglement_supplier_id;
}
if (empty($fk_account) && !empty($soc->fk_account)) {
$fk_account = $soc->fk_account;
}
if (empty($remise_percent) && !empty($soc->remise_supplier_percent)) {
$remise_percent = $soc->remise_supplier_percent;
}
if (empty($remise_absolue) && !empty($soc->remise_absolue)) {
$remise_absolue = $soc->remise_absolue;
}
if (empty($transport_mode_id) && !empty($soc->transport_mode_id)) {
$transport_mode_id = $soc->transport_mode_id;
}
}
}
// If we want one invoice per reception or if there is no first invoice yet for this thirdparty.
$objecttmp->socid = $rcp->socid;
$objecttmp->type = $objecttmp::TYPE_STANDARD;
$objecttmp->cond_reglement_id = $rcp->cond_reglement_id || $rcp->thirdparty->cond_reglement_supplier_id;
$objecttmp->mode_reglement_id = $rcp->mode_reglement_id || $rcp->thirdparty->mode_reglement_supplier_id;
$objecttmp->fk_account = !empty($rcp->thirdparty->fk_account) ? $rcp->thirdparty->fk_account : 0;
$objecttmp->remise_percent = !empty($rcp->thirdparty->remise_percent) ? $rcp->thirdparty->remise_percent : 0;
$objecttmp->remise_absolue = !empty($rcp->thirdparty->remise_absolue) ? $rcp->thirdparty->remise_absolue : 0;
$objecttmp->cond_reglement_id = $cond_reglement_id;
$objecttmp->mode_reglement_id = $mode_reglement_id;
$objecttmp->fk_account = $fk_account;
$objecttmp->remise_percent = $remise_percent;
$objecttmp->remise_absolue = $remise_absolue;
$objecttmp->transport_mode_id = $transport_mode_id;
$objecttmp->fk_project = $rcp->fk_project;
//$objecttmp->multicurrency_code = $rcp->multicurrency_code;
@ -280,6 +363,11 @@ if (empty($reshook)) {
$objecttmp->origin = 'reception';
$objecttmp->origin_id = $id_reception;
// Auto calculation of date due if not filled by user
if (empty($objecttmp->date_echeance)) {
$objecttmp->date_echeance = $objecttmp->calculate_date_lim_reglement();
}
$objecttmp->array_options = $rcp->array_options; // Copy extrafields
// Set $objecttmp->linked_objects with all links order_supplier existing on reception, so same links will be added to the generated supplier invoice

View File

@ -189,6 +189,31 @@ a.info-box-text-a i.fa.fa-exclamation-triangle {
bottom: 0;
}
/* customize section img box on list of products */
.info-box-img {
height: 105px !important;
width: 88px;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px;
display: block;
overflow: hidden;
float: left;
text-align: center;
font-size: 2.8em;
line-height: 90px;
margin-right: 5px;
background: var(--colorbacktitle1) !important;
}
.info-box-img > img {
width: 90%;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<?php if (empty($conf->global->MAIN_DISABLE_GLOBAL_BOXSTATS) && !empty($conf->global->MAIN_INCLUDE_GLOBAL_STATS_IN_OPENED_DASHBOARD)) { ?>
.info-box-icon-text{
opacity: 1;

View File

@ -83,4 +83,4 @@ if ($res == -1) {
exit();
}
print json_encode($res);
print json_encode($res, JSON_PARTIAL_OUTPUT_ON_ERROR);

View File

@ -511,7 +511,7 @@ if (!empty($id) || !empty($ref)) {
<script type="text/javascript">
variants_available = <?php echo json_encode($prodattr_alljson); ?>;
variants_available = <?php echo json_encode($prodattr_alljson, JSON_PARTIAL_OUTPUT_ON_ERROR); ?>;
variants_selected = {
index: [],
info: []