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.

Parents
  • 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

Reply
  • 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

Children
  • 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. 

  • Hi Francesca, 

    Thanks again, the solution you provided above is working well for me now when I create a Contract from scratch.

    However when I create a Contract from the Account Screen, or from the Contract Menu, the Account Name is already populated and does not fire the OnChange event, therefore my "licneseename_c" field is not set on the Contract when they are created with this method.  (BTW we call call Contracts Agreements.)

    Do you know if this is a different Event that is fired, e.g. an OnLoad event, or is there a way of detecting where the Contract was created from, e.g. from scratch or form the Account page?  As I would like to make sure that my "licenseename_c" field is populated when I create Contracts/Agreements using these methods. 

    As always, any suggestions would be greatly appreciated. 

  • Because you are in the "Create" view clearly this is a new record, otherwise you would be in the "Record" view. This means that ever time your CreateView controller runs it does so for a brand new record.

    You could therefore run the Populate my field directly in your initialize for the first time, then repeat it if the account changes (maybe the user got the wrong account at first and wants to change it):

    ({

      extendsFrom: 'RecordView',

      initialize: function(options){

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

        populateMyField: function(){

               ....do your thing
          
        },
    })

    The

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

    will prevent the function from running any further if there is no account selected.

    Having said that, note that you have a condition:

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

    Which means that the function only takes effect once - the first time you set the liceseename. 

    If the user sets the account, then changes the account (maybe they made a mistake), the licesee name will NOT change to that of the newly set account. I think you should remove that if statement - though I may be missing something in your logic.

    You may also consider adding the on change event to your Record View controller in case a user wants to change the Account after the record was saved. When editing a previously saved record the controller will be the RecordView controller, not the Create controller.

    Hope this helps,

    FrancescaS