diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 5c4c4aae9f1..6c063c61a8d 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -221,7 +221,7 @@ if (empty($reshook)) { } } - $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : null), (GETPOST('update_prices', 'aZ') ? true : false)); + $result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOST('entity', 'int') : null), (GETPOST('update_prices', 'aZ') ? true : false), (GETPOST('update_desc', 'aZ') ? true : false)); if ($result > 0) { header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); exit(); @@ -2137,7 +2137,8 @@ if ($action == 'create') { // 'text' => $langs->trans("ConfirmClone"), // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid', 'int'), 'socid', '(s.client=1 OR s.client=2 OR s.client=3)', '', 0, 0, null, 0, 'maxwidth300')), - array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => (!empty($conf->global->PROPOSAL_CLONE_UPDATE_PRICES) ? 1 : 0)), + array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0), + array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0), ); if (!empty($conf->global->PROPAL_CLONE_DATE_DELIVERY) && !empty($object->delivery_date)) { $formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date); diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 40e8fe385d7..09bdfb94d73 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1360,9 +1360,10 @@ class Propal extends CommonObject * @param int $socid Id of thirdparty * @param int $forceentity Entity id to force * @param bool $update_prices [=false] Update prices if true + * @param bool $update_desc [=false] Update description if true * @return int New id of clone */ - public function createFromClone(User $user, $socid = 0, $forceentity = null, $update_prices = false) + public function createFromClone(User $user, $socid = 0, $forceentity = null, $update_prices = false, $update_desc = false) { global $conf, $hookmanager, $mysoc; @@ -1413,9 +1414,9 @@ class Propal extends CommonObject } // update prices - if ($update_prices === true) { + if ($update_prices === true || $update_desc === true) { if ($objsoc->id > 0 && !empty($object->lines)) { - if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { + if ($update_prices === true && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { // If price per customer require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php'; } @@ -1425,36 +1426,41 @@ class Propal extends CommonObject $prod = new Product($this->db); $res = $prod->fetch($line->fk_product); if ($res > 0) { - $pu_ht = $prod->price; - $tva_tx = get_default_tva($mysoc, $objsoc, $prod->id); - $remise_percent = $objsoc->remise_percent; + if ($update_prices === true) { + $pu_ht = $prod->price; + $tva_tx = get_default_tva($mysoc, $objsoc, $prod->id); + $remise_percent = $objsoc->remise_percent; - if (!empty($conf->global->PRODUIT_MULTIPRICES) && $objsoc->price_level > 0) { - $pu_ht = $prod->multiprices[$objsoc->price_level]; - if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility - if (isset($prod->multiprices_tva_tx[$objsoc->price_level])) { - $tva_tx = $prod->multiprices_tva_tx[$objsoc->price_level]; + if (!empty($conf->global->PRODUIT_MULTIPRICES) && $objsoc->price_level > 0) { + $pu_ht = $prod->multiprices[$objsoc->price_level]; + if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility + if (isset($prod->multiprices_tva_tx[$objsoc->price_level])) { + $tva_tx = $prod->multiprices_tva_tx[$objsoc->price_level]; + } } - } - } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { - $prodcustprice = new Productcustomerprice($this->db); - $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $objsoc->id); - $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); - if ($result) { - // If there is some prices specific to the customer - if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { + $prodcustprice = new Productcustomerprice($this->db); + $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $objsoc->id); + $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); + if ($result) { + // If there is some prices specific to the customer + if (count($prodcustprice->lines) > 0) { + $pu_ht = price($prodcustprice->lines[0]->price); + $tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); + if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + } } } } - } - $line->subprice = $pu_ht; - $line->tva_tx = $tva_tx; - $line->remise_percent = $remise_percent; + $line->subprice = $pu_ht; + $line->tva_tx = $tva_tx; + $line->remise_percent = $remise_percent; + } + if ($update_desc === true) { + $line->desc = $prod->description; + } } } } diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 85020ab2150..0a95a44488d 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -591,8 +591,6 @@ class Facture extends CommonInvoice // We do not add link to template invoice or next invoice will be linked to all generated invoices //$this->linked_objects['facturerec'][0] = $this->fac_rec; - $forceduedate = $this->calculate_date_lim_reglement(); - // For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice if ($_facrec->frequency > 0) { dol_syslog("This is a recurring invoice so we set date_last_gen and next date_when"); diff --git a/htdocs/core/ajax/ajaxtooltip.php b/htdocs/core/ajax/ajaxtooltip.php index 90c416100cb..9a4d42ce5bb 100644 --- a/htdocs/core/ajax/ajaxtooltip.php +++ b/htdocs/core/ajax/ajaxtooltip.php @@ -79,7 +79,7 @@ top_httphead(); $html = ''; if (is_object($object)) { - if ($object->id > 0) { + if ($object->id > 0 || !empty($object->ref)) { $html = $object->getTooltipContent($params); } elseif ($res == 0) { $html = $langs->trans('Deleted'); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 5415a96ed4f..f11548d6a5a 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -391,6 +391,22 @@ abstract class CommonObject */ public $shipping_method_id; + /** + * @var string Shipping method label + * @see setShippingMethod() + */ + public $shipping_method; + + /** + * @var string multicurrency code + */ + public $multicurrency_code; + + /** + * @var string multicurrency tx + */ + public $multicurrency_tx; + /** * @var string * @see SetDocModel() diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index ef68d5c5ff2..113c295a97b 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8064,14 +8064,6 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : ''); $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl; - if (is_object($object) && $object->element == 'propal') { - require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; - $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref); - } - if (is_object($object) && $object->element == 'fichinter') { - require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; - $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref); - } if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') { $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element); } else { @@ -8105,6 +8097,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, if (is_object($object) && $object->element == 'propal') { $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref); } if (is_object($object) && $object->element == 'commande') { $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id; @@ -8114,9 +8108,13 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, } if (is_object($object) && $object->element == 'contrat') { $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref); } if (is_object($object) && $object->element == 'fichinter') { $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref); } if (is_object($object) && $object->element == 'supplier_proposal') { $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id; @@ -11285,6 +11283,11 @@ function getElementProperties($element_type) $subelement = 'commande'; } elseif ($element_type == 'propal') { $classpath = 'comm/propal/class'; + } elseif ($element_type == 'shipping') { + $classpath = 'expedition/class'; + $classfile = 'expedition'; + $classname = 'Expedition'; + $module = 'expedition'; } elseif ($element_type == 'supplier_proposal') { $classpath = 'supplier_proposal/class'; $module = 'supplier_proposal'; @@ -11323,6 +11326,10 @@ function getElementProperties($element_type) $classpath = 'comm/propal/class'; $module = 'propal'; $subelement = 'propaleligne'; + } elseif ($element_type == 'opensurvey_sondage') { + $classpath = 'opensurvey/class'; + $module = 'opensurvey'; + $subelement = 'opensurveysondage'; } elseif ($element_type == 'order_supplier') { $classpath = 'fourn/class'; $module = 'fournisseur'; @@ -11340,7 +11347,7 @@ function getElementProperties($element_type) } elseif ($element_type == "service") { $classpath = 'product/class'; $subelement = 'product'; - } elseif ($objecttype == 'salary') { + } elseif ($element_type == 'salary') { $classpath = 'salaries/class'; $module = 'salaries'; } diff --git a/htdocs/core/tpl/extrafields_view.tpl.php b/htdocs/core/tpl/extrafields_view.tpl.php index ec7578e0aa4..38b99fc5736 100644 --- a/htdocs/core/tpl/extrafields_view.tpl.php +++ b/htdocs/core/tpl/extrafields_view.tpl.php @@ -212,7 +212,7 @@ if (empty($reshook) && isset($extrafields->attributes[$object->table_element]['l $html_id = !empty($object->id) ? $object->element.'_extras_'.$tmpkeyextra.'_'.$object->id : ''; - print ''; + print ''; // Convert date into timestamp format if (in_array($extrafields->attributes[$object->table_element]['type'][$tmpkeyextra], array('date'))) { diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 7b1c8ae6df7..6e987b38050 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -1834,7 +1834,8 @@ class Expedition extends CommonObject { global $conf, $langs; - $langs->load('shipping'); + $langs->load('sendings'); + $nofetch = !empty($params['nofetch']); $datas = array(); @@ -1844,6 +1845,13 @@ class Expedition extends CommonObject } $datas['ref'] = '
'.$langs->trans('Ref').': '.$this->ref; $datas['refcustomer'] = '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); + if (!$nofetch) { + $langs->load('companies'); + if (empty($this->thirdparty)) { + $this->fetch_thirdparty(); + } + $datas['customer'] = '
'.$langs->trans('Customer').': '.$this->thirdparty->getNomUrl(1, '', 0, 1); + } return $datas; } diff --git a/htdocs/install/mysql/migration/17.0.0-18.0.0.sql b/htdocs/install/mysql/migration/17.0.0-18.0.0.sql index a63c5313bae..fb8cb956a6d 100644 --- a/htdocs/install/mysql/migration/17.0.0-18.0.0.sql +++ b/htdocs/install/mysql/migration/17.0.0-18.0.0.sql @@ -380,3 +380,6 @@ ALTER TABLE llx_product_lot ADD COLUMN last_main_doc varchar(255) AFTER model_pd ALTER TABLE llx_product_fournisseur_price ADD COLUMN status integer DEFAULT 1; +ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_product_fournisseur (fk_product_fournisseur); +ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_user (fk_user); +--ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_multicurrency (fk_multicurrency); diff --git a/htdocs/install/mysql/tables/llx_product_fournisseur_price_log.key.sql b/htdocs/install/mysql/tables/llx_product_fournisseur_price_log.key.sql new file mode 100644 index 00000000000..63949eeaf53 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_product_fournisseur_price_log.key.sql @@ -0,0 +1,21 @@ +-- ============================================================================ +-- Copyright (C) 2023 Frédéric France +-- +-- 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 +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ============================================================================ + +ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_product_fournisseur (fk_product_fournisseur); +ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_user (fk_user); +--ALTER TABLE llx_product_fournisseur_price_log ADD INDEX idx_product_fournisseur_price_log_fk_multicurrency (fk_multicurrency); diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 595507a4bf4..194e2ca0dcd 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -55,6 +55,7 @@ CopyPropalFrom=Create commercial proposal by copying existing proposal CreateEmptyPropal=Create empty commercial proposal or from list of products/services DefaultProposalDurationValidity=Default commercial proposal validity duration (in days) DefaultPuttingPricesUpToDate=By default update prices with current known prices on cloning a proposal +DefaultPuttingDescUpToDate=By default update descriptions with current known descriptions on cloning a proposal UseCustomerContactAsPropalRecipientIfExist=Use contact/address with type 'Contact following-up proposal' if defined instead of third party address as proposal recipient address ConfirmClonePropal=Are you sure you want to clone the commercial proposal %s? ConfirmReOpenProp=Are you sure you want to open back the commercial proposal %s? diff --git a/htdocs/langs/fr_FR/propal.lang b/htdocs/langs/fr_FR/propal.lang index 66a0093db96..6e3d8b16870 100644 --- a/htdocs/langs/fr_FR/propal.lang +++ b/htdocs/langs/fr_FR/propal.lang @@ -55,6 +55,7 @@ CopyPropalFrom=Créer proposition/devis par recopie d'un proposition existante CreateEmptyPropal=Créer proposition/devis vierge ou avec la liste des produits/services DefaultProposalDurationValidity=Délai de validité par défaut (en jours) DefaultPuttingPricesUpToDate=Par défaut, mettre à jour les prix avec les prix connus actuels lors du clonage d'une proposition +DefaultPuttingDescUpToDate=Par défaut, mettre à jour les descriptions lors de clonage d'une proposition commerciale UseCustomerContactAsPropalRecipientIfExist=Utiliser l'adresse de 'contact suivi client' si définie plutôt que l'adresse du tiers comme destinataire des propositions ConfirmClonePropal=Êtes-vous sûr de vouloir cloner la proposition commerciale %s ? ConfirmReOpenProp=Êtes-vous sûr de vouloir réouvrir la proposition commerciale %s ?