How to add email in new record with hook after or before save?

@Dharmik

I am using this version too.
There is small video for you. I think that there is mistake somewhere in your code. I can not see your code fully. I very sorry but I don’t know where.

I think there is some other problem. Not code. I am also unable to update email Field from SuiteCRM workflow.

@Dharmik

  1. The $bean->email1 = $personal_email; action doesn’t make sense;
  2. Change logichook from before_save to after_save as in my video. Maybe you SuiteCRM has another code which preventing to do it.

Sorry for describing issue with less info. I have just checked suitecrm.error.log file in nginx server.
It gives me following error.
2021/04/20 09:18:43 [error] 12282#12282: *11479 FastCGI sent in stderr: "PHP message: PHP Notice: Undefined index: SweeterCalc in /var/www/html/suitecrm/modules/AOW_Actions/FormulaCalculator.php on line 108" while reading response header from upstream, client: 123.201.70.169, server: suitecrm.server.org, request: "POST /index.php HTTP/2.0", upstream: "fastcgi://unix:/var/run/php/php7.2-fpm.sock:", host: "suitecrm.server.org", referrer: "https://suitecrm.server.org/"

It says SweeterCalc is undefined. I think I need to update FormulaCalculator.php file. :confused:

I have following line on 108th line.
$this->debugEnabled = $this->configurator->config[FormulaCalculator::CONFIGURATOR_NAME]['DebugEnabled'] == 1;

@Dharmik

I don’t have any comments for it. I never saw this error. I don’t know “nginx” well. I am using “apache” usually.

Can you share FormulaCalculator.php file?
I think both apache and nginx gives same error

@Dharmik

You can find full version of SuiteCRM on GitHub always. This is the file:

after seeing github files, both files are same no change.
I found similar issue in following link
https://community.suitecrm.com/t/error-500-after-add-a-calculated-field-in-workflow/55341/5

But I didn’t find solution there also.
I found SweeterCalc pdf that explains all about SweeterCalc.


just for reference.

I searched for FastCGI sent in stderr and some answers tell that it is related to nginx and its configuration. Or may be wrongly installed some scripts. I don’t know what to describe to server administrator about this.

@p.konetskiy I have checked SugarEmailAddress.php file, saveEmail() function executes 2 time when I code run

$bean->emailAddress->addresses[0]=array(
        'email_address' => $personal_email,
        'primary_address' => 1,
        'reply_to_address' => 0,
        'invalid_email' => 0,
        'opt_out' => 0,
        'confirm_opt_in_flag' => 0
    );
    $bean->emailAddress->saveEmail($bean->id,$bean->module_name); 

:confused:

I setup SuiteCRM in my local machine. It is working fine in localhost. If it fires two times, it gives exact same value. Like I have placed logging/debugging code in SugarEmailAddress.php file like incrementally 1, 2, 3 and so on. So when I save once. It fires two times and both have different output. Like 2 3 4 5 and second 2 3 4 5 7 8 9 like this. But in localhost both have same output. Don’t know why different on server??

@Dharmik

You can add the code to SugarEmailAddress.php for testing. The function debug_backtrace write in log who called saveEmail (the first array). I looked at my log and saw that the first call from include/SugarObjects/templates/person/Person.php with old data of email and the second call from custom/modules/Contacts/<my_logichook_file>.php with new data of email.

        $GLOBALS['log']->fatal(get_class()." ". __FUNCTION__." id:\n ".print_r($id,true));
        $GLOBALS['log']->fatal(get_class()." ". __FUNCTION__." module:\n ".print_r($module,true));
        $GLOBALS['log']->fatal(get_class()." ". __FUNCTION__." this->addresses:\n ".print_r($this->addresses,true));
        $GLOBALS['log']->fatal(get_class()." ". __FUNCTION__." debug_backtrace:\n ".print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,0),true));

Ok. I did this. But with little customisations.(Please check attachment)
and Output of that log file is as bellow
2
3
4
5
2
4
5
6
8
9
10
FIRING ONCE
2
3
4
5

code in EnableDisableHandler.php (Hook file)

$bean->emailAddress->addresses[0]=array(
        'email_address' => $personal_email,
        'primary_address' => 1,
        'reply_to_address' => 0,
        'invalid_email' => 0,
        'opt_out' => 0,
        'confirm_opt_in_flag' => 0
    );
    $bean->emailAddress->saveEmail($bean->id,$bean->module_name);

@Dharmik

Sorry I don’t understand what are you doing.
I wrote about changing method saveEmail in file SugarEmailAddress.php

Yes, I changed that function/method. I added file_put_contents in saveEmail function at some places, after that when I run It gives me above output.
When function executes, it will store 1 2 3 incrementally after some line of code executions. So It should go to 10 to successfully insert email address. So when my logic hook fire, It calls saveEmail function 3 times. first 2 to 5 than 2 to 10 and then 2 to 5.
So, it saves email ID and remove it.

I have observed database. When I save contact form, it saves 2 times normally, after save. Means I press save button and it executes two times. So according to above code, when I call saveEmail Function (THAT MEANS CALLING THIRD TIME - this save function calls at second place - between two save) it saves email address set relationship and all that and then it call again save function ad set email address that was last saved to deleted=1. When I go to email_addr_bean_rel this table and set deleted to 1 it shows email address in contact detail of that record.

@Dharmik

I don’t see any problems if some method called several times if it’s written correctly. If you use my recommendations you can see which method and with which data called saveEmail.

@Dharmik

You have several records in database with mark as primary. When you set deleted for one record you see other record.

Thanks a lot for this.

Used this code to roll back the email address in a contact before save hook.

The before save hook don’t work with email, the email is saved anyway, even if you exit() in a function in before_save. (all other field work).

So I used this code to roll back email if my verification fail.

		    $bean->emailAddress->addresses[0]=array(
	        'email_address' => $bean->fetched_row['email1'],
	        'primary_address' => 1,
	        'reply_to_address' => 0,
	        'invalid_email' => 0,
	        'opt_out' => 0,
	        'confirm_opt_in_flag' => 0
		    );
		    $bean->emailAddress->saveEmail($bean->id,$bean->module_name);
		    unset($bean->emailAddress->addresses[0]);

@p.konetskiy

Thank you for this post; it helped me do something I needed for my new installation.

Question: When you tested your code, did you try it with Importing and did you look in the List View? If so, did the new email appear in the List View and subpanels?

I have your code half working.

I used your code as shown above to add a fake email address when the record creation did not include an email address and then set the fake email address to an invalid email address. I did this with an after_save logic hook (the before_save did not work since there was no $bean->id for a new record).

The code called by the after_save logic hook is

<?php

if (!defined('sugarEntry') || !sugarEntry) {
    die('Not A Valid Entry Point');
}

class fakeEmailCreate {

    public function setEmailToInvalid( $bean , $event , $arguments ) {

        if( empty($bean->emailAddress->addresses[0]['email_address']) ) {
            $tempEmailAddress = $bean->first_name . "." . $bean->last_name ."@rcfakeemail.duh";
            $bean->emailAddress->addresses[0]=array(
                'email_address' => $tempEmailAddress,
                'primary_address' => 1,
                'reply_to_address' => 0,
                'invalid_email' => 1,
                'opt_out' => 0,
                'confirm_opt_in_flag' => 0
            );
            $bean->emailAddress->saveEmail($bean->id,$bean->module_name);
            unset($bean->emailAddress->addresses[0]);
        }
    }
}

So far so good. The record is saved with the email and the Invalid checkbox is Checked. When I open the Contact record with the Detail View (or Edit View) all is as it should be.

Howerver …

I am Importing new Contacts, sometimes a hundreds at a time. Many do not have any email address and these are still useful to us since we both email and post mail to our Contacts.

When I Import a Contact with no email address, the record is properly created with the fake email address set to invlaid but …

For Imported Contacts, in the Contacts List View, the email address does not show, nor does the email show in the Accounts subpanel for Contacts.

If I manually open the new Contact and manually save it via the Edit View, the email address now shows in the List View and subpanels.

But I cannot do this after importing hundreds of new Contacts.

I have tried numerous work-arounds but anything I do to get the email address to show in List View or subpanels ends up generating an error message about trying to create a duplicate “Primary” key.

So, 2 Questions:

  1. When you tested your code, did you try it with Importing and did you look in the List View? If so, did the new email appear in the List View and subpanels?
  2. What is the purpose of the line
unset($bean->emailAddress->addresses[0]);

and why is it done AFTER the line creating the new email address setup ?
(OK, 3 questions …)

@Ramblin
1.

You can use the code for logic hook “before_save” if need to get “id”:

$bean->id = create_guid();
$bean->new_with_id=true;

For import you can write method “afterImportSave” for object “Contact”. The method can create in custom code. How do it you can know if look at the documentation:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_12.2/Data_Framework/Models/SugarBean/Customizing_Core_SugarBeans/

I didn’t test the code, but the logic hooks work for import.

@p.konetskiy

I think the issue may have something to do with the customizations I have for the Import function.

And because of these customizations, I cannot pre-assign an ID to a new record. The Import function treats any records with an ID as a new record (as it should) and does NOT use the custom code and I cannot use that.

The customization enables me to import a Contact with an Account Name and if the Account Name matches one and only one Account in the system, it will save the Contact with the relationship to the Account set. It will do this without requiring the Account ID to be included in the Import file.

So when I pre-assign the Contact ID and Import with the Account Name (without an Account ID), it ignores the Account Name and does not create the Contact relationship with the Account.

I can get the email to show in the Detail/Edit Views but not in the List View or subpanels. I get the “Duplicate Primary key” error message when i try.

Since this is my issue with my custom code, I will work on it here, but I wanted to thank you for responding quickly and for posting the original work.

You are a great help on these forums and I appreciate it.