diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index e302c83e2d8..4ae9fe197fe 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -5171,11 +5171,11 @@ class FactureLigne extends CommonInvoiceLine // Check parameters if ($this->product_type < 0) return -1; - // if buy price not defined, define buyprice as configured in margin admin - if ($this->pa_ht == 0 && $pa_ht_isemptystring) - { - if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0) - { + // if buy price not provided, define buyprice as configured in margin admin + if ($this->pa_ht == 0 && $pa_ht_isemptystring) { + // We call defineBuyPrice only if data was not provided (if input was '0', we will not go here and value will remaine '0') + $result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product); + if ($result < 0) { return $result; } else { $this->pa_ht = $result; @@ -5214,7 +5214,7 @@ class FactureLigne extends CommonInvoiceLine $sql .= ", total_localtax2=".price2num($this->total_localtax2); } $sql .= ", fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? "'".$this->db->escape($this->fk_fournprice)."'" : "null"); - $sql .= ", buy_price_ht='".price2num($this->pa_ht)."'"; + $sql .= ", buy_price_ht=".(($this->pa_ht || $this->pa_ht === 0 || $this->pa_ht === '0') ? price2num($this->pa_ht) : "null"); // $this->pa_ht should always be defined (set to 0 or to sell price depending on option) $sql .= ", fk_parent_line=".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null"); if (!empty($this->rang)) $sql .= ", rang=".$this->rang; $sql .= ", situation_percent=".$this->situation_percent; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index af2c902aacb..8a3f50c02a4 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7122,7 +7122,7 @@ abstract class CommonObject $buyPrice = 0; - if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) // In most cases, test here is false + if (($unitPrice > 0) && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) // In most cases, test here is false { $buyPrice = $unitPrice * (1 - $discountPercent / 100); } else { diff --git a/htdocs/core/class/html.formmargin.class.php b/htdocs/core/class/html.formmargin.class.php index 233f98df662..608698cf1b1 100644 --- a/htdocs/core/class/html.formmargin.class.php +++ b/htdocs/core/class/html.formmargin.class.php @@ -91,8 +91,10 @@ class FormMargin if ($product->fetch_product_fournisseur_price($line->fk_fournprice)) $line->pa_ht = $product->fourn_unitprice * (1 - $product->fourn_remise_percent / 100); } - // si prix d'achat non renseignĂ© et devrait l'ĂȘtre, alors prix achat = prix vente - if ((!isset($line->pa_ht) || $line->pa_ht == 0) && $line->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) { + + // If buy price is not defined (null), we will use the sell price. If defined to 0 (it means it was forced to 0 during insert, for example for a free to get product), we must still use 0. + //if ((!isset($line->pa_ht) || $line->pa_ht == 0) && $line->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) { + if ((!isset($line->pa_ht)) && $line->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull > 0)) { $line->pa_ht = $line->subprice * (1 - ($line->remise_percent / 100)); } diff --git a/htdocs/langs/en_US/margins.lang b/htdocs/langs/en_US/margins.lang index 76ea8ad5c4d..c3bff2305de 100644 --- a/htdocs/langs/en_US/margins.lang +++ b/htdocs/langs/en_US/margins.lang @@ -22,7 +22,7 @@ ProductService=Product or Service AllProducts=All products and services ChooseProduct/Service=Choose product or service ForceBuyingPriceIfNull=Force buying/cost price to selling price if not defined -ForceBuyingPriceIfNullDetails=If buying/cost price not defined, and this option "ON", margin will be zero on line (buying/cost price = selling price), otherwise ("OFF"), marge will be equal to suggested default. +ForceBuyingPriceIfNullDetails=If buying/cost price not provided when we add a new line, and this option is "ON", the margin will be 0 on the new line (buying/cost price = selling price). If this option is "OFF", margin will be equal to the value suggested by default (and 100% if no default value can be found). MARGIN_METHODE_FOR_DISCOUNT=Margin method for global discounts UseDiscountAsProduct=As a product UseDiscountAsService=As a service diff --git a/htdocs/margin/agentMargins.php b/htdocs/margin/agentMargins.php index e7229abd2d3..d2a19e87149 100644 --- a/htdocs/margin/agentMargins.php +++ b/htdocs/margin/agentMargins.php @@ -170,7 +170,11 @@ if (!empty($startdate)) if (!empty($enddate)) $sql .= " AND f.datef <= '".$db->idate($enddate)."'"; $sql .= " AND d.buy_price_ht IS NOT NULL"; -if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1) $sql .= " AND d.buy_price_ht <> 0"; +// We should not use this here. Option ForceBuyingPriceIfNull should have effect only when inserting data. Once data is recorded, it must be used as it is for report. +// We keep it with value ForceBuyingPriceIfNull = 2 for retroactive effect but results are unpredicable. +if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 2) { + $sql .= " AND d.buy_price_ht <> 0"; +} //if ($agentid > 0) $sql.= " GROUP BY s.rowid, s.nom, s.code_client, s.client, u.rowid, u.login, u.lastname, u.firstname"; //else $sql.= " GROUP BY u.rowid, u.login, u.lastname, u.firstname"; $sql .= " GROUP BY s.rowid, s.nom, s.code_client, s.client, u.rowid, u.login, u.lastname, u.firstname"; diff --git a/htdocs/margin/customerMargins.php b/htdocs/margin/customerMargins.php index 468d633875d..feb5cd34c8e 100644 --- a/htdocs/margin/customerMargins.php +++ b/htdocs/margin/customerMargins.php @@ -234,8 +234,11 @@ $sql .= " AND f.datef >= '".$db->idate($startdate)."'"; if (!empty($enddate)) $sql .= " AND f.datef <= '".$db->idate($enddate)."'"; $sql .= " AND d.buy_price_ht IS NOT NULL"; -if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1) -$sql .= " AND d.buy_price_ht <> 0"; +// We should not use this here. Option ForceBuyingPriceIfNull should have effect only when inserting data. Once data is recorded, it must be used as it is for report. +// We keep it with value ForceBuyingPriceIfNull = 2 for retroactive effect but results are unpredicable. +if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 2) { + $sql .= " AND d.buy_price_ht <> 0"; +} if ($client) $sql .= " GROUP BY s.rowid, s.nom, s.code_client, s.client, f.rowid, f.ref, f.total, f.datef, f.paye, f.fk_statut"; else $sql .= " GROUP BY s.rowid, s.nom, s.code_client, s.client"; $sql .= $db->order($sortfield, $sortorder); diff --git a/htdocs/margin/productMargins.php b/htdocs/margin/productMargins.php index ebe8c9c1cac..b7695c9b2ea 100644 --- a/htdocs/margin/productMargins.php +++ b/htdocs/margin/productMargins.php @@ -197,8 +197,11 @@ if (!empty($startdate)) if (!empty($enddate)) $sql .= " AND f.datef <= '".$db->idate($enddate)."'"; $sql .= " AND d.buy_price_ht IS NOT NULL"; -if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1) +// We should not use this here. Option ForceBuyingPriceIfNull should have effect only when inserting data. Once data is recorded, it must be used as it is for report. +// We keep it with value ForceBuyingPriceIfNull = 2 for retroactive effect but results are unpredicable. +if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 2) { $sql .= " AND d.buy_price_ht <> 0"; +} if ($id > 0) $sql .= " GROUP BY p.label, p.rowid, p.fk_product_type, p.ref, p.entity, d.fk_product, f.rowid, f.ref, f.total, f.datef, f.paye, f.fk_statut"; else $sql .= " GROUP BY p.label, p.rowid, p.fk_product_type, p.ref, p.entity"; $sql .= $db->order($sortfield, $sortorder); diff --git a/htdocs/margin/tabs/productMargins.php b/htdocs/margin/tabs/productMargins.php index 5fcec11c93b..eb82f121295 100644 --- a/htdocs/margin/tabs/productMargins.php +++ b/htdocs/margin/tabs/productMargins.php @@ -150,7 +150,11 @@ if ($id > 0 || !empty($ref)) if (!$user->rights->societe->client->voir && !$socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; if (!empty($socid)) $sql .= " AND f.fk_soc = $socid"; $sql .= " AND d.buy_price_ht IS NOT NULL"; - if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1) $sql .= " AND d.buy_price_ht <> 0"; + // We should not use this here. Option ForceBuyingPriceIfNull should have effect only when inserting data. Once data is recorded, it must be used as it is for report. + // We keep it with value ForceBuyingPriceIfNull = 2 for retroactive effect but results are unpredicable. + if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 2) { + $sql .= " AND d.buy_price_ht <> 0"; + } $sql .= " GROUP BY s.nom, s.rowid, s.code_client, f.rowid, f.ref, f.total, f.datef, f.paye, f.fk_statut, f.type"; if (!$user->rights->societe->client->voir && !$socid) $sql .= ", sc.fk_soc, sc.fk_user"; $sql .= $db->order($sortfield, $sortorder); diff --git a/htdocs/margin/tabs/thirdpartyMargins.php b/htdocs/margin/tabs/thirdpartyMargins.php index bfa5ac15811..0b79ec62b90 100644 --- a/htdocs/margin/tabs/thirdpartyMargins.php +++ b/htdocs/margin/tabs/thirdpartyMargins.php @@ -163,7 +163,11 @@ if ($socid > 0) $sql .= " AND d.fk_facture = f.rowid"; $sql .= " AND f.fk_soc = $socid"; $sql .= " AND d.buy_price_ht IS NOT NULL"; - if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1) $sql .= " AND d.buy_price_ht <> 0"; + // We should not use this here. Option ForceBuyingPriceIfNull should have effect only when inserting data. Once data is recorded, it must be used as it is for report. + // We keep it with value ForceBuyingPriceIfNull = 2 for retroactive effect but results are unpredicable. + if (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 2) { + $sql .= " AND d.buy_price_ht <> 0"; + } $sql .= " GROUP BY s.nom, s.rowid, s.code_client, f.rowid, f.ref, f.total, f.datef, f.paye, f.fk_statut, f.type"; $sql .= $db->order($sortfield, $sortorder); // TODO: calculate total to display then restore pagination