Dolibarr / dolibarr

Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.
https://www.dolibarr.org
GNU General Public License v3.0
5.37k stars 2.77k forks source link

ERROR : selectForForms: Error bad setup of field objectdescorig=User, objectfield=webpassword_webpassword:fk_element #29369

Open john-botella opened 6 months ago

john-botella commented 6 months ago

@eldy I have this error message on V19 of Dolibarr : selectForForms: Error bad setup of field objectdescorig=User, objectfield=webpassword_webpassword:fk_element This error appear on a lot of our Modules and also on fresh module created with ModuleBuilder

https://github.com/Dolibarr/dolibarr/blob/5278cb07a834a1cc628b8fe184ecd37a0f4d26fa/htdocs/core/class/commonobject.class.php#L7726-L7727

Backward to like V17 resolve my problème.

    $objectfield = null;
    $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, (empty($val['disabled']) ? 0 : 1), '', $objectfield);

But why $objectfield was added ? Before I create a fix I need to understand why $objectfield was populated.

eldy commented 6 months ago

When we link to a field of an object, we must know a lot of information about the fied we link to. The class and path TARGET was provided into objectdesc.

But sometimes we need more. it was not enough. We have all information, already defined into the SOURCE object into the table $fields OR into $extrafields definition. So with objectfields, we can just provide the name of the field in source object or extrafield of source object, and system will retreive the information of the target with it.

This second method is used only if param objectfield is provided. When provided, we can retreive the $objectdesc. If not, we backfall on old code for compatibility. If objectfield is provided, objectdesc is not used. First method is deprecated because less complete (was using a hardcoded solution when we can retreived info dynamically). It was also not compatible with extrafields.

If you have objectfield=webpassword_webpassword:fk_element then you must have into the Webpassword->$fields an entry 'fk_element' with 'type'='integer:User...'

PS: i do not experience troubles with new generated object with modulebuilder.

john-botella commented 6 months ago

Ok thanks, I'll look into it.

soehlrich commented 6 months ago

After upgrading to V19.01 a lot of the complementary fields that use links to objects have stopped working. I have a Delivery Address field in Purchase orders that is a link to a warehouse (entrepot) object.

I have tried to see what the issue is, but am not familiar enough with the system. I did manually put your (Eldy ) correction into the functions.lib.php code _} elseif ($element_type == 'stock' || $elementtype == 'entrepot') { $module='stock'; $classpath = 'product/stock/class'; $classfile = 'entrepot'; $classname = 'Entrepot';

but this issue seems to affect all other objects links as well.

I have attempted to put some debug code , hopefully this may help. I noticed that the field 'options_deladdr' is being found , but then it is using the table element of 'societe'.

Anyway here is my debug out put along with snippets of code where I have put the error_log() statements. Any suggestion or help would be greatly appreciated as this has stopped us in our tracks.

Debug output In selectForForms Function ObjectDesc:entrepot HTML Name:options_deladdr PreSelected Value: Object Field:commande_fournisseur:options_deladdr tmparray:array (\n 0 => 'commande_fournisseur',\n 1 => 'options_deladdr',\n) Reg1:array (\n 0 => 'options_deladdr',\n 1 => 'deladdr',\n) objector table element:societe

SQL Query:SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'societe' ORDER BY pos Object Tmp:NULL,

SQL Query:SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'commande_fournisseurdet' ORDER BY pos

SQL Query:SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'facture_fourn' ORDER BY pos

SQL Query:SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'facture_fourn_det' ORDER BY pos

SQL Query:SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'actioncomm' ORDER BY pos

Error_log code -

in html.form.class.php public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '') { global $conf, $extrafields, $user;

    $objectdescorig = $objectdesc;
    $objecttmp = null;
    $InfoFieldList = array();

        //PSL
        error_log("In selectForForms Function");
        error_log("ObjectDesc:$objectdesc");
        error_log("HTML Name:$htmlname");
        error_log("PreSelected Value:$preSelectedValue");
        error_log("Object Field:$objectfield");
        //PSL

    if ($objectfield) { // We must retreive the objectdesc from the field or extrafield

        // Example: $objectfield = 'product:options_package'
        $tmparray = explode(':', $objectfield);
        $objectdesc = '';

        error_log("tmparray:".var_export($tmparray,true));  //PSL

        // Load object according to $id and $element
        $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
        $reg = array();
        //error_log("Objforfieldstmp:".var_export($objectforfieldstmp,true));  //PSL
        error_log("Reg0:".var_export($reg,true));  //PSL
        if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
            // For a property in extrafields

            error_log("Reg1:".var_export($reg,true)); //PSL

            $key = $reg[1];
            // fetch optionals attributes and labels

            error_log("objector table element:".$objectforfieldstmp->table_element); //PSL

            $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element); 

            //error_log("Extra Fields:".var_export($extrafields,true));        //PSL

and in extrafields.class.php public function fetch_name_optionals_label($elementtype, $forceload = false) { // phpcs:enable global $conf;

    if (empty($elementtype)) {
        return array();
    }

    if ($elementtype == 'thirdparty') {
        $elementtype = 'societe';
    }
    if ($elementtype == 'contact') {
        $elementtype = 'socpeople';
    }
    if ($elementtype == 'order_supplier') {
        $elementtype = 'commande_fournisseur';
    }

    // Test cache $this->attributes[$elementtype]['loaded'] to see if we must do something
    // TODO

    $array_name_label = array();

    // We should not have several time this request. If we have, there is some optimization to do by calling a simple $extrafields->fetch_optionals() in top of code and not into subcode
    $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help,";
    $sql .= " css, cssview, csslist";
    $sql .= " FROM ".$this->db->prefix()."extrafields";
    //$sql.= " WHERE entity IN (0,".$conf->entity.")";    // Filter is done later
    if ($elementtype && $elementtype != 'all') {
        $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; // Filed with object->table_element
    }
    $sql .= " ORDER BY pos";

    **error_log("SQL Query:".$sql);  //PSL**
john-botella commented 6 months ago

Ok I found the origin, but can't change the core, we need to talk before at devcamp to find a good way to patch.

PS : I found a way by updating my module (I don't like my patch, but do the job)

after that I found another problem with extrafiedls because table name isn't the same as element....

rycks commented 4 months ago

Hello all, that bug seems to be linked to function fetchObjectByElement : that function return -1 in some case ... and there is A LOT of dolibarr code where there is no test of that race condition and we use result as an object !

please have a loot at #29996 ... and maybe a more bigger PR will come for 19.0 and then develop ...

john-botella commented 4 months ago

linked to https://github.com/Dolibarr/dolibarr/pull/30036

john-botella commented 4 months ago

I created a way for external integrator to fix module compatibility whith V19 by backporting a V20 hook in V19 see #30086

finalbeta commented 2 months ago

I come across this error after upgrading to V19 from V18. On the vendor module I have a "Complementary attribute".

image

Before this allowed me to link a purchase order to a customer order. Now I get the selectForForms error: image

(Might be relevant to this ticket)