function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Emmanuel B.Emmanuel B. 

Bug on createPortalUser : wrong contact association

Hello,

Here's the scenario : one active community, one account, two contacts. The 2 contacts have the same email address. You want to create a community user for contact One, it associates with contact Two.

Code in CommunitiesSelRegController, called by a commandButton in apex page :

public void test()
    {
        Account a = new Account(Name='Account test', OwnerId='005A0000001fgpe' ); //Owner = me, must have a role
        insert a;
       
        List<Contact> lc = new list<Contact>{
                new Contact(LastName='One', email='same@mail.com', AccountId=a.Id),
                new Contact(LastName='Two', email='same@mail.com', AccountId=a.Id),
                new Contact(LastName='Three', email='different@mail.com', AccountId=a.Id)
                    };
        insert lc;
       
        User u = new User();
        u.userName = lc[1].email;
        u.email = lc[1].email;
        u.FirstName = 'test';   
        u.LastName = lc[1].LastName;
        u.alias = 'watvr';
        u.CommunityNickName=u.alias;
        u.ProfileId = '00eA0000000yex2'; //Customer community user profile
        u.ContactId = lc[1].Id;
         u.CompanyName = a.Name;
        system.debug(u);     // will output User:{ ...ContactId = Two.Id ...}
        String userId = Site.createPortalUser(u, a.Id, null, true);
        system.debug(u);// will output User:{ ...ContactId = One.Id ...}
        }

Don't know where to report this bug...
ShashForceShashForce
Hi,

lc[1] would be contact two, because contact one will be lc[0]. Did I miss anything else?

Thanks,
Shashank
Emmanuel B.Emmanuel B.
Yes lc[1] is contact two, there's no problem with it.

The problem is that when you call createPortalUser with, as 1st argument, a User whose property ContactId is set to ContactTwo.Id, it creates a user with ContactId = ContactOne.Id.

I wrote a trigger on User Before Create to check it, the trigger only executes a System.debug(trigger.new[0].ContactId);
It shows that the ContactId is changed for ContactOne.Id even before it's inserted in the database. So it's somewhere in the implementation of createPortalUser that there definitely is a bug.
Emmanuel B.Emmanuel B.
Another strange behavior :
On a user page, I click on the associate contact
=> I load the contact page, I click on "Log in to community as user"'
=> I get a message like "user must have a community account"

That happens when you have 2 contacts on the same account with the same name (duplicates).
But since I followed the link from the user page, I should land on the right contact page, shouldn't I ?
Or would salesforce associate contacts to users by name or email instead of by Id ?
MFrederickMFrederick
I am actually seeing an error in create Portal user when there are 2 contacts with the same email address. Even though 1 contact info is sent it is not creating the user.
Emmanuel B.Emmanuel B.
Hi MFrederik,

CreatePortalUser actually creates the user AND the contact and should not be used in the context of an existing contact to be associated with a new user. This is not documented and triggers weird behaviors if you do so. It's a bug (it should either be forbidden, or have the expected behavior) but it looks that it won't be fixed.

Instead, you should use DML statements on User object :
User u = new User(AccountId=yourAccId, ContactId=yourContactId...);
insert u;
Of course the welcome mail optionnaly sent by createPortalUser won't be sent but you still can make a workflow for this.

Hope this helps.
MFrederickMFrederick
But it does work for 90% of the time. When user self registers, code finds the contact and creates the user. It is only when there are duplicate contacts it does not work. And some cases where there is only 1 contact it does not work.  It is very strange and do not know how to debug.
Emmanuel B.Emmanuel B.
Yes it does work 90% of the time.
That means it doesn't 10% of the time and that's what you shouldn't use it. As I said, use insert DML statements instead.
You can't debug it because the bug is not in your code but in the createPortalUser method implementation.
If you want to be sure of this, do the following.

-> Create two contacts on an account with the same email address : contact1 and contact2
-> Write a short trigger UserBeforeInsert with a simple
System.debug(trigger.new);
instruction

-> Make a call two createPortalUser with the contact1 Id associated to the user
-> you'll see that even before the user is inserted, it is associated with the contact2 Id (it is always the last created).

So just replace your
String userId = Site.createPortalUser(u, a.Id, null, true);

call by
u.accountId = a.Id;
insert u;
and that will work.
Emmanuel B.Emmanuel B.
or do what we did, delete email fields on the dups, but it's an ugly solution :(
Ben Burbridge 7Ben Burbridge 7
I had the same concerns (about creating a Community user and having it hook up to the wrong Contact when more than one Contact has the same email). As Emmanuel described, I created a User and inserted it, and it works.

However, I then set their password with Site.setPassword, and about 10% of the time (random, intermittent), the password is created with an expiration date that is 24 hours -before- the creation of the User record. This forces the user to immediately change the password they just entered, leading to no end of confusion for them. And the Password Expiration Date is only available in reports, not on the User page layout (go figure), so was quite difficult to figure out what was really going on.

I've had a Case open for about 6 weeks and have demonstrated the ability to reproduce the problem. It went all the way to R&D, and their recommendation (so far), is to use Site.createExternalUser(), which, while hardly documented, likely does the same thing as createPortalUser, taking me back to the original concern of this post.