Oracle CRM On Demand Desktop Administration Guide > Customizing Oracle CRM On Demand Desktop >

Setting Up Books for a Customized Package from Version 2.0


To set up book functionality from a customized Oracle CRM On Demand Desktop Version 2.0 package to work with the current version of Oracle CRM On Demand Desktop, complete the following procedure.

Before You Begin

Complete the steps in Updating Oracle CRM On Demand Desktop Product-Specific Files from Version 5.0 to Version 5.1.

To set up books for a customized package from Version 2.0

  1. In the package_res.xml file, insert the following lines inside the <res_root> element:

    <str key="lbl_book_of_business">Book Name:</str>
    <str key="btn_book_select">...</str>
    <str key="obj_book_plural">Books</str>
    <str key="lbl_record_set_caption">Record Set</str>
    <str key="cbx_record_set_team">All records where I am owner or on the team</str>
    <str key="cbx_record_set_book">All records in a book</str>
    <str key="cbx_record_set_default_book">All records in my default book</str>
    <str key="btn_book_select">...</str>
    <str key="head_record_type">Record Type</str>
    <str key="head_visibility_model">Record Set</str>
    <str key="head_book_name">Book Name</str>
    <str key="record_set_tab_description">Please specify the visibility model to be used for each record type. If using visibility based on Book of Business, you will need to pick a book using the Book Selector. If a visibility mode is not specified for a record type, then "Owner and Team" visibility will be used.</str>
    <str key="caption_book_dlg">Select Book</str>
    <str key="msg_book_is_required">Book Name is required.</str>
    <str key="msg_book_cannot_contain_data">This book cannot contain data. Select another one to proceed.</str>
    <str key="msg_book_must_be_custom">Record must be associated to a custom book.</str>
    <str key="msg_owner_must_be_empty">Owner must be empty.</str>
    <str key="inaccessible_book">&lt;Inaccessible book&gt;</str>
    <str key="lbl_include_book_subitems">Include Sub-Items</str>
    <str key="book_selector_top_node">$obj_book_plural$</str>
    <str key="msg_ownership_log" skip_translation="yes">Ownership mode of {0} is {1}</str>
    <str key="msg_Specifying_both_Book_and_Owner_is_prohibited">Specifying both Book and Owner is prohibited.</str>
    <str key="lbl_books_not_supported">There are no Books of Business defined for this user. Only records where you are owner or a team member will be synchronized.</str>
    <str key="books_retrieve_failed_title">Books of Business</str>
    <str key="btn_clear">Clear</str>
    <str key="filter_page-page_description">Please, specify the criteria you'd like to use for determining which $remote_app_name$ items have to be synchronized with $app_name$. The following filters are applied to selected categories and sub-categories based on the data selected in the $lbl_record_set_caption$ tab.</str>
    <str key="msg_subitems_required_for_book">The book you have selected is a parent book and cannot contain data.
    To synchronize using the related sub-books, enable "Include Sub-Books" to continue.
    If this parent book has no sub-books, select another book.</str>
    <str key="msg_cannot_select_book_subitems_disallowed">You cannot select a book that cannot contain data.</str>
    <str key="head_contact_book_info">Contact Book info</str>
    <str key="head_account_book_info">Account Book info</str>
    <str key="head_opportunity_book_info">Opportunity Book info</str>
    <str key="head_lead_book_info">Lead Book info</str>
    <str key="err_msg_invalid_request">Request contains invalid data</str>
    <str key="msg_book_access_denied">You don't have access rights to Books of Business, used for synchronization or the Books are no longer valid. Please check your Books of Business configuration settings in the Control Panel or contact technical support for assistance.</str>
    <str key="msg_record_access_denied">Access denied.</str>
    <str key="msg_record_set_query_save_record_set">Do you want to save changes to record set?</str>

  2. In the dialogs.xml file, make the following updates:
    1. Remove the following lines from the <dialogs> element:

    <dialog id="Control panel">
      <script>
      </script>
      <layout caption="#control_panel_title" sizable="true"    small_icon="app_small_icon">
        <appearance height="480" width="744" position="desktop_center" />
        <cell>
          <stack layout="vert" rollup="true">
            <cell size="70">
              <cp_toolbar id="toolbar"/>
            </cell>
            <cell size="32" autosize="true">
              <cp_infobar id="infobar"/>
            </cell>
            <cell>
              <pages id="cp_pages" tab_order="2">
                <page id="cp_busy_page" layout="cp_busy_page"/>
                <page id="cp_filters_page" layout="cp_filters_page"/>
                <page id="cp_issues_page" layout="cp_issues_page"/>
                <page id="cp_conflicts_page" layout="cp_conflicts_page"/>
                <page id="cp_duplicates_page" layout="cp_duplicates_page"/>
                <page id="cp_confirmations_page" layout="cp_confirmations_page"/>
              </pages>
            </cell>
          </stack>
        </cell>
      </layout>
    </dialog>

    1. Insert the following lines inside the <dialogs> element:

    <dialog id="select_book_dialog">
      <script><![CDATA[]]>
      </script>
      <layout sizable="true" id="General" caption="#caption_book_dlg"    min_height="300" min_width="600" small_icon="app_small_icon">
        <appearance height="300" width="600" position="desktop_center" />
        <cell>
          <stack layout="horz" padding="10">
            <cell>
              <stack layout="vert" padding="10" spacing="5">
                <cell>
                  <stack layout="horz" spacing="5" padding="5">
                    <cell>
                      <treeview id="books_tree" tab_order="1" lines_at_root="true" /                   >
                    </cell>
                  </stack>
                </cell>
                <cell size="10" />
                <cell size="25">
                  <stack layout="horz" spacing="5">
                    <cell size="75">
                      <button tab_order="2" id="btn_clear" visible="false">
                        <text>#btn_clear</text>
                      </button>
                    </cell>
                    <cell>
                      <checkbox id="include_subitems" tab_order="3" visible="false">
                        <text>#lbl_include_book_subitems</text>
                      </checkbox>
                    </cell>
                    <cell />
                    <cell size="75">
                      <button tab_order="4" id="btn_ok">
                        <text>#btn_ok</text>
                      </button>
                    </cell>
                    <cell size="75">
                      <button id="btn_cancel" tab_order="5">
                        <text>#btn_cancel</text>
                      </button>
                    </cell>
                  </stack>
                </cell>
              </stack>
            </cell>
          </stack>
        </cell>
      </layout>
    </dialog>

  3. In the connector_configuration.xml file, make the following updates:
    1. Locate the <bindings> section and make the following updates:
      • Add the following code to <type name="Opportunity"> section:

    <binding>
      <field name="OwnerId"/>
      <field name="BookId"/>
    </binding>

    • Add the following code to the <type name="Activity"> section:

    <binding>
      <field name="OwnerId"/>
      <field name="BookId"/>
    </binding>

    • Add the following code to <bindings>:

    <type name="Contact">
        <binding>
          <field name="OwnerId"/>
          <field name="BookId"/>
        </binding>
    </type>
    <type name="Account">
        <binding>
          <field name="OwnerId"/>
          <field name="BookId"/>
        </binding>
    </type>
    <type name="Lead">
        <binding>
          <field name="OwnerId"/>
          <field name="BookId"/>
        </binding>
    </type>

    1. Add the following code to the <types> section:

    <type id="Book.Type.Association"> <!--Fake type to store user selected data-->
        <view label="Book.Type.Association" label_plural="Book.Type.Association"      small_icon="type_image:Generic:16" normal_icon="type_image:Generic:24"      large_icon="type_image:Generic:48" suppress_sync_ui="true"></view>
        <synchronizer sync_it="false" name_format=":[:(BookId) :]:[:(TypeName):]"      threshold="0">
          <natural_keys>
            <natural_key>
              <field>TypeName</field>
            </natural_key>
          </natural_keys>
        </synchronizer>
    </type>
    <type id="Book">
        <view label="Book" label_plural="Books" small_icon="type_image:Generic:16"      normal_icon="type_image:Generic:24" large_icon="type_image:Generic:48"      suppress_on_top="true" suppress_sync_ui="true"></view>
        <synchronizer name_format=":[:(Label):]" threshold="0" frequency="0">
          <links></links>
        </synchronizer>
    </type>
    <type id="BookDefaults">
        <view label="BookDefaults" label_plural="BookDefaults"     small_icon="type_image:Generic:16" normal_icon="type_image:Generic:24"     large_icon="type_image:Generic:48" suppress_sync_ui="true"></view>
        <synchronizer name_format=":[:(Value) :]:[:(BookId):]" threshold="0"     frequency="0">
          <links></links>
        </synchronizer>
    </type>
    <type id="RequiredFields">
        <view label="RequiredFields" label_plural="RequiredFields"      small_icon="type_image:Generic:16" normal_icon="type_image:Generic:24"      large_icon="type_image:Generic:48" suppress_sync_ui="true"></view>
        <synchronizer name_format=":[:(TypeName) :]:[:(Value):]" threshold="0"      frequency="0">
          <links></links>
        </synchronizer>
    </type>

    1. Replace the two occurrences of the <field>OwnerId</field> element inside the <type id="Activity"> <natural_keys> section with the following line:

    <field allow_null="true">OwnerId</field>

  4. Update the data_sources.xml file, as follows:
    1. Replace all occurrences of the scope="general" attribute with the following value:

    scope="6001"

    1. Insert the following lines inside the <connector> element:

    <data_source name="Book.Type.Association">
        <type>Book.Type.Association</type>
        <columns>
          <column>TypeName</column>
          <column>BookId</column>
          <column>IncludeSubBooks</column>
        </columns>
    </data_source>
    <data_source name="::Defaults">
        <type>::Defaults</type>
        <columns>
          <column>DefaultBookId</column>
          <column>DefaultBookName</column>
        </columns>
    </data_source>
    <data_source name="Book">
        <type>Book</type>
        <columns>
          <column>Label</column>
          <column>Value</column>
          <column>ParentBookName</column>
          <column>ParentBookId</column>
          <column>BookType</column>
          <column>CanContainDataFlag</column>
        </columns>
    </data_source>
    <data_source name="BookDefaults">
        <type>BookDefaults</type>
        <columns>
          <column>Label</column>
          <column>Value</column>
          <column>BookId</column>
          <column>IncludeSubBooks</column>
          <column>OrderNumber</column>
        </columns>
    </data_source>

  5. In the forms_11.xml and forms_12.xml files, add a book selector control and a label to each form for the book-enabled object types, and provide a tab_order attribute value for those elements:
    • Label:

    <static id="lbl_book_of_business" tab_order="...">
      <text>#lbl_book_of_business</text>
    </static>

    • Book selector control:

    <stack layout="horz">
      <cell>
        <scriptable_edit id="book_of_business" tab_order="...">
          <field value="string"></field>
        </scriptable_edit>
      </cell>
      <cell size="5"></cell>
      <cell size="22">
        <button id="btn_book_select" tab_order="...">
          <text>#btn_book_select</text>
        </button>
      </cell>
    </stack>

  6. Update the od_basic_mapping.xml file as follows:
    1. Insert the following lines inside the <type id = "User"> element:

    <field id = "PrimaryPositionId"> <!-- Custom Book id -->
        <type>
          <simple type = "string"/>
        </type>
    </field>

    1. Insert the following lines inside the <type id = " ::Defaults"> element:

    <field id = "DefaultBookId">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "DefaultBookName">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "Book">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "TypeDefaultBook">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "RequiredFields">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "PrimaryPositionId">
        <type>
          <simple type = "string"/>
        </type>
    </field>
    <field id = "FullName">
        <type>
          <simple type = "string"/>
        </type>
    </field>

    1. Add new types by inserting XML code inside the <database> <types> element. For a listing of the code to add, see XML Code Addition for the od_basic_mapping.xml File.
    2. Add the BookId field to each book-enabled object type as follows:

    <field id="BookId">
        <reader>
          <mapi_user>
            <user_field id="od BookId" ol_field_type="1"></user_field>
            <convertor>
              <string/>
            </convertor>
          </mapi_user>
        </reader>
        <writer>
          <outlook_user>
            <user_field id="od BookId" ol_field_type="1"></user_field>
            <convertor>
              <string/>
            </convertor>
          </outlook_user>
        </writer>
    </field>

  7. Update the od_meta_info.xml file as follows:
    1. Locate the following lines:

    <product_flavor>OD</product_flavor>
    <error_codes Type="RecordAlreadyExists" >SBL-EAI-04383/SBL-EAI-04383, SBL-DAT-00381/SBL-EAI-04381, SBL-DAT-00357/SBL-EAI-04375, SBL-DAT-00381/SBL-DAT-00381, SBL-DAT-00357/SBL-DAT-00357, SBL-DAT-00215/SBL-DAT-00215</error_codes>
    <error_codes Type="RecordAlreadyDeleted" >SBL-EAI-04378/SBL-EAI-04378</error_codes>
    <error_codes Type="AccessDenied" >*/SBL-ODS-50085</error_codes>
    <error_codes Type="SessionExpired" >SBL-ODU-01006/*</error_codes>
    <error_codes Type="RecordUpdatedPrematurely" >SBL-DAT-00523/SBL-EAI-04290</error_codes>

    1. Replace these lines with the following:

    <errors>
        <codes Type="RecordAlreadyExists">SBL-EAI-04383/SBL-EAI-04383, SBL-DAT-     00381/SBL-EAI-04381, SBL-DAT-00357/SBL-EAI-04375, SBL-DAT-00381/SBL-     DAT-00381, SBL-DAT-00357/SBL-DAT-00357, SBL-DAT-00215/SBL-DAT-00215</     codes>
         <codes Type="RecordAlreadyDeleted">SBL-EAI-04378/SBL-EAI-04378</codes>
         <codes Type="AccessDenied">*/SBL-ODS-50085</codes>
        <codes Type="SessionExpired">SBL-ODU-01006/*</codes>
        <codes Type="RecordUpdatedPrematurely">SBL-DAT-00523/SBL-EAI-04290</     codes>
        <codes Type="BookAccessDenied"      ErrMsgReplacement="#msg_book_access_denied" PassToBalloon="true">SBL-     EAI-04471/SBL-EAI-04471</codes>
        <codes Type="RecordAccessDenied"      ErrMsgReplacement="#msg_record_access_denied">SBL-DAT-00542/SBL-EAI-     04376</codes>
    </errors>

    1. Locate the following line:

    <object TypeId="::Defaults" Label="#obj_defaults" LabelPlural="#obj_defaults" IsAssociation="no" IsTopLevel="yes" AllowTypedefCaching="false">

    1. Replace this line with the following:

    <object TypeId="::Defaults" Label="#obj_defaults" LabelPlural="#obj_defaults" IsAssociation="no" IsTopLevel="yes">

    1. Insert the following lines inside the <common_settings> element:

    <access_modes_config>
        <books Enable="true" >
          <request_scopes>
            <scope Name="General" />
            <scope Name="QBID" />
          </request_scopes>

          <t2b_bnd_config StorageTname="Book.Type.Association"        TnameFldname="TypeName" BookIdFldName="BookId"        SubbooksFldname="IncludeSubBooks" />
          <default_books_picklist Name="TypeDefaultBookPL" />
        </books>
    </access_modes_config>

    1. Locate the following line:

    <field Name="Id" Label="Id" IsPrimaryKey="yes" IsReadonly="yes" IsRequired="no" DataType="DTYPE_ID" IsNullable="no" />

    1. Replace this line with the following:

    <field Name="RawId" Label="RawId" IsPrimaryKey="yes" IsReadonly="yes" DataType="DTYPE_ID" IsNullable="no" IsHidden="true" IsFake="true" />

    1. Add the following fields to the <object TypeId="::Defaults"> element:

    <field Name="FullName" Label="FullName" DataType="DTYPE_TEXT" />
    <field Name="PrimaryPositionId" Label="PrimaryPositionId" DataType="DTYPE_TEXT" />
    <field Name="Book" Label="Book" DataType="DTYPE_TEXT" IsHidden="true" IsFake="true" PicklistTypeId="BookPL" />
    <field Name="DefaultBookId" Label="DefaultBookId" DataType="DTYPE_TEXT" />
    <field Name="DefaultBookName" Label="DefaultBookName" DataType="DTYPE_TEXT" />
    <field Name="TypeDefaultBook" Label="TypeDefaultBook" DataType="DTYPE_TEXT" IsHidden="true" IsFake="true" PicklistTypeId="TypeDefaultBookPL" />
    <field Name="RequiredFields" Label="RequiredFields" DataType="DTYPE_TEXT" IsHidden="true" IsFake="true" PicklistTypeId="FieldsInfoPL" />

    1. For each <object> element which contains the <extra_command_options> element, do the following:
      • Locate the following line:

    <option Name="UseDefaultViewMode" Value="true" Scopes="Dedup" />

    • Replace this line with the following:

    <option Name="UseDefaultViewMode" Value="true" Scopes="Dedup;ONLKP;QBID" />

    • Insert the following lines inside the <object> element:

    <viewmodes>
        <viewmode Name="None" Scopes="Dedup;ONLKP;QBID" />
    </viewmodes>

    1. For each <object> element of a book-enabled object type, do the following:
      • Insert the following lines inside the <object> element, where TypeOrderNumber is the order number of the Type in the connector_configuretion.xml file:

    <access_mode_config BooksSupported="true" TypeOrderNumber="5" >
        <involved_fields>
          <field Name="Owner" />
          <field Name="BookName" />
        </involved_fields>
        <scopes>
          <scope Id="Dedup" BookId="" />
          <scope Id="ONLKP" BookId="" />
          <scope Id="QBID" BookId="" />
        </scopes>
    </access_mode_config>

    • Add the following fields to the <object> element of the Contact, Account, Opportunity, and Lead record types:

    <field Name="BookId" Label="BookId" DataType="DTYPE_TEXT" CRMName="Primary Position Id" />
    <field Name="BookName" Label="BookName" DataType="DTYPE_TEXT" CRMName="Primary Position Name" >
        <suppress_on Upstream="true" />
    </field>

    • Add the following fields to the <object> element of the Activity record type:

    <field Name="BookId" Label="BookId" DataType="DTYPE_TEXT" CRMName="Position Id" />
    <field Name="BookName" Label="BookName" DataType="DTYPE_TEXT" CRMName="Position Name" >
        <suppress_on Upstream="true" />
    </field>

    • Replace the <field Name='Owner' ... /> element of the Contact, Account, Opportunity, and Lead record types with the following field element:

    <field Name='Owner' Label='Owner' DataType='DTYPE_TEXT' IsFilterable='no' IsHidden="yes" CRMName="Owner Alias" >
        <suppress_on Upstream="true" />
    </field>

    • Add the following field element to the Activity object:

    <field Name="Owner" Label="Owner" DataType="DTYPE_ID" IsFake="true" IsFilterable='no' CRMName="Assigned To" IsHidden="yes">
        <suppress_on Upstream="true" />
    </field>

    1. Inside the <root> element, add the lines of XML code listed in XML Code Addition for the od_meta_info.xml File.
  8. In the od_helpers.js file, after the first line of the file, insert the JavaScript code listed in JavaScript Code Addition for the od_helpers.js File.
  9. Update the application_script.js file as follows:
    1. Insert the following code line after the var cp_pages = [ line:

    {native: false, layout: "cp_record_set_page", available: true, image: "type_image:Book:32", caption: application.session.res_string("lbl_record_set_caption")},

    1. Locate the existing fra_handler(fra) function:

    function fra_handler(fra)
    {
          var current_form = null;

          var on_closed = function()

    {
              current_form = null;
              fra.exit_current_step(false);
          }
          function on_fra_step(id)
          {

              if (id == "advanced")
              {
                var xml = ui.get_dialog_xml("PropSheetHost");
                xml = helpers.replace_all("$prop_sheet_layout",             "options_advanced_page", xml);
                 current_form = ui.create_dialog_from_xml(0, xml);
                 current_form.on_closed.connect(on_closed)
                 current_form.visible = true;
              }
          }

          fra.on_step.connect(on_fra_step);
          fra.add_builtin_step("welcome");
          fra.add_builtin_step("sync_filters");
          fra.add_builtin_step("sync_schedule");
          fra.add_step("advanced", session.res_string("sa-advanced_settings-      caption"), session.res_string("sa-advanced_settings-description"), "sa-      advanced_settings-picture", true);
          fra.add_builtin_step("convert_items");
          fra.add_builtin_step("first_sync");
        }

    1. Replace the existing fra_handler() function with the following:

    function fra_handler(fra)
    {
      var current_form = null;

      var on_closed = function()
      {
        current_form = null;
        fra.exit_current_step(false);
      }

      function on_fra_step(id)
      {
        switch (id) {
          case "advanced": step_advanced(); break;
          case "record_set": step_record_set(); break;
          case "server_configuration": step_server_configuration(); break;
        }

        function step_advanced() {
          var xml = ui.get_dialog_xml("PropSheetHost");
          xml = helpers.replace_all("$prop_sheet_layout", "options_advanced_page",       xml);
          current_form = ui.create_dialog_from_xml(0, xml);
          current_form.on_closed.connect(on_closed);
          current_form.visible = true;
        }

        function step_record_set() {
          var cp_ctx =
          {
            "open_context": "cp_record_set_page",
            "single_page": true,
            "on_closed_fn": on_closed
          };
          sync_ui_session..show_cp(cp_ctx);
        }

        function step_server_configuration() {
          current_form = ui.create_dialog(0, "FRA Server Configuration Dlg");
          current_form.on_closed.connect(on_closed);
          current_form.visible = true;
        }
      }

      fra.on_step.connect(on_fra_step);
      fra.add_builtin_step("welcome");
      fra.add_step("server_configuration", application.session.res_string("sa-  server_configuration-caption"), application.session.res_string("sa-  server_configuration-description"), "sa-server_configuration-picture", true);
      fra.add_step("record_set", application.session.res_string("sa-record_set-  caption"), application.session.res_string("sa-record_set-description"), "sa-  record_set-picture", true);
      fra.add_builtin_step("sync_filters");
      fra.add_builtin_step("sync_schedule");
      fra.add_step("advanced", application.session.res_string("sa-  advanced_settings-caption"), application.session.res_string("sa-  advanced_settings-description"), "sa-advanced_settings-picture", true);
      fra.add_builtin_step("convert_items");
      fra.add_builtin_step("first_sync");
    }

    1. Add the following code to the end of the file:

    var ownership_logger = application.create_state_set();
    var types_to_log = ["Activity", "Contact", "Opportunity", "Lead", "Account"];
    ownership_logger.add("synchronizing", false);
    ownership_logger.on_changed.connect(function(synchronizing_finished){
      if(synchronizing_finished)
       {
            var sync_is_finished = ownership_logger.is_actual;
            helpers.for_each2(types_to_log, function(type_id){

            application.logger.info(helpers.format(session.res_string("msg_owners          hip_log"),[type_id, od_helpers.get_ownership_mode(g_ctx, type_id)]));
            });
            // Store Users' Custom Book Ids for autoresolver
            var book_ids = [];
            helpers.for_each(session.find_items("User", session.empty_criteria),         function(item) { book_ids.push(item["PrimaryPositionId"]); });
            g_ctx.application.settings.set("CustomBookIds", book_ids.join(";"));
        }
    });

  10. Update the autoresolver.js file as follows:
    1. Replace the substring left_values with remote_values throughout the entire file.
    2. Replace the substring right_values with local_values throughout the entire file.
    3. Add the following resolve_custom_book() function to the end of the file:

    function resolve_custom_book(field_name, local_set, remote_set, resolution)
    {
      var lid = local_set.get_field(field_name);
      var rid = remote_set.get_field(field_name);
      var custom_book_ids = application.settings.get("CustomBookIds");
      if (lid == "" && custom_book_ids != null && custom_book_ids.search(rid) > -1)
        return resolution.set_field(field_name, rid), true;
      return false;
    }

    1. Locate the following line:

    resolve_to_winner("OwnerId", remote_set, local_set, resolution); //OLOD-284

    1. Add the following after the line:

    resolve_custom_book("BookId", local_set, remote_set, resolution);

    1. Locate the following line:

    resolve_to_local_nonempty("PrimaryShipToCounty", local_set, remote_set, resolution);

    1. Add the following after the line:

    resolve_custom_book("BookId", local_set, remote_set, resolution);

    1. Locate the following line:

    resolve_to_local_nonempty("AlternateCounty", local_set, remote_set, resolution)

    1. Add the following after the line:

    resolve_custom_book("BookId", local_set, remote_set, resolution);

    1. Locate the following line:

    resolve_zero_to_null("Revenue", local_set, remote_set, resolution)

    1. Add the following after the line:

    resolve_custom_book("BookId", local_set, remote_set, resolution);

    1. Locate the following line:

    resolve_to_local_nonempty("County", local_set, remote_set, resolution);

    1. Add the following after the line:

    resolve_custom_book("BookId", local_set, remote_set, resolution);

  11. Update the business_logic.js file as follows:
    1. Locate the following line:

    if(!(ctx.form.item.snapshot.AccountId != null && account_id == null))

    1. Replace the line with the following:

    if(!(action_ctx.item_ex.get_property("AccountId") != null && account_id == null))

    1. Locate the following function:

    function deny_primary_delete(mvg_link)
    { scheme.triggers.add_simple_trigger(data_model.deny_primary_delete_trigger, mvg_link.type, mvg_link.link_to, mvg_link.tag, "removing");
    }

    1. Replace the function with the following functions:

    function deny_primary_delete(mvg_link)
    {
        scheme.triggers.add_simple_trigger(deny_primary_delete_trigger_wrapper,     mvg_link.type, mvg_link.link_to, mvg_link.tag, "removing");
        scheme.triggers.add_simple_trigger(deny_primary_set_non_current_user,     mvg_link.type, mvg_link.link_to, null, "creating");

        function deny_primary_set_non_current_user(ctx, action_ctx)
        {
          var mode = od_helpers.get_ownership_mode(ctx, action_ctx.type);
          if(mode == "mixed" || mode == "owner")
          {
            var curr_user_id = helpers.get_current_user_id(ctx.session),
            with_user_id = action_ctx.with_id;
            var is_manual_operation = action_ctx.params == null ||         action_ctx.params.is_manual_operation;
            // prevent manual set primary to non-current user
            if (is_manual_operation && with_user_id != null && action_ctx.tag ==         "direct" && !helpers.ids_equal(ctx.session, curr_user_id,          with_user_id )) action_ctx.notification_params.cancel = true;
              // set current user primary, allowed for manual operation only
              if (is_manual_operation && with_user_id != null && action_ctx.tag           == "mvg" && helpers.ids_equal(ctx.session, curr_user_id,          with_user_id ))
             {
                var linked_direct = ctx.linker.linked({ "item_ex":             action_ctx.item_ex, "tag": "direct", "link_to":             action_ctx.link_to });
                ctx.linker.link({ "item_ex": action_ctx.item_ex, "link_to":             action_ctx.link_to, "tag": "direct", "with_id": with_user_id });
                var linked = ctx.linker.linked({ "item_ex": action_ctx.item_ex,             "tag": "mvg", "link_to": action_ctx.link_to });
                if(linked_direct.value == null &&             helpers.contains_object_id(ctx.session, linked.values,             with_user_id)) // owner was empty but association with current user             alrady exists
              action_ctx.notification_params.cancel = true; // prevent "already           present" msg
            }
          }
        }

        function deny_primary_delete_trigger_wrapper(ctx, action_ctx)
        {
            var mode = od_helpers.get_ownership_mode(ctx, action_ctx.type);
            if(mode == "owner")
              data_model.deny_primary_delete_trigger(ctx, action_ctx);
        }
    }

    1. Locate the following function:

    function prefill_owner(ctx)
    {
        var current_user_id = helpers.get_current_user_id(ctx.session);
        if (current_user_id != null)
        {
          return ([
              { "with_id": current_user_id, "tag": "mvg" },
              { "with_id": current_user_id, "tag": "direct" }
          ]);
        }
        else return [];
    }

    1. Replace the function with the following code:

    function prefill_owner(ctx, type_id)
    {
        type_id = type_id || ctx.item_ex.get_type();
        var current_user_id = helpers.get_current_user_id(ctx.session);
        if (current_user_id != null)
        {
          var ownership_mode = od_helpers.get_ownership_mode(ctx, type_id);
          var fill_owner = ownership_mode != "book" && !(ownership_mode == "mixed"       && prefill_book(ctx, type_id)); // prefill owner in mixed mode if no book       was prefilled

          var links = [
            { "with_id": current_user_id, "tag": "mvg" }, // add to team
            { "with_id": current_user_id, "tag": "direct" } // fill owner
          ];
          if(!fill_owner)
            links = [];
          return links;
        }
        else return [];
    }

    function prefill_activity_owner(ctx)
    {
        return prefill_owner(ctx, "Activity");
    }

    function prefill_book(ctx, type_id)
    {
        type_id = type_id || ctx.item_ex.get_type();
        var ownership_mode = od_helpers.get_ownership_mode(ctx, type_id);
        switch (ownership_mode)
        {
          case "book":
            var user_selected_book = od_helpers.get_ol_storage_rs_book(ctx,         type_id);
            var book_id = user_selected_book != null ? user_selected_book.BookId         : "";
            if (!book_id) {
              var default_book = ctx.session.find_item("BookDefaults",           ctx.session.create_expression("Value", "eq", type_id));
              book_id = default_book != null ? default_book.BookId : "";
              }
            if(!book_id)
            {
                var defaults = helpers.get_defaults(ctx.session),
                  user_default_book_name = defaults != null ?               defaults.DefaultBookName : "",
                  user_default_book = ctx.session.find_item("Book",               ctx.session.create_expression("Label", "eq",               user_default_book_name));
                  book_id = user_default_book != null ? user_default_book.Value :               book_id;
            }
            if(od_helpers.book_can_contain_data(ctx, book_id))
              return book_id;
        break;
        case "mixed":
            var user_selected_book = od_helpers.get_ol_storage_rs_book(ctx,         type_id);
            var book_id = user_selected_book != null ? user_selected_book.BookId         : "";
            if (book_id && od_helpers.book_can_contain_data(ctx, book_id))
          return book_id;
        break;
        default:
          return "";
        break;
        }
    }

    function prefill_activity_book(ctx)
    {
        return prefill_book(ctx, "Activity");
    }
    function prefill_lead_owner_od(ctx)
    {
        var current_user_id = null;
        if(ctx.security_descriptor.ownership_mode() != "book")
        {
          current_user_id = helpers.get_current_user_id(ctx.session);
        }
        return current_user_id;}
    }

    1. Locate the following line:

    scheme.objects.get_object("Activity")["initial_links_fn"] = prefill_owner;
    scheme.objects.get_object("Activity").get_field("OwnerId")["initial_value_fn"] = prefill_owner_od;

    1. Replace the line with the following:

    scheme.objects.get_object("Activity")["initial_links_fn"] = prefill_activity_owner;
    scheme.objects.get_object("Activity").get_field("BookId")["initial_value_fn"] = prefill_activity_book;

    1. Locate the following line:

    scheme.objects.get_object("Contact").get_field("OwnerId")["initial_value_fn"] = prefill_owner_od;

    1. Replace the line with the following:

    scheme.objects.get_object("Contact").get_field("BookId")["initial_value_fn"] = prefill_book;

    1. Locate the following line:

    scheme.objects.get_object("Account").get_field("OwnerId")["initial_value_fn"] = prefill_owner_od;

    1. Reeplace the line with the following:

    scheme.objects.get_object("Account").get_field("BookId")["initial_value_fn"] = prefill_book;

    1. Locate the following line:

    scheme.objects.get_object("Lead").get_field("OwnerId")["initial_value_fn"] = prefill_owner_od;

    1. Replace the line with the following:

    scheme.objects.get_object("Lead").get_field("OwnerId")["initial_value_fn"] = prefill_lead_owner_od;
    scheme.objects.get_object("Lead").get_field("BookId")["initial_value_fn"] = prefill_book;

    1. Locate the following line:

    scheme.objects.get_object("Opportunity").get_field("OwnerId")["initial_value_fn"] = prefill_owner_od;

    1. Replace the line with the following:

    scheme.objects.get_object("Opportunity").get_field("BookId")["initial_value_fn"] = prefill_book;

    1. Locate the following line:

    add_association_description(owner_result.owner, proxy, null, "direct");

    1. Replace the line with the following:

    if(activity_ownership_mode() != "book" && !proxy.item_ex().get_property("BookId")) add_association_description(owner_result.owner, proxy, null, "direct");

    1. Locate the following line:

    var const_ctx = { "item_ex": proxy.item_ex(), "submited": submited != false };

    1. Replace the line with the following:

    var const_ctx = { "item_ex": proxy.item_ex(), "submited": submited != false, "params": {"is_manual_operation": false} };

    1. Locate the following line:

    if(helpers.contains_object_id(ctx.session, proxy_team.values, current_user))

    1. Replace the line with the following:

    if(activity_ownership_mode() != "owner" || helpers.contains_object_id(ctx.session, proxy_team.values, current_user))

    1. Locate the following lines:

    // var owner_filter = ctx.session.create_expression("Primary Owner Id", "eq", owner);
      var owner_filter = ctx.session.create_expression("OwnerId", "eq", owner);

    1. Replace the lines with the following:

      var owner_filter = ctx.session.create_expression("OwnerId", "eq", owner),
       ownership_mode = activity_ownership_mode();

    1. Locate the following line:

    conversation_id_filter.add(owner_filter);

    1. Replace the line with the following:

    if(ownership_mode == "owner")
      conversation_id_filter.add(owner_filter);

    1. Locate the following line:

    filter.add(owner_filter);

    1. Replace the line with the following:

    if(ownership_mode == "owner")
      filter.add(owner_filter);

    1. Locate the following line:

    if (helpers.ids_equal(ctx.session, owner.value, get_owner_for_ol_item(ol).owner)

    1. Replace the line with the following:

    if ((activity_ownership_mode() != "owner" || helpers.ids_equal(ctx.session, owner.value, get_owner_for_ol_item(ol).owner))

    1. Locate the following line:

    if (is_current_user(primary_employee.value) || object_is_not_sync)

    1. Replace the line with the following:

    if (activity_ownership_mode() == "owner" && is_current_user(primary_employee.value) || object_is_not_sync)

    1. Insert the following function inside the activity_processor(ctx) function:

    function activity_ownership_mode()
    {
      return od_helpers.get_ownership_mode(ctx, "Activity")
    }

  12. Update the forms.js file as follows:
    1. Insert the register_book_control(ctx, owner_ctrl) function at the end of the file. For a listing of the code, see JavaScript Code Addition for the forms.js File.
    2. Locate the following line inside the activity_subform(ctx) function:

    activity_form_base.apply(this, arguments);

    1. Add the following code after the line:

    register_book_control(ctx, "ActionToEmployee");

    1. Make the following changes inside the activity_form(ctx) function:
      • Remove the following lines:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();

    • Locate the following line:

    activity_form_base.apply(this, arguments);

    • Add the following code after the line:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();
    register_book_control(ctx, "ActionToEmployee");

    • Remove the following line:

    validator.validate_empty_field("OwnerId", "ActionToEmployee", "msg_activity_owner_validation", false);

    1. Locate the following line inside the od_contact_form(ctx) function:

    ctx.form_links_manager.init_new();

    1. Add the following after the line:

    register_book_control(ctx, "TeamToContact");

    1. Locate the following line inside the od_lead_form(ctx) function:

    ctx.form_links_manager.init_new();

    1. Add the following after the line:

    register_book_control(ctx);

    1. Make the following changes inside the od_opportunity_form(ctx) function:
      • Remove the following lines:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();

    • Remove the following lines:

    Status_control_changed();
    if (ctx.item_ex.get_id() == null) {
      Type_control_changed();
    } else {
      update_picklistSalesStage_control(form.item.snapshot.SalesProcessId);
    }

    • Locate the following line:

    ctx.form.on_saved.connect(form_saved);

    • Add the following code after the line:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();

    register_book_control(ctx, "TeamToOpportunity");

    Status_control_changed();
    if (ctx.item_ex.get_id() == null) {
      Type_control_changed();
    } else {
      update_picklistSalesStage_control(form.item.snapshot.SalesProcessId);

    }

    1. Make the following changes inside the od_opportunity_form(ctx) function:
      • Remove the following lines:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();

    • Locate the following line:

    ctx.form.on_saved.connect(form_saved);

    • Add the following code after the line:

    // enabling autoprefilling this item;
    ctx.form_links_manager.init_new();

    register_book_control(ctx, "TeamToAccount");

Oracle CRM On Demand Desktop Administration Guide, Version 5.2 Copyright © 2017, Oracle and/or its affiliates. All rights reserved. Legal Notices.