Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX #32791 Lost user and THM when updating task time #32822

Draft
wants to merge 1 commit into
base: 20.0
Choose a base branch
from

Conversation

mdeweerd
Copy link
Contributor

FIX #32791 Lost user and THM when updating task time

The task time was assigned the user '0' when updating, which resulted in an error where a NULL object was used.
This resulted in a partially replaced record with no user and empty THM.

The correction adds the use of a DB transaction to avoid inconsistency in case of an error.
The correction uses the fields from the original record if no new fields are provided in the POST arguments

# FIX Dolibarr#32791 Lost user and THM when updating task time

The task time was assigned the user '0' when updating, which resulted in an
error where a NULL object was used.
This resulted in a partially replaced record with no user and empty THM.

The correction adds the use of a DB transaction to avoid inconsistency in case
of an error.
The correction uses the fields from the original record if no new fields
are provided in the POST arguments
@mdeweerd mdeweerd marked this pull request as ready for review January 28, 2025 00:49
@hregis
Copy link
Contributor

hregis commented Jan 28, 2025

@mdeweerd GETPOSTINT return 0 if the value is null, you can use GETPOST(xxxx, 'int') instead

@mdeweerd
Copy link
Contributor Author

@mdeweerd GETPOSTINT return 0 if the value is null, you can use GETPOST(xxxx, 'int') instead

The code first validates that the value is provided and not '' before using the int value.
I normally would use intermediate variables to get the POST value and then reuse that, but that's not the method used in dolibarr. In that case, $val = GETPOST(xxx, 'int'); if($val!=='') {$otherval=(int)$val;}

Anyway, this code works for me: I can update a line. I also tested on a line that I fixed in the DB without updating the cost value (which was 0) and the cost was updated to the correct value when I saved the line (without any modifications made).

@mdeweerd mdeweerd marked this pull request as draft January 28, 2025 17:54
@mdeweerd
Copy link
Contributor Author

Draft again, some cases are not ok.

@vsatmydynipnet
Copy link

I fixed the one affecting me. Commented the patch, but I am sure there is a better solution :-)

--- project.class.php.ORIG      2025-02-12 12:33:32.468000000 +0100
+++ project.class.php.01.VS    2025-02-12 13:44:31.652000000 +0100
@@ -1620,9 +1620,22 @@
                $sql .= " WHERE p.entity IN (".getEntity('project').")";
                // Internal users must see project he is contact to even if project linked to a third party he can't see.
                //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
-               if ($socid > 0) {
+                // -----------------------------------------------------------------------------------
+                // VS There must be a bug:
+                // socid is the socid of the contact, probably only if the dolibarr user is linked to a business partner contact?
+                // then the query would want to select p_fk_soc based on the fk_soc of the partner linked to the user
+                // and it fails with 0 returns. For whatever reason this does not happen in 19.0.2, but started with 20.0.3
+                // our user, linked to a business partner, is named as external contact, maybe because of the link. So he has permissions,
+                // but there are no records selected because p-fk_soc is set based on the customer the project is opened and not
+                // on the fk_soc of the user (and his linked to partner)
+                // NOTE: socid is set also if user is linked to a business partner and therefor he is external. then socid is set with the one of the user
+               // Buggy if ($socid > 0) {
+                // I am sure there is a better solution....
+               if ( ($socid > 0) AND ($user->socid != $socid) ) {
                        $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
                }
+                // end of fix
+                // -----------------------------------------------------------------------------------

                // Get id of types of contacts for projects (This list never contains a lot of elements)
                $listofprojectcontacttype = array();
@@ -1665,7 +1678,7 @@
                        $sql .= $filter;
                }

-               //print $sql;
+               //print "FUNCTION SQL:" . $sql."<br>";

                $resql = $this->db->query($sql);
                if ($resql) {

For me this fix works for my problem.

@mdeweerd
Copy link
Contributor Author

Did you check if the task in the table still has the user after the change?

The patch changes the documented functionnality of the method - it doe nos longer filter on a specific third party if the third party that is examined is the same as the one of the user.
This indicates that getProjectsAuthorizedForUser influences your issue, so one needs to check how.

@vsatmydynipnet
Copy link

As I wrote I commented the patch and I am sure there are better solutions.

My problem was:

  • As user which is linked to some business partner and shown as external, has rights to the project/task
  • The project is linked to another business partner
  • Based on the above the user was able to enter time into a project, but the line was not shown anymore after they added the line. So my users made massive troubles because they entered time in a "blind way" unable to correct typos

Currently some users added times and it looks good. The function by itself, as I understood, only return projects the user has rights too as string or array?

@mdeweerd
Copy link
Contributor Author

In the latest code this was added versus 19.0.2, so maybe that is your reason or your fix:

htdocs/projet/tasks/time.php

        if (!$user->hasRight('projet', 'all', 'lire')) {
            // Get list of project id allowed to user (in a string list separated by comma)
            // TODO This may generate performance trouble when list of project is very large. Solution can be 
o complete $filterproj with filters on project.
            $filterproj = '';
            $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, $user->socid > 0 ? $user->socid : , $filterproj);
            $sql .= " AND p.rowid IN (".$db->sanitize($projectsListId).")"; // public and assigned to, or restricted to company for external users
        }

@vsatmydynipnet
Copy link

That code was my start investigating.

$projectsListId = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, $user->socid > 0 ? $user->socid : , $filterproj);

returns an empty value in my case, because sql2 query from the getProjectsAuthorizedForUser in my case is an empty result.

at least since 20.0.3 socid in the function is the socid of the business partner socid of the business partner the user is linked too and not the socid of the project/task itself.

@vsatmydynipnet
Copy link

I assume the solution would be to address the "socid named here:

  •           if ( ($socid > 0) AND ($user->socid != $socid) ) {
                      $sql .= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".((int) $socid).")";
              }
    

as PROJECT->socid here. I assume $socid is filled wrong in 20.x.x.

@mdeweerd
Copy link
Contributor Author

My interpretation of the code in time.php is that this restriction is added only if the user does not have the right to see all projets and so the projects are restricted to his socid.
The modification of getProjectsAuthorizedForUser undoes this restriction.

So in this case the question is what rule allows the user access to the project + what the reason is to show the project on this page.
Mode 0 restricts access to public and assigned projects.
So the $socid argument should be use to restrict to the company viewed on the page, or the $filter argument should be used for that.

Apparently this restristion was introduced in #30362 .

@vsatmydynipnet
Copy link

I think this code does make the entry/ies available to internal users if the project is linked to a 3rd party business partner:

// Internal users must see project he is contact to even if project linked to a third party he can't see.

But I think since 20.x somewhere else $socid if filled with the id of the businesspartner the logged in user is linked too and not with the socid where the project is linked too. But I have not found where $socid without any $something->socid is set.

@hregis
Copy link
Contributor

hregis commented Feb 14, 2025

@vsatmydynipnet You should never say that your solution is the best solution or the only solution because you don't have a global vision of all the interactions! You see what you see because that's what you want to see...

@vsatmydynipnet
Copy link

@hregis where I said my code is the best solution?

I wrote:
"As I wrote I commented the patch =>and I am sure there are better solutions<=."

I was happy to fix my problem, but I am sure, somebody with deeper knowledge shoulld look into this one and fix the $socid change finally.

@hregis
Copy link
Contributor

hregis commented Feb 14, 2025

@vsatmydynipnet ah ? sorry i don't understand your words !

"I fixed the one affecting me. Commented the patch, but I am sure there is a better solution :-)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants