Module CustomFields Cases: Difference between revisions

Jump to navigation Jump to search
Added case "Modify the total global price with a coefficient (without tampering the discount)"
(Added case "Modify the total global price with a coefficient (without tampering the discount)")
Line 345: Line 345:
Thank's to netassopro for the tip.
Thank's to netassopro for the tip.


= Modify the total price of every product/service line with a coefficient (without tampering the discount) =
= Modify the total global price with a coefficient (without tampering the discount) =
 
This is more troublesome than modifying the total price per product/service line, because the total global price of an object (let's say an invoice, but this also works for any other object) is always recomputed by summing the prices and quantity of each product/service line. This means that although there's an entry "total_ttc" in the database to store the invoice's total price, this price is in fact always recomputed, it's never used as-is. Thus, it's useless to change only the database record: we need to inject some code to change how the total price is computed.
 
This could be done using an overloading function or a trigger, but unluckily, Dolibarr doesn't call a trigger nor a hook when recomputing the price. We thus need to edit core files to do what we want.
 
However, the bright side is that we can cleverly edit just two functions from one core file: update_price() and getMarginInfos() from /htdocs/core/class/commonobject.class.php , and everything should run smoothly. Beware that if you update Dolibarr, you will need to redo these two modifications in the code.
 
First, you need to create a new custom field called "global_coefficient" in Invoices (not Invoices Lines!). Then you can continue to the subchapters below.
 
Also note that this global coefficient is also compatible with per line coefficients (as described in the next chapter), thus you can use a global coefficient and per line coefficients at the same time. You can also use multiple global coefficient if you wish.
 
Another note: if you have a grid of discounts depending on quantity or price or whatever parameter, you can program a precomputation code using a Custom Ajax function (this way, your discounts will be automatically computed, but then you can still manually enter them for particular cases since the custom field is editable).
 
== Implement the change of global price in most of Dolibarr (including remaining debt to pay and PDF and ODT) ==
 
The change we will implement here will reflect the new total price with the global coefficient in most of Dolibarr's code, since we will here change the main function that is usually called to update and get the total price.
 
Open /htdocs/core/class/commonobject.class.php and look for the function update_price().
 
You should see the following:
 
<source lang="php">
function update_price($exclspec=0,$roundingadjust='none',$nodatabaseupdate=0,$seller='')
{
    global $conf;
 
    include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
</source>
 
Just below the include_once line, add the following:
 
<source lang="php">
// Global coefficient (CustomFields)
include_once DOL_DOCUMENT_ROOT.'/customfields/class/customfields.class.php';
include_once DOL_DOCUMENT_ROOT.'/customfields/conf/conf_customfields_func.lib.php';
$customfields = new CustomFields($this->db, $this->table_element);
// Get object's id (either stored in property "id" or "rowid")
$this_id = (!empty($this->id)) ? $this->id : $this->rowid;
// Load custom fields records
$cf_parent_record = $customfields->fetch($this_id);
</source>
 
This will load the global_coefficient custom field (and also any other custom field you have defined for invoices).
 
Now scroll below, and you should see this:
 
<source lang="php">
while ($i < $num)
{
    $obj = $this->db->fetch_object($resql);
 
    ... (lots of code)
 
    i++;
}
 
// Add revenue stamp to total
$this->total_ttc      += isset($this->revenuestamp)?$this->revenuestamp:0;
 
$this->db->free($resql);
</source>
 
This is the end of the loop that is summing each product/service line price to compute the total price. Just after this loop, you should see this:
 
<source lang="php">
// Now update global field total_ht, total_ttc and tva
$fieldht='total_ht';
$fieldtva='tva';
$fieldlocaltax1='localtax1';
$fieldlocaltax2='localtax2';
$fieldttc='total_ttc';
// Specific code for backward compatibility with old field names
if ($this->element == 'facture' || $this->element == 'facturerec')            $fieldht='total';
if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva';
if ($this->element == 'propal')                                                $fieldttc='total';
</source>
 
Between those two blocks of code (so just above // Now update global field total_ht, total_ttc and tva), you can place the following:
 
<source lang="php">
// Global coefficient (CustomFields)
if (!empty($cf_parent_record->global_coefficient)) { // avoid applying the coefficient if empty (this will return a 0 price)
    $this->total_ht = $this->total_ht * $cf_parent_record->global_coefficient;
    $this->total_tva = $this->total_tva * $cf_parent_record->global_coefficient;
    $this->total_ttc = $this->total_ttc * $cf_parent_record->global_coefficient;
}
</source>
 
Done, now try to add/edit a product/service line, and the total price should be affected by the global coefficient.
 
== Implementing the change of price in margin module ==
 
If you enabled the margin module, you should see that the coefficient is not applied there, but it's easy to fix that.
 
Open the file /htdocs/core/class/commonobject.class.php and find the function getMarginInfos(), then inside find the following lines:
 
<source lang="php">
foreach($this->lines as $line) {
    if (empty($line->pa_ht) && isset($line->fk_fournprice) && !$force_price) {
        $product = new ProductFournisseur($this->db);
        if ($product->fetch_product_fournisseur_price($line->fk_fournprice))
            $line->pa_ht = $product->fourn_unitprice * (1 - $product->fourn_remise_percent / 100);
        if (isset($conf->global->MARGIN_TYPE) && $conf->global->MARGIN_TYPE == "2" && $product->fourn_unitcharges > 0)
            $line->pa_ht += $product->fourn_unitcharges;
    }
    // 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)) {
        $line->pa_ht = $line->subprice * (1 - ($line->remise_percent / 100));
    }
</source>
 
This is where the lines are filled with margin infos. The price has just been fetched here, and we will now modify it with the coefficient before the price gets used for margin computation.
 
Just below the code we found, paste the following:
 
<source lang="php">
// Global coefficient (CustomFields)
dol_include_once('/customfields/lib/customfields_aux.lib.php');
// Get object's id (either stored in property "id" or "rowid")
$this_id = (!empty($this->id)) ? $this->id : $this->rowid;
// Load custom fields records
$customfields = customfields_fill_object($this);
// Apply the coefficient
if (!empty($this->customfields->cf_global_coefficient)) {
    $line->pa_ht = $line->pa_ht * $this->customfields->cf_global_coefficient;
    $line->subprice = $line->subprice * $this->customfields->cf_global_coefficient;
}
</source>
 
Note that here we cheated a bit: we do not compute the coefficient on the global total price, but rather per product/service line price. This is done on purpose, because mathematically this should produce no difference, and it also allows Dolibarr to continue peacefully with its margin calculations (else we would have to adapt all those computations, which would imply a lot more of code changes!).
 
That's all, the price should be reflected in the margin. Just refresh the page to reflect the change.
 
= Modify the total price PER product/service line with a coefficient (without tampering the discount) =


Here we will go through the creation and management of a custom field called '''coefficient''' that will change the total price of each product by modifying it by the coefficient.
Here we will go through the creation and management of a custom field called '''coefficient''' that will change the total price of each product by modifying it by the coefficient.
439

edits

Navigation menu