Modify return data from related field

Hi,

I'm working on Sugar 7.5 Enterprise, i have a relation between accounts and oportunitties and i need to copy a content field from the accounts module and paste into a field in the opportunitties module, but keeping this field editable.

In SugarCE 6.5, i can modify the open_popup function in the related field from the opportunities module and add the required field:

open_popup(
  "Accounts", 
  600, 
  400, 
  "", 
  true, 
  false, 
  {"call_back_function":"set_return","form_name":"EditView","field_to_name_array":{"id":"account_id","name":"account_name", "my_account_field":"my_opportunity_field" }}, 
  "single", 
  true
);

But in Sugar 7.5 this process it's very different, i extends a record.js in the opportunities module, but i don't know how to modify the related field functionality.

Thanks for the help.

  • If I understand correctly you have an Account on an Opportunity.

    When you select an Account on the Opportunity you want to copy field my_account_field from Accounts to field my_opportunity_field on Opportunity but the user should be able to change the Opportunity field from that default if they wish to do so.

    I am assuming Account is a Relate Field on Opportunity so the Opportunity will have an account_id

    I would do this as an on.change on the account_id field on the opportunity in the Opportunity's record and create-actions view and check that the opportunity field is not already filled (you don't want to override what it was set to on an existing opportunity when it's edited).

    You will need something like:

    In custom/modules/Opportunities/clients/base/view/create-actions/create-actions.js

    and similar in  custom/modules/Opportunities/clients/base/view/record/record.js

    ({

      extendsFrom: 'CreateActionsView',

     

      initialize: function(options){

        this._super('initialize', [options]);

        this.model.on('change:account_id', this.populateMyOppField, this);

      },

    populateMyOppField: function(){

       //if the account field on the opportunity is not empty (we just changed it and it could have been deleted)

    if(!_.isEmpty(this.model.get('account_id')) {

         //if the field on the opp is not already set, you'll need this more on edit than create not to override prior values

          if(_.isEmpty(this.model.get('my_opportunity_field'))){

             //get the account bean

             var accountBean = app.data.createBean('Accounts', {id: account_id});

             requestAccount = accountBean.fetch();

             requestAccount.xhr.done(function(){

               //once you have the Account information you can copy my_account_field to my_opportunity_field

               this.model.set('my_opportunity_field', accountBean.get('my_account_field'));

             }

         }

       }

    },

    });

    Note the code is just intended to give you an idea, it is not tested, it's written off the cuff, so there could be syntax errors.

    There may be a better/easier way of doing this.

    HTH

    FrancescaS

  • Thanks a lot!! Worked perfectly . But i have a question, why extends the CreateActionsView? this manages the events in the record view?

  • In custom/modules/Opportunities/clients/base/view/record/record.js you extend record view and you need this for when you edit an existing record.

    You need the create-actions for when you create an Opportunity from scratch, a new one.

    So you need two pieces of code which are almost identical, the one above in

    custom/modules/Opportunities/clients/base/view/create-actions/create-actions.js

    and in

    custom/modules/Opportunities/clients/base/view/record/record.js

    ({

      extendsFrom: 'RecordView',

     

      initialize: function(options){

        this._super('initialize', [options]);

        this.model.on('change:account_id', this.populateMyOppField, this);

      },

    populateMyOppField: function(){

       //if the account field on the opportunity is not empty (we just changed it and it could have been deleted)

    if(!_.isEmpty(this.model.get('account_id')) {

         //if the field on the opp is not already set, you'll need this more on edit than create not to override prior values

          if(_.isEmpty(this.model.get('my_opportunity_field'))){

             //get the account bean

             var accountBean = app.data.createBean('Accounts', {id: account_id});

             requestAccount = accountBean.fetch();

             requestAccount.xhr.done(function(){

               //once you have the Account information you can copy my_account_field to my_opportunity_field

               this.model.set('my_opportunity_field', accountBean.get('my_account_field'));

             }

         }

       }

    },

    });

    HTH

    FrancescaS

  • Hello ,

    Francesca , do you know if this would be possible to do in reverse ? I guess calling model.set on the account.bean is not possible ? So would have the update it with an app.api.call ? app.api.call('update', app.api.buildURL('Accounts/'+accountid), {"accountfield" : "value" }, callbacks...  ?

  • So you want to update the related Account from within the Opportunities view controller?

    You should be able to do that:

             //get the account bean

             var accountBean = app.data.createBean('Accounts', {id: account_id});

             requestAccount = accountBean.fetch();

             requestAccount.xhr.done(function(){

               //once you have the Account you can update the values you need to update

               accountBean.set('the_field', the_value);

                // save your changes

                accountBean.save();

             }

     

    HTH

    FrancescaS

  • Oh Interesting thanks! So many ways to skin a cat.

    Did it with the api.call initially

    The bean.set offers superior performance I would reckon since there is no network overhead ?

    requestAccount.xhr.done(function(){
      //once you have the Account information compare the visit dates
      if ( moment(pcaDatVisite).isAfter(accountBean.get('v_der_date_visite_c').substr(0,10))) {
      //update the date visite of account using api.call
      //once you have the Account you can update the values you need to update
    
    
      accountBean.set('ca_autocompl_c', new Date(pcaDatVisite));
      // save your changes
      accountBean.save();
      /*
      app.api.call('update', app.api.buildURL('Accounts/'+relAccId), { "v_der_date_visite_c" : new Date(pcaDatVisite)}, {
      success: _.bind(function(response) {
      //response comes back from your api, maybe you want to set some value on your model or alter a response?
      }, this)
      });
      */
      }
      });
    
  • I would think the bean.set leverages the api, so the performance wouldn't necessarily be better one way or another. After all both need to affect the database.


    FrancescaS

  • Hi Francesca,

    The above sample code has been very helpful in solving a similar problem that I have.

    I'm using SugarCRM Professional 8.0.3. I have a relationship between my Contracts and Accounts. I want to copy a custom field from and Account ('account_licenseename_c') to a custom field on the Contract ('licenseename_c') when the Account is changed on the Contract, then eventually when a new Contract is created.

    I have adapted code from the example you provided in this post. However I seem to be receiving an error on the following line:

    this.model.set('licenseename_c',accountLicenseeName);

    The error is shown in the Debug window as "Uncaught TypeError: Cannot read property 'set' of undefined." As in the screen shot below.

    My full code is provided.

    ({

      extendsFrom: 'RecordView',

      initialize: function(options){

        this._super('initialize', [options]);
        this.model.on('change:account_id', this.populateMyField, this);

      },

        populateMyField: function(){

        //if the account field on the Agreement is not empty (we just changed it and it could have been deleted)

            if(!_.isEmpty(this.model.get('account_id'))) {


                //if the field on the Agreement is not already set, you'll need this more on edit than create not to override prior values
                var newAcccountID = this.model.get('account_id');

                if(_.isEmpty(this.model.get('licenseename_c'))){

                    //get the account bean
                    var accountBean = app.data.createBean('Accounts', {id: newAcccountID});
                    var accountLicenseeName = '';

                    requestAccount = accountBean.fetch();

                    requestAccount.xhr.done(function(){

                        accountLicenseeName = accountBean.get('account_licenseename_c');
                        //once you have the Account information you can copy account_licenseename_c to licenseename_c
                        console.log(accountBean.toJSON());
                        console.log(accountLicenseeName);
                        this.model.set('licenseename_c',accountLicenseeName);

                    })
                }
            }
        },
    });

    My console.log lines show the information as expected.

                        console.log(accountBean.toJSON());
                        console.log(accountLicenseeName);

    Any help or ideas on the best way to resolve this would be greatly appreciated.

  • Are you copying the Account name from the relate field into a text field called licenseename_c?

    Because if that's the case then you don't need to go through all that, you should have a hidden field called 'account_name' in the model itself.

    Try console.log(this.model) at the beginning of your method to see where the account name is, I'm pretty sure it's there.

    So your method could just copy that:

    populateMyField: function(){
      if(!_.isEmpty(this.model.get('account_name'))){
        this.model.set('licenseename_c', this.model.get('account_name'));
      }
    }

    If you need to get other fields from Accounts, then you can continue with the method above. I'm thinking I had an error in the code and that inside the xhr the "this" is not what we think it should be, add a 

    var self = this;

    at the beginning of your method and then use self instead of this inside the xhr, that should work.

    FrancescaS

  • Thanks Francesca, 

    var self = this;

    Was what I needed.