diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 09f69993310..86e07ed424d 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -1103,6 +1103,23 @@ class BOM extends CommonObject } } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'bom_bomline' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Get Net needs by product * diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index f93f5aeccb7..ac26cf0c56a 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -2236,6 +2236,26 @@ class ActionComm extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $dbs Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id) + { + $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'actioncomm SET fk_element = ' . ((int) $dest_id) . ' WHERE elementtype="product" AND fk_element = '.((int) $origin_id); + // using $dbs, not $this->db because function is static + if (!$dbs->query($sql)) { + //$this->errors = $dbs->lasterror(); + return false; + } + + return true; + } + /** * Is the action delayed? * diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index a30fc456b18..be10e45383c 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -3821,8 +3821,24 @@ class Propal extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } -} + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'propaldet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } +} /** * Class to manage commercial proposal lines diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 4c745948f52..f17006738bf 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -4039,6 +4039,23 @@ class Commande extends CommonOrder return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commandedet', + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the customer order delayed? * diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 219d8bee154..324800910da 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -1728,7 +1728,7 @@ class Account extends CommonObject if ($dbs->query($sql)) { return true; } else { - //if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B. + //if ($ignoreerrors) return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B. //$this->errors = $dbs->lasterror(); return false; } diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index 290467a9d54..91d0fd0f20a 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -1759,6 +1759,23 @@ class FactureRec extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facturedet_rec' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Update frequency and unit * diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index af029376d53..5fe58adcd7b 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4818,6 +4818,23 @@ class Facture extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facturedet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the customer invoice delayed? * diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 68ac203d955..d85ad51946a 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -2474,6 +2474,23 @@ class Contrat extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'contratdet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Load an object from its id and create a new one in database * diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 469f2753839..0a351f08ff3 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -8120,7 +8120,7 @@ abstract class CommonObject /** * Function used to replace a thirdparty id with another one. - * This function is meant to be called from replaceThirdparty with the appropiate tables + * This function is meant to be called from replaceThirdparty with the appropriate tables * Column name fk_soc MUST be used to identify thirdparties * * @param DoliDB $db Database handler @@ -8137,7 +8137,36 @@ abstract class CommonObject if (!$db->query($sql)) { if ($ignoreerrors) { - return true; // TODO Not enough. If there is A-B on kept thirdarty and B-C on old one, we must get A-B-C after merge. Not A-B. + return true; // TODO Not enough. If there is A-B on kept thirdparty and B-C on old one, we must get A-B-C after merge. Not A-B. + } + //$this->errors = $db->lasterror(); + return false; + } + } + + return true; + } + + /** + * Function used to replace a product id with another one. + * This function is meant to be called from replaceProduct with the appropriate tables + * Column name fk_product MUST be used to identify products + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id (the product to delete) + * @param int $dest_id New product id (the product that will received element of the other) + * @param string[] $tables Tables that need to be changed + * @param int $ignoreerrors Ignore errors. Return true even if errors. We need this when replacement can fails like for categories (categorie of old product may already exists on new one) + * @return bool True if success, False if error + */ + public static function commonReplaceProduct(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors = 0) + { + foreach ($tables as $table) { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_product = '.((int) $dest_id).' WHERE fk_product = '.((int) $origin_id); + + if (!$db->query($sql)) { + if ($ignoreerrors) { + return true; // TODO Not enough. If there is A-B on kept product and B-C on old one, we must get A-B-C after merge. Not A-B. } //$this->errors = $db->lasterror(); return false; diff --git a/htdocs/delivery/class/delivery.class.php b/htdocs/delivery/class/delivery.class.php index ab1f1563ab7..f41b855e123 100644 --- a/htdocs/delivery/class/delivery.class.php +++ b/htdocs/delivery/class/delivery.class.php @@ -1092,6 +1092,23 @@ class Delivery extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'deliverydet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/fichinter/class/fichinterrec.class.php b/htdocs/fichinter/class/fichinterrec.class.php index d3f3c82636e..4488b4643b8 100644 --- a/htdocs/fichinter/class/fichinterrec.class.php +++ b/htdocs/fichinter/class/fichinterrec.class.php @@ -40,7 +40,7 @@ class FichinterRec extends Fichinter { public $element = 'fichinterrec'; public $table_element = 'fichinter_rec'; - public $table_element_line = 'fichinter_rec'; + public $table_element_line = 'fichinterdet_rec'; /** * @var string Fieldname with ID of parent key if this field has a parent @@ -706,6 +706,22 @@ class FichinterRec extends Fichinter return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'fichinterdet_rec' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } /** * Update frequency and unit diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 327bfc867d9..07ae8554a86 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3249,6 +3249,23 @@ class CommandeFournisseur extends CommonOrder return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commande_fournisseurdet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the supplier order delayed? * We suppose a purchase ordered as late if a the purchase order has been sent and the delivery date is set and before the delay. diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 9912f71df4b..da71a2a795d 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -3153,6 +3153,23 @@ class FactureFournisseur extends CommonInvoice return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture_fourn_det' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * Is the payment of the supplier invoice having a delay? * diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index 396995c4c86..55aabde8141 100644 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -972,6 +972,23 @@ class ProductFournisseur extends Product return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'product_fournisseur_price' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } + /** * List supplier prices log of a supplier price * diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index f843277c87a..be9918a7f7c 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -409,6 +409,11 @@ mandatoryHelper=Check this if you want a message to the user when creating / val DefaultBOM=Default BOM DefaultBOMDesc=The default BOM recommended to use to manufacture this product. This field can be set only if nature of product is '%s'. Rank=Rank +MergeOriginProduct=Duplicate product (product you want to delete) +MergeProducts=Merge products +ConfirmMergeProducts=Are you sure you want to merge the chosen product with the current one? All linked objects (invoices, orders, ...) will be moved to the current product, after which the chosen product will be deleted. +ProductsMergeSuccess=Products have been merged +ErrorsProductsMerge=Errors in products merge SwitchOnSaleStatus=Switch on sale status SwitchOnPurchaseStatus=Switch on purchase status StockMouvementExtraFields= Extra Fields (stock mouvement) diff --git a/htdocs/product/card.php b/htdocs/product/card.php index beb2e015fc4..efa14b1e582 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -226,6 +226,174 @@ if (empty($reshook)) { } $action = ''; } + // merge products + if ($action == 'confirm_merge' && $confirm == 'yes' && $user->rights->societe->creer) { + $error = 0; + $productOriginId = GETPOST('product_origin', 'int'); + $productOrigin = new Product($db); + + if ($productOriginId <= 0) { + $langs->load('errors'); + setEventMessages($langs->trans('ErrorProductIdIsMandatory', $langs->transnoentitiesnoconv('MergeOriginProduct')), null, 'errors'); + } else { + if (!$error && $productOrigin->fetch($productOriginId) < 1) { + setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors'); + $error++; + } + + if (!$error) { + // TODO Move the merge function into class of object. + $db->begin(); + + // Recopy some data + $listofproperties = array( + 'ref', + 'ref_ext', + 'label', + 'description', + 'url', + 'barcode', + 'fk_barcode_type', + 'import_key', + 'mandatory_period', + 'accountancy_code_buy', + 'accountancy_code_buy_intra', + 'accountancy_code_buy_export', + 'accountancy_code_sell', + 'accountancy_code_sell_intra', + 'accountancy_code_sell_export' + ); + foreach ($listofproperties as $property) { + if (empty($object->$property)) { + $object->$property = $productOrigin->$property; + } + } + // Concat some data + $listofproperties = array( + 'note_public', 'note_private' + ); + foreach ($listofproperties as $property) { + $object->$property = dol_concatdesc($object->$property, $productOrigin->$property); + } + + // Merge extrafields + if (is_array($productOrigin->array_options)) { + foreach ($productOrigin->array_options as $key => $val) { + if (empty($object->array_options[$key])) { + $object->array_options[$key] = $val; + } + } + } + + // Merge categories + $static_cat = new Categorie($db); + $custcats_ori = $static_cat->containing($productOrigin->id, 'product', 'id'); + $custcats = $static_cat->containing($object->id, 'product', 'id'); + $custcats = array_merge($custcats, $custcats_ori); + $object->setCategories($custcats); + + // If product has a new code that is same than origin, we clean origin code to avoid duplicate key from database unique keys. + if ($productOrigin->barcode == $object->barcode) { + dol_syslog("We clean customer and supplier code so we will be able to make the update of target"); + $productOrigin->barcode = ''; + //$productOrigin->update($productOrigin->id, $user, 0, 'merge'); + } + + // Update + $result = $object->update($object->id, $user, 0, 'merge'); + if ($result <= 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + + // Move links + if (!$error) { + // TODO add this functionality into the api_products.class.php + // TODO Mutualise the list into object product.class.php + $objects = array( + 'ActionComm' => '/comm/action/class/actioncomm.class.php', + 'Bom' => '/bom/class/bom.class.php', + // do not use Categorie, it cause foreign key error, merge is done before + //'Categorie' => '/categories/class/categorie.class.php', + 'Commande' => '/commande/class/commande.class.php', + 'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php', + 'Contrat' => '/contrat/class/contrat.class.php', + 'Delivery' => '/delivery/class/delivery.class.php', + 'Facture' => '/compta/facture/class/facture.class.php', + 'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php', + 'FactureRec' => '/compta/facture/class/facture-rec.class.php', + 'FichinterRec' => '/fichinter/class/fichinterrec.class.php', + 'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php', + 'Propal' => '/comm/propal/class/propal.class.php', + 'Reception' => '/reception/class/reception.class.php', + 'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php', + ); + + //First, all core objects must update their tables + foreach ($objects as $object_name => $object_file) { + require_once DOL_DOCUMENT_ROOT.$object_file; + + if (!$error && !$object_name::replaceProduct($db, $productOrigin->id, $object->id)) { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + break; + } + } + } + + // External modules should update their ones too + if (!$error) { + $reshook = $hookmanager->executeHooks( + 'replaceProduct', + array( + 'soc_origin' => $productOrigin->id, + 'soc_dest' => $object->id, + ), + $object, + $action + ); + + if ($reshook < 0) { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + $error++; + } + } + + + if (!$error) { + $object->context = array( + 'merge' => 1, + 'mergefromid' => $productOrigin->id, + ); + + // Call trigger + $result = $object->call_trigger('PRODUCT_MODIFY', $user); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + // End call triggers + } + + if (!$error) { + // We finally remove the old product + // TODO merge attached files from old product into new one before delete + if ($productOrigin->delete($user) < 1) { + $error++; + } + } + + if (!$error) { + setEventMessages($langs->trans('ProductsMergeSuccess'), null, 'mesgs'); + $db->commit(); + } else { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorsProductsMerge'), null, 'errors'); + $db->rollback(); + } + } + } + } // Type if ($action == 'setfk_product_type' && $usercancreate) { @@ -2502,6 +2670,17 @@ if (($action == 'delete' && (empty($conf->use_javascript_ajax) || !empty($conf-> || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js $formconfirm = $form->formconfirm("card.php?id=".$object->id, $langs->trans("DeleteProduct"), $langs->trans("ConfirmDeleteProduct"), "confirm_delete", '', 0, "action-delete"); } +if ($action == 'merge') { + $formquestion = array( + array( + 'name' => 'product_origin', + 'label' => $langs->trans('MergeOriginProduct'), + 'type' => 'other', + 'value' => $form->select_produits('', 'product_origin', '', 0, 0, 1, 2, '', 1, array(), 0, 1, 0, 'minwidth200', 0, '', null, 1), + ) + ); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("MergeProducts"), $langs->trans("ConfirmMergeProducts"), "confirm_merge", $formquestion, 'no', 1, 250); +} // Clone confirmation if (($action == 'clone' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js @@ -2572,6 +2751,9 @@ if ($action != 'create' && $action != 'edit') { } else { print dolGetButtonAction($langs->trans("ProductIsUsed"), $langs->trans('Delete'), 'delete', '#', '', false); } + if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 1) { + print ''.$langs->trans('Merge').''."\n"; + } } else { print dolGetButtonAction($langs->trans("NotEnoughPermissions"), $langs->trans('Delete'), 'delete', '#', '', false); } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index d308ceb8e53..365b5e90916 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -491,8 +491,7 @@ class Product extends CommonObject 'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000), //'tosell' =>array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Active', -1=>'Cancel')), //'tobuy' =>array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Active', -1=>'Cancel')), - 'mandatory_period' =>array('type'=>'integer', 'label'=>'mandatory_period', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000), - + 'mandatory_period' => array('type'=>'integer', 'label'=>'mandatory_period', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000), ); /** diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php index 08756f5454d..2ff316ecb58 100644 --- a/htdocs/reception/class/reception.class.php +++ b/htdocs/reception/class/reception.class.php @@ -2078,4 +2078,21 @@ class Reception extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commande_fournisseur_dispatch' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index 168a0f8d4ee..6fa4c0e5de9 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -2697,6 +2697,23 @@ class SupplierProposal extends CommonObject return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); } + + /** + * Function used to replace a product id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old product id + * @param int $dest_id New product id + * @return bool + */ + public static function replaceProduct(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'supplier_proposaldet' + ); + + return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables); + } }