How do you autopopulate a related field in custom module from a related field of another module?

I'm fighting against this issue since a couple of weeks and I can't figure out a way to do that.

I have a custom module for the orders management and I need to produce invoices automatically.
I'm following the example of 'ConverToInvoice.php' from Quotes module so, if I click on that button (under the Edit button in Detail View) I should create a new Invoice whose fields are pre-filled and  editable.
I have to grab fields' values from current order management.
My first problem is that a lot of those fields are related, too.

For example, I need to fill a related field called 'Suppliers' in my invoice. The value I need comes from a module (Suppliers) related to the Account, which is related to the current order management.

How can I easily grab that value and put it in my suppliers field?

I tryed to follow this guide  but it didn't worked.. probably I miss something.
I really need help, as soon as possible.

Thank you.

  • Cristina,
    How many Accounts are related to your OrderManagement record and how many Suppliers are related to an Account? Are these records linked via a relate field or a relationship?

    If they are just relate fields the Account on the OrderManagement can be retrieved using the bean. If $bean is your Order Management bean, and account_id is the relate field for Account on that bean.

    $account = new Account();
    $account->retrieve($bean->account_id);

    Now $account is the bean with all the Account information.
    In turn if Supplier is a relate field on Account and supplier_id is the relate field for Supplier on that bean:

    $supplier = new Supplier();
    $supplier->retrieve($account->supplier_id);

    If instead you have multiple Accounts on an OrderManangement and/or multiple Suppliers on an Account and want to retrieve them all  you can get related beans using the relationship name as described by Jeff Bickart: http://developer.sugarcrm.com/2012/03/23/howto-using-the-bean-instead-of-sql-all-the-time/

    I always find getting the right relationship name a bit tricky so I created a function that given two modules returns the relationship name:
    http://developer.sugarcrm.com/2013/05/29/programmatically-find-the-name-of-the-relationship-between-...
     
    I personally keep this, and other such functions I created, in a utilities folder for reuse but you can also simply include it in the script you are writing.

    So you can do something like (note, I'm guessing your module names).
    (assuming you have $bean = your current Order_Management bean)

    include_once('<your path to my function>/getRelashionshipByModules.php'); $suppliers = array();
    $order_to_account_relationship = getRelationshipByModules ('Order_Management', 'Accounts');
    $account_to_supplier_relationship = getRelationshipByModules('Account', 'Suppliers');
    $bean->load_relationship($order_to_account_relationship);
    //loop through the Accounts linked to the Order
    foreach($bean->$order_to_account_relationship->getBeans() as $account){
        //loop through the suppliers for this account
        $account->load_relationship($account_to_supplier_relationship);
        foreach($account->$account_to_supplier_relationship->getBeans as $supplier){        //check for duplicated by id (the key of the array)        //if you don't already have this supplier in your list, add it.
           if(!array_key_exists($supplier->id, $suppliers)) $suppliers[ $supplier->id] = $supplier->name;
       }
    }
    //the array $suppliers now contains all your suppliers with key the id of the record and value the name of the supplier.

    Note, the code above has not been tested, it's just to give you some ideas.
    Spero che questa risposta ti sia d'aiuto.

    HTH
    FrancescaS
  • Hi, thank you so much for your reply, it really helped me a lot.
    My relationships are One to Many and Many to Many, something like
    Order Management <<--->> Account <<---> Supplier
    so I guess I have to retrieve records using the second solution you told me.
    I can delete relationships and use only related fields, at the least for the One to Many relationships (I don't actually need the 'Many' part)..
    I have just one question: almost all the fields I need to fill in Invoice, are custom. How can I refer those fields? They are columns of the _cstm tables on DB and I don't know how to grab them.
    I was wondering if can I retrieve a record with
    $account->retrieve($bean->account_id);
    and refer a single fields as
    $account->field_name;
    or
    $account->field_name_c; //for a custom field
    Thank you so much for your support.
    Cheers.
  • That is the correct way to refer to custom fields, yes. They are part of the bean once retrieved.
    So $account->field_name_c for custom fields is perfect.
  • Ok that's a good news.
    I'm in troubles with 'load_relationship()' function now..
    As you told me, I called that function  on
    $bean->load_relationship($order_to_account_relationship);
    but I receive a PHP Fatal Error:
    Call to a member function load_relationship() on a non-object in /../custom/modules/Cproj_order_management01/converToInvoice.php on line 95, referer: ..=Cproj_order_management01&action=DetailView&record=420d92b1-1cde-725b-b6ef-522725fbaf91
    I'm not understanding what's the matter. I tried to declarate a new object for $bean but it didin't solve the problem.
    This is the whole code I wrote since now.

    require_once('modules/Cproj_order_management01/Cproj_order_management01.php');
    require_once('modules/AOS_Invoices/AOS_Invoices.php');
    require_once('modules/Accounts/Account.php');
    require_once('modules/a122_Suppliers/a122_Suppliers.php');
    require_once('modules/Relationships/Relationship.php');

    global $timedate;
       //your function
    function getRelationshipByModules ($m1, $m2)
    {
    global $db,$dictionary,$beanList;
    $rel = new Relationship;
    if($rel_info = $rel->retrieve_by_sides($m1, $m2, $db)){
    $bean = BeanFactory::getBean($m1);
    $rel_name = $rel_info['relationship_name'];
    foreach($bean->field_defs as $field=>$def){
    if(isset($def['relationship']) && $def['relationship']==$rel_name) {
      return(array($def['name'], $m1));
    }
    }
    } elseif($rel_info = $rel->retrieve_by_sides($m2, $m1, $db)){
    $bean = BeanFactory::getBean($m2);
    $rel_name = $rel_info['relationship_name'];
    foreach($bean->field_defs as $field=>$def){
    if(isset($def['relationship']) && $def['relationship']==$rel_name) {  
                   return(array($def['name'], $m2));
    }
       }
    }
    return(FALSE);
    }
    $invoice=new AOS_Invoices();
    //$om=new Cproj_order_management01();

    $suppliers=array();

    $order_to_account_relationship = getRelationshipByModules ('Cproj_order_management01', 'Accounts');
    $account_to_supplier_relationship = getRelationshipByModules('Accounts', 'a122_Suppliers');
    $bean->load_relationship($order_to_account_relationship);
    foreach($bean->$order_to_account_relationship->getBeans() as $account){
    $account->load_relationship($account_to_supplier_relationship);
    foreach($account->$account_to_supplier_relationship->getBeans() as $supplier){
     
    if(!array_key_exists($supplier->id, $suppliers)) 
          $suppliers[ $supplier->id] = $supplier->name;
    }
    }
    //when It works I'm gonna use that fields to fill my invoice fields
    [......]

    $invoice->save();

    ob_clean();
    header('Location: index.php?module=AOS_Invoices&action=EditView&record='.$invoice->id);
    I'm going crazy. Thanks for your help, again.

  • Try an echo after you get the relationship and die(); to see what you can see...

    $order_to_account_relationship = getRelationshipByModules ('Cproj_order_management01', 'Accounts');
    echo("relationship = " . $order_to_account_relationship);die();

    There may be a problem fetching the relationship....

  • Ok, perfect, I found the problem. My relationship was empty, I thought it was Many to Many, but the field value I was searching for was in a related field and the relationship was actually One To One.
    Now I can retrieve all I need! :D
    Last question. How do I fill related fields in my Invoice with values I just retrieved?
    I have no problem on populate simple text fields, but is not the same for related fields.

    Thank you, you are saving my life!

  • If you are creating a new invoice in the script then you can do so just populating the supplier id in the invoice bean populating the bean:

    //create a new bean
    $invoice=new AOS_Invoices();
    //for each object populate it
    $invoice->field_name = "field_value";
    //relate the invoice to the supplier
    $invoice->supplier_id = $supplier_id //check the naming of the relate field's id
    $invoice->save();

    Francesca
  • Hi there

    I have  a similar problem like you are managing in this post. I have created two custom modules with a one to one relationship

    R2_Microchip has a one to one relathichip with R2_Solicitud. I am builing a button in the DetailView of the R2_Solicitud module and this button calls a controller function that needs to take the related R2_Microchip and work with it.

    To do so i need to know the relationship between these two modules to be able to call it.

    I have found in this forum a post that points to  this blog

    http://developer.sugarcrm.com/2013/05/29/programmatically-find-the-name-of-the-relationship-between-...

    However in my code, when I call this function this way

    $rel_microchip = getRelationshipByModulesgetRelacion("R2_Solicitud","R2_Microchip");

    $bean_solicitud->load_relationship($rel_microchip);
    $chip_bean=implode($bean_solicitud->$rel_microchip->get());

    I get this error message in the log file
    Warning: Illegal offset type in isset or empty in /opt/lampp/htdocs/sugarcrm/data/SugarBean.php on line 975

    Notice: Array to string conversion in /opt/lampp/htdocs/sugarcrm/custom/modules/R2_Solicitud/Funciones_Solicitud.php on line 75

    Notice: Undefined property: R2_Solicitud::$Array in /opt/lampp/htdocs/sugarcrm/custom/modules/R2_Solicitud/Funciones_Solicitud.php on line 75

    Fatal error: Call to a member function get() on a non-object in /opt/lampp/htdocs/sugarcrm/custom/modules/R2_Solicitud/Funciones_Solicitud.php on line 75
    (Line 75 is this one in my code $chip_bean=implode($bean_solicitud->$rel_microchip->get());)

    As the function is returning just the word "Array".
    If this function does not work.... How can I know how to call the relationships between two custom modules like 
    $bean_solicitud->load_relationship($rel_microchip);??????

    Thanks a lot!!
  • Note that my function from the blog returns an array when it finds the relationship:
    return(array($def['name'], $m1));
    or
    return(array($def['name'], $m2));

    The first element is the relationship name, the second the rhs module, just in case you need it. You get "Array" if you echo the result because it's returning an array, if you try a var_dump instead you'll see it's components.

    Try
    list($rel_microchip, $m) = getRelationshipByModulesgetRelacion("R2_Solicitud","R2_Microchip");

    HTH
    FrancescaS