Tried to add Line items to Opportunities

Hello,
I am trying to add Line items to Opportunities. I followed the instructions here::

What I have done so far:

  1. Created Opportunities module in custom, and copied over the vardefs.php and added line item and product quote props. Also added the relationships.
  2. Added the items in the language file.
  3. Copied in changes from invoices for the save functionailty
  4. Modified the detail and edit files.
    When I tried this , this is what I see

I also don’t see a script generated for the new data when I do a quick repair and rebuild. What am I missing here.

For example, add the Positions panel to the Opportunity module.

Important note, this guide is an example and does not provide a safe update as changes are made directly to the Opportunity module.

Developer mode must be enabled.

1 Step. In the Opportunity module, we create a one-to-many relationship (Main Opportunity module) with a subordinate Positions module.

Example picture below:

Relation:

Result:

Let’s remember that our relation has the name:

opportunities_aos_products_quotes_1

this name was generated automatically in the Studio.

Opportunity module name: Opportunities
Table in the database: opportunities

'relationship' => 'opportunities_aos_products_quotes_1',
'lhs_module' => 'Opportunities',
'lhs_table' => 'opportunities',

This is necessary for proper installation in /custom/modules/Opportunities/Ext/Vardefs/vardefs.ext.php
image

This will be discussed later.

Repair and Rebuild.

Step 2. Add fields related to the Positions module (LBL_CURRENCY,….LBL_GRAND_TOTAL) to the panel of the Deals module in /custom/modules/Opportunities/metadata/editviewdefs.php and /custom/modules/Opportunities/metadata/detailviewdefs.php

   'lbl_editview_panel1' => 
      array (
        0 => 
        array (
          0 => 
          array (
            'name' => 'currency_id',
            'studio' => 'visible',
            'label' => 'LBL_CURRENCY',
          ),
        ),
        1 => 
        array (
          0 => 
          array (
            'name' => 'line_items',
            'label' => 'LBL_LINE_ITEMS',
          ),
        ),
        2 => 
        array (
          0 => 
          array (
            'name' => 'total_amt',
            'label' => 'LBL_TOTAL_AMT',
          ),
        ),
        3 => 
        array (
          0 => 
          array (
            'name' => 'discount_amount',
            'label' => 'LBL_DISCOUNT_AMOUNT',
          ),
        ),
        4 => 
        array (
          0 => 
          array (
            'name' => 'subtotal_amount',
            'label' => 'LBL_SUBTOTAL_AMOUNT',
          ),
        ),
        5 => 
        array (
          0 => 
          array (
            'name' => 'shipping_amount',
            'label' => 'LBL_SHIPPING_AMOUNT',
            'displayParams' => 
            array (
              'field' => 
              array (
                'onblur' => 'calculateTotal(\'lineItems\');',
              ),
            ),
          ),
        ),
        6 => 
        array (
          0 => 
          array (
            'name' => 'shipping_tax_amt',
            'label' => 'LBL_SHIPPING_TAX_AMT',
          ),
        ),
        7 => 
        array (
          0 => 
          array (
            'name' => 'tax_amount',
            'label' => 'LBL_TAX_AMOUNT',
          ),
        ),
        8 => 
        array (
          0 => 
          array (
            'name' => 'total_amount',
            'label' => 'LBL_GRAND_TOTAL',
          ),
        ),
      ),

These values ​​can be obtained from any module where Positions are used:

The result will be to display the panel in edit and view mode:

If we refresh the page we will see this result:

Step 3. Add translation of field headers for your language /custom/modules/Opportunities/language/en_us.lang.php

$mod_strings = array (
  'LBL_OPPORTUNITIES_AOS_PRODUCTS_QUOTES_1_FROM_AOS_PRODUCTS_QUOTES_TITLE' => 'Line Items',
  'LBL_IMPORT_LINE_ITEMS' => 'Import Line Items',
  'LBL_LINE_ITEMS' => 'Line Items',
  'LBL_GRAND_TOTAL' => 'Grand Total',
  'LBL_TOTAL_AMT' => 'Total',
  'LBL_TAX_AMOUNT' => 'Tax',
  'LBL_SUBTOTAL_AMOUNT' => 'Subtotal',
  'LBL_SHIPPING_AMOUNT' => 'Shipping',
  'LBL_SHIPPING_TAX_AMT' => 'Shipping Tax',
  'LBL_DISCOUNT_AMOUNT' => 'Discount',
  'LBL_ADD_PRODUCT_LINE' => 'Add Product Line',
  'LBL_ADD_SERVICE_LINE' => 'Add Service Line ',
  'LBL_REMOVE_PRODUCT_LINE' => 'Remove',
  'LBL_SERVICE_NAME' => 'Service',
  'LBL_SERVICE_LIST_PRICE' => 'List',
  'LBL_SERVICE_PRICE' => 'Sale Price',
  'LBL_SERVICE_DISCOUNT' => 'Discount',
  'LBL_VAT_AMT' => 'Tax Amount',
  'LBL_TOTAL_PRICE' => 'Total',
  'LBL_PRODUCT_QUANITY' => 'Quantity',
  'LBL_PRODUCT_NAME' => 'Product',
  'LBL_PART_NUMBER' => 'Part Number',
  'LBL_PRODUCT_NOTE' => 'Note',
  'LBL_PRODUCT_DESCRIPTION' => 'Description',
  'LBL_LIST_PRICE' => 'List',
  'LBL_DISCOUNT_AMT' => 'Discount',
  'LBL_UNIT_PRICE' => 'Sale Price',
  'LNK_LIST' => 'View Invoices',
  'LBL_AOS_CONTRACTS' => 'Contracts',
  'LBL_AOS_QUOTES' => 'Quotes',
);

Step 4. Add fields and connections to vardefs /custom/modules/Opportunities/Ext/Vardefs/vardefs.ext.php

For example:

$dictionary['Opportunity']['fields']['tax_amount'] =
  array(
      'required' => false,
      'name' => 'tax_amount',
      'vname' => 'LBL_TAX_AMOUNT',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => 1,
      'reportable' => true,
      'len' => '26,6',
);
  $dictionary['Opportunity']['fields']['shipping_tax_amt'] =
  array(
      'required' => false,
      'name' => 'shipping_tax_amt',
      'vname' => 'LBL_SHIPPING_TAX_AMT',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => 0,
      'reportable' => true,
      'len' => '26,6',
      'size' => '10',
      'enable_range_search' => false,
      'function' =>
          array(
              'name' => 'display_shipping_vat',
              'returns' => 'html',
              'include' => 'modules/AOS_Products_Quotes/Line_Items.php'
          ),
        );
  $dictionary['Opportunity']['fields']['shipping_amount'] =
  array(
      'required' => false,
      'name' => 'shipping_amount',
      'vname' => 'LBL_SHIPPING_AMOUNT',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => 0,
      'reportable' => true,
      'len' => '26,6',
  );
  $dictionary['Opportunity']['fields']['subtotal_amount'] =
  array(
      'required' => false,
      'name' => 'subtotal_amount',
      'vname' => 'LBL_SUBTOTAL_AMOUNT',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => 1,
      'reportable' => true,
      'len' => '26,6',
  );
$dictionary['Opportunity']['fields']['currency_id'] =
  array(
      'required' => false,
      'name' => 'currency_id',
      'vname' => 'LBL_CURRENCY',
      'type' => 'id',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => 0,
      'audited' => false,
      'reportable' => false,
      'len' => 36,
      'size' => '20',
      'studio' => 'visible',
      'function' =>
          array(
              'name' => 'getCurrencyDropDown',
              'returns' => 'html',
              'onListView' => true,
          ),
        );
  $dictionary['Opportunity']['fields']['discount_amount'] =
  array(
      'required' => false,
      'name' => 'discount_amount',
      'vname' => 'LBL_DISCOUNT_AMOUNT',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => 1,
      'reportable' => true,
      'len' => '26,6',
  );
  $dictionary['Opportunity']['fields']['line_items'] =
  array(
      'required' => false,
      'name' => 'line_items',
      'vname' => 'LBL_LINE_ITEMS',
      'type' => 'function',
      'source' => 'non-db',
      'massupdate' => 0,
      'importable' => 'false',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => 0,
      'audited' => false,
      'reportable' => false,
      'inline_edit' => false,
      'function' =>
          array(
              'name' => 'display_lines',
              'returns' => 'html',
              'include' => 'modules/AOS_Products_Quotes/Line_Items.php'
          ),
        );
  $dictionary['Opportunity']['fields']['total_amount'] =
  array(
      'required' => false,
      'name' => 'total_amount',
      'vname' => 'LBL_GRAND_TOTAL',
      'type' => 'currency',
      'massupdate' => 0,
      'comments' => '',
      'help' => '',
      'importable' => 'true',
      'duplicate_merge' => 'disabled',
      'duplicate_merge_dom_value' => '0',
      'audited' => false,
      'reportable' => true,
      'len' => '26,6',
      'enable_range_search' => true,
      'options' => 'numeric_range_search_dom',
  );
  $dictionary['Opportunity']['fields']['aos_products_quotes'] =
  array(
      'name' => 'aos_products_quotes',
      'vname' => 'LBL_AOS_PRODUCT_QUOTES',
      'type' => 'link',
      'relationship' => 'opportunities_aos_products_quotes_1',
      'module' => 'AOS_Products_Quotes',
      'bean_name' => 'AOS_Products_Quotes',
      'source' => 'non-db',
  );
 $dictionary['Opportunity']['fields']['opportunities_aos_products_quotes_1'] =
  array(
      'lhs_module' => 'Opportunities',
      'lhs_table' => 'opportunities',
      'lhs_key' => 'id',
      'rhs_module' => 'AOS_Products_Quotes',
      'rhs_table' => 'aos_products_quotes',
      'rhs_key' => 'parent_id',
      'relationship_type' => 'one-to-many',
  );
  $dictionary['Opportunity']['fields']['opportunities_aos_line_item_groups'] =
  array(
      'lhs_module' => 'Opportunities',
      'lhs_table' => 'opportunities',
      'lhs_key' => 'id',
      'rhs_module' => 'AOS_Line_Item_Groups',
      'rhs_table' => 'aos_line_item_groups',
      'rhs_key' => 'parent_id',
      'relationship_type' => 'one-to-many',
  );

For example:

Step 5. Add logic for saving Positions in the Opportunity module (public function save($check_notify = false)) /modules/Opportunities/Opportunity.php

require_once('modules/AOS_Line_Item_Groups/AOS_Line_Item_Groups.php');
$productQuoteGroup = BeanFactory::newBean('AOS_Line_Item_Groups');
$productQuoteGroup->save_groups($_POST, $this, 'group_');

Important: this code is added to the main module and is not safe when updating SuiteCRM

Results:

All that remains is to add translations of the panels

2 Likes

Thank you for such a detailed answer. I truly appreciate it. I have got it working to the point of having the items appear. The line items however do not get saved in the DB. The totals (the data that is in the opportunities table itself is getting saved - just not the line items. Any idea why that could be?

Check step 5, this is save logic

Should this work in version 8? (8.7)

I assume this: custom/modules/Opportunities/Ext/Vardefs/vardefs.ext.php will become /public/legacy/custom/modules/Opportunities/Ext/Vardefs/vardefs.ext.php ?

This file is auto generated, so fails at step 1 as each time i repair this file is reset.

I haven’t tried, but I doubt this will work in SuiteCRM 8, unless you make the Opportunities module a legacy module.

Thanks, i really don’t want to do that! L like the insights bar on that module, Still getting used to version 8!

@marat.agl, instead of adding entire Line Items module in the views. I just want functionality of ADD PRODUCT LINE.

The ADD PRODUCT LINE will only have 3 columns in the row :arrow_right:

Quantity, Part Number and Description

Is it possible to implement it? Also, when we generate a PDF from the Cases module, it should displays those Line Items values into the PDF. Using v7.13! :face_with_peeking_eye:

How to do it? @vibhagopal, @pstevens do you guys have any ideas? :bulb:


Where can I add lines of code from the step 5 for the Cases module. I did not see the similar function.

For Cases:

modules/Cases/Case.php


    public function save($check_notify = false)
    {
            // Remove invoice-specific numbering logic
            require_once('modules/AOS_Products_Quotes/AOS_Utils.php');
            
            // Handle line items first
            perform_aos_save($this);
            
            // Save relationships before parent save
            $this->save_relationship_changes(true);
            
            $return_id = parent::save($check_notify);
            
            // Use correct relationship prefix
            $productQuoteGroup = BeanFactory::newBean('AOS_Line_Item_Groups');
            $productQuoteGroup->save_groups($_POST, $this, 'cases_'); 
            
            return $return_id;
    }