Calculated extrafield using other extrafields values

Hello, I’m sharing the following in hopes that it will be useful to other “Dolibarr users” :slight_smile:

I needed to create an invoice extra field that uses the value of another extra field:

  • First extra field: custom due date (key: customdue_date), date type, to be filled out by Dolibarr users on all invoices.
  • Second extra field: text type field, calculating the difference in days from today to that custom due date.

It took me almost two hours to get it working, even though I’ve been using “calculated fields” for years. However, until now, I hadn’t tried basing them on the values of other additional fields on the same object… and honestly, it wasn’t easy.

The biggest challenge in getting these formulas to work is that Dolibarr uses a security validation function that heavily restricts certain things—certain functions, certain syntax, etc. Let’s get into the details.

The formula is as follows, and I’ll explain it below:

($object->paye == 1 ? '' : ( ($reloadedobj = new Facture($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0) && !empty($reloadedobj->array_options['options_customdue_date']) ? round( (intval($reloadedobj->array_options['options_customdue_date']) - dol_now('auto')) / 86400) : ''))

Explanation:

  • If the invoice has already been paid, I don’t want to show anything in that column of the invoice list.
  • If it hasn’t been paid, I instantiate an object of type Facture(), then retrieve the record of that invoice WITHOUT COMPUTING (using $objectoffield->id). Only this way can I access the values of the EXTRAFIELDS!!
  • In other words, this doesn’t happen with native invoice fields, but it does with extra fields (that discovery alone took me almost an hour…).
  • Finally, I compare that date value (which is actually retrieved as a UNIX timestamp integer) and subtract the current timestamp—which can’t be done with time() but with dol_now('auto').
  • Oh, and finally, I divide it by the number of seconds in a day (86400) and round it.

Very important:

  • Some validation errors in this formula were resolved simply by ADDING A BLANK SPACE before certain elements. For example, instead of “round((intval(”, you need to insert a blank space after “round(” like this: “round( (intval(”.
  • Debugging these errors took me almost another hour, through trial and error, by debugging directly from the PHP code evaluating these expressions. :sweat_smile:

Anyway… if you manage to get another complex expression like this to work, I encourage you to share it on the forum.

Greetings!
Sergi

1 Like

Can we see some example pictures?

Yes… of course.

This is the final result of another field i created today… more complicated :slight_smile:

Briefly:

  • “Importe total” is the native field llx_facture.multicurrency_total_ttc
  • My customer has some invoices in MXN and some other in USD, set at llx_facture.multicurrency_code field
  • My customer has an extrafield for factures called tipodecambiocfdi , because they began to use this “custom multicurrency system” before Dolibarr had more finished this multicurrency matter :wink: and they save manually the currency exchange MANUALLY. And, by demands of the Mexican government, the currency exchanges are always expressed respect the MXN, so in inverse order than the multicurrency_rate used by Dolibarr (it’s complicated to explain this part, but it’s not relevant for this post)

I created this field “Total en MXN”:

If you need to copy my formula:

($object->multicurrency_code == 'MXN' ? price( round($object->multicurrency_total_ttc,2)) : ( ($reloadedobj = new Facture($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0) && !empty($reloadedobj->array_options['options_tipodecambiocfdi']) ? price( round($object->multicurrency_total_ttc * floatval($reloadedobj->array_options['options_tipodecambiocfdi']),2) ) : '?') )

Briefly:

  • if the currency is MXN then returns the stored multicurrency_amount (rounded and formatted)
  • if the currency is USD then load the llx_facture_extrafields when doing fetchNoCompute()
  • then if is NOT EMPTY the field options_tipodecambiocfdi (currency rate) then proceed with a product of the amount x rate and apply a round(2) and a price() formatting

Certainly, is not simple. But it runs :slight_smile:

1 Like