상단

    SugarCRM Customize 방법을 정리 합니다.

     

    Sugar 분석


    Home

    Global Search 필드 추가

    • Global Search (Unified Search) 필드 추가 사례

      • 모듈명 : test1_vacation

      • 테이블명 : test1_vacation

      • 검색에 포함할 필드명 : subject

       
    • vi custom/Extension/modules/test1_vacation/Ext/Vardefs/customGlobalSearchFields.php

     
     $dictionary['test1_vacation']['unified_search']('unified_search'.md) = true; 
     $dictionary['test1_vacation']['unified_search_default_enabled']('unified_search_default_enabled'.md) = true;
     $dictionary[‘test1_vacation']['fields']['subject']['unified_search']('unified_search'.md) = true; 
     
    • vi custom/modules/test1_vacation/metadata/SearchFields.php

     
        'default');
        ?>
     
    • "관리자 모드 -> 검색" 메뉴에서 test1_vacation을 "사용가능한 모듈"에 추가

     
     

    ElasticSearch

    • ElasticSearch

    • vi include/SugarSearchEngine/SugarSearchEngineFactory.php

      • 검색 엔진 ($sugar_config->full_text_engine)

        • include/SugarSearchEngine/SugarSearchEngine.php

        • include/SugarSearchEngine/Elastic/SugarSearchEngineElastic.php

       
    • vi include/SugarSearchEngine/Elastic/SugarSearchEngineElastic.php

      • index (Database) : $_indexName($sugar_config->unique_key)으로 지정

      • type (Table) : $bean->module_dir (default. SugarBean) 로 지정

     
     

    레코드의 요약 정보 표시 변경

    • 표시 위치

      • Global Search 결과

      • Recently Viewed, Favorites

     
     
     class Ticket extends Issue
     {
         public function get_summary_text() {
             return "Ticket #{$this->ticket_number} - {$this->name}"
         }
     }
     

    Module Menu 추가

    • vi custom/Extension/module/Opportunities/Ext/Menus/menu.customDivide.php

     
     global $mod_strings, $app_strings, $sugar_config;
     $module_menu[](.md)=  Array(
         "index.php?module=Import&action=Step1&import_module=Opportunities&return_module=Opportunities&return_action=index", 
         $mod_strings['LNK_DIVIDE']('LNK_DIVIDE'.md),
         "Opportunies",
         "Opportunies"
     );
     

    Request Type

    • 목록 화면

     
        -   Request - Module : Cases, Action : favorites
        -   Request - Module : Cases, Action : modulelistmenu
        -   Request - Module : Cases, Action : index
     
    • 편집 화면 (등록)

     
        -   Request - Module : Cases, Action : EditView
            Request - array (   'module' => 'Cases',   'action' => 'EditView',   'return_module' => 'Cases',   'return_action' => 'DetailView', )
        -   Request - Module : ExpressionEngine, Action : getRelatedValues
            Request - array (   'module' => 'ExpressionEngine',   'action' => 'getRelatedValues',   'record_id' => '',   'tmodule' => 'Cases',   'fields' => '[{"link":"contacts","type":"related","relate":"email_c"}]({"link":"contacts","type":"related","relate":"email_c"}.md)',   'to_pdf' => '1', )
     
    • 편집 화면 (수정)

     
        -   Request - Module : Cases, Action : EditView, Record : 5ffc4f56-1f11-9147-3f69-515e69ad90a6
            Request - array (   
                'module' => 'Cases',   'action' => 'EditView',   'record' => '5ffc4f56-1f11-9147-3f69-515e69ad90a6',   
                'return_module' => 'Cases',   'return_action' => 'DetailView',   'return_id' => '5ffc4f56-1f11-9147-3f69-515e69ad90a6',   
                'module_tab' => '',   'isDuplicate' => 'false',   'offset' => '1',   'sugar_body_only' => '', )
        -   Request - Module : ExpressionEngine, Action : getRelatedValues
     
    • 관련 목록에서 빠른 편집 화면 (등록) : view type - classic

      • custom/modules/Home/SubpanelEdits.php 파일 실행

      • custom/modules/Cases/metadata/quickcreatedefs.php

     
        -   Request - Module : Home, Action : SubpanelCreates, Record :
            Request - array (   
                'module' => 'Home', 'action' => 'SubpanelCreates', 'record' => '', 'target_module' => 'Cases',   'target_action' => 'QuickCreate', 
                'parent_type' => 'Accounts', 'parent_id' => 'sfdc_00120000005hOWpAAM', 'parent_name' => '다우기술',   
                'return_module' => 'Accounts',   'return_action' => 'DetailView',   'return_id' => 'sfdc_00120000005hOWpAAM',   
                'return_relationship' => 'account_cases',   'return_name' => '다우기술',
                'account_id' => 'sfdc_00120000005hOWpAAM',   'account_name' => '다우기술',   'account_cases_name' => '다우기술',   
                'to_pdf' => 'true',   'tpl' => 'QuickCreate.tpl',     'account_cases_신규자료추가하기_button' => '신규자료 추가하기', )
     
    • 관련 목록에서 빠른 편집 화면 (수정) : view type - classic

      • custom/modules/Home/SubpanelEdits.php 파일 실행

      • custom/modules/Cases/metadata/quickcreatedefs.php

     
        -   Request - Module : Home, Action : SubpanelEdits, Record : cc180f6e-36e1-ee71-fb4a-515d0ad0af20
            Request - array (   
                'module' => 'Home',   'action' => 'SubpanelEdits',   'record' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20', 'target_module' => 'Cases', 'target_action' => 'QuickCreate',
                'parent_type' => 'Accounts',   'parent_id' => 'sfdc_00120000005hOWpAAM', 'parent_name' => '다우기술',
                'return_module' => 'Accounts',   'return_action' => 'DetailView',   'return_id' => 'sfdc_00120000005hOWpAAM',   
                'return_relationship' => 'account_cases',        'return_name' => '다우기술',
                'account_id' => 'sfdc_00120000005hOWpAAM',   'account_name' => '다우기술',   'account_cases_name' => '다우기술',   
                'to_pdf' => 'true',   'tpl' => 'QuickCreate.tpl',            'Cases_subpanel_cancel_button' => '취소', )
        -   Request - Module : ExpressionEngine, Action : getRelatedValues
            Request - array (   'module' => 'ExpressionEngine',   'action' => 'getRelatedValues',   'record_id' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20',   'tmodule' => 'Cases',   'fields' => '[{"link":"contacts","type":"related","relate":"email_c"}]({"link":"contacts","type":"related","relate":"email_c"}.md)',   'to_pdf' => '1', )
     
    • 관련 목록에서 빠른 편집 전체 화면 (등록)

     
        -   Request - Module : Cases, Action : EditView, Record :
            Request - array (   
                'module' => 'Cases',   'action' => 'EditView',    'record' => '',   
                'return_module' => 'Accounts', 'return_action' => 'DetailView',   'return_id' => 'sfdc_00120000005hOWpAAM',
                'relate_to' => 'account_cases',   'relate_id' => 'sfdc_00120000005hOWpAAM',
                'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술',   
                'full_form' => 'full_form',
                'assigned_user_id' => 'sfdc_00520000000shVfAAI', 'assigned_user_name' => '김계현 수석',   
                            'isDuplicate' => 'false',         'module_tab' => '',   'contact_role' => '',      'offset' => '1',   
                'user_id1_c' => '',   생략)
     
    • 관련 목록에서 빠른 편집 전체 화면 (수정)

     
        -   Request - Module : Cases, Action : EditView, Record : cc180f6e-36e1-ee71-fb4a-515d0ad0af20
            Request - array (   
                'module' => 'Cases',   'action' => 'EditView', 'record' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20',   
                'return_module' => 'Accounts',   'return_action' => 'DetailView',   'return_id' => 'sfdc_00120000005hOWpAAM',
                'relate_to' => 'account_cases',   'relate_id' => 'sfdc_00120000005hOWpAAM', 
                'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술', 
                'full_form' => 'full_form',
                'assigned_user_id' => 'sfdc_00520000000slI0AAI', 'assigned_user_name' => '송솔잎 차장',   
                'isDuplicate' => 'false',         'module_tab' => '',   'offset' => '1',
                'contact_role' => '',         생략)
     
    • 보고서에서 빠른 편집 화면 (수정)

     
     - Request - Module : Accounts, Action : Quickedit, Record : sfdc_00120000005hOWpAAM
       Request - array (   'to_pdf' => '1',   'module' => 'Accounts',   'action' => 'Quickedit',   'record' => 'sfdc_00120000005hOWpAAM', )
      
    • 데이터 저장 (등록)

     
        -   Request - Module : Accounts, Action : Save, Record :
            Request - array (   
                'module' => 'Accounts',   'action' => 'Save', 'record' => '',      
                'return_module' => 'Accounts',   'return_action' => 'index',   'return_id' => '',  
                'relate_to' => 'Accounts',   'relate_id' => '',             
                'module_tab' => '',   'isDuplicate' => 'false',   
                'contact_role' => '',     생략 )
     
    • 데이터 저장 (수정)

     
        -   Request - Module : Accounts, Action : Save, Record : 705aabbb-22d4-fd77-c66e-516226ae32f4
            Request - array (   
                'module' => 'Accounts',   'action' => 'Save', 'record' => '705aabbb-22d4-fd77-c66e-516226ae32f4',   
                'return_module' => 'Accounts',   'return_action' => 'DetailView',   'return_id' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
                'relate_to' => 'Accounts',   'relate_id' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
                'parent_name' => '',   'parent_id' => '',
                'isDuplicate' => 'false',         'module_tab' => '',   'contact_role' => '',      'offset' => '1',   
                'name' => 'zzaaa',   생략 )
     
    • 삭제 화면

     
        -   Request - Module : Accounts, Action : Delete, Record : 705aabbb-22d4-fd77-c66e-516226ae32f4
            Request - array (   
                'module' => 'Accounts',   'action' => 'Delete', 'record' => '705aabbb-22d4-fd77-c66e-516226ae32f4',   
                'return_module' => 'Accounts', 'return_action' => 'ListView',     'return_id' => '',   
                'module_tab' => '',   'isDuplicate' => 'false',   'offset' => '1',      'sugar_body_only' => '', )
     
    • 조회 화면

     
        -   Request - Module : Accounts, Action : DetailView, Record : sfdc_00120000005hOWpAAM
            Request - array (   'module' => 'Accounts',   'action' => 'DetailView',   'record' => 'sfdc_00120000005hOWpAAM',  )
     
    • 목록 화면에서 고급 검색 화면만 불러 오기

     
     Request - Module : Cases, Action : index
     Request - array (   'module' => 'Cases',   'action' => 'index',   'search_form_only' => 'true',   'to_pdf' => 'true',   'search_form_view' => 'advanced_search', )
     

    DetailView

     

    버튼 추가 1

    • vi custom/modules/Opportunities/views/view.detail.php

     
     class CustomOpportunitiesViewDetail extends OpportunitiesViewDetail {
     	const JS_COMMON = 'custom/include/javascript/viewdefs.js';
     	const JS_MODULE = 'custom/modules/Opportunities/Opportunities.js';
      	
      	public function preDisplay() {
     		parent::preDisplay();
     		
     		//---	영업기회 분할 버튼 추가
     		$tmpStr = '';
     		$tmpStr = $tmpStr.'{if $bean->aclAccess("edit")}';
     		$tmpStr = $tmpStr.'';
     		$tmpStr = $tmpStr.'{/if}';
     		$this->dv->defs['templateMeta']['form']['buttons'][](.md) = array ('customCode' => $tmpStr);
     
     		//---	계약 생성 버튼 추가
     		$tmpStr = '';
     		$tmpStr = $tmpStr.'{if $bean->aclAccess("edit")}';
     		$tmpStr = $tmpStr.'';
     		$tmpStr = $tmpStr.'{/if}';
     		$this->dv->defs['templateMeta']['form']['buttons'][](.md) = array ('customCode' => $tmpStr);
     		
     		$this->dv->defs['templateMeta']['includes'][](.md) = array ('file' => $this::JS_COMMON);
     		$this->dv->defs['templateMeta']['includes'][](.md) = array ('file' => $this::JS_MODULE); 
     	}
     }
     
    • vi custom/include/javascript/viewdefs.js

     
     function funcClickButton(theForm, argModule, argAction, argRecord, argReturnModule, argReturnAction, argReturnId) {
     	if (argModule != null) {
     		theForm.module.value = argModule;
     	}
     	theForm.action.value = argAction;
     	theForm.record.value = argRecord;
     	theForm.return_module.value = argReturnModule;
     	theForm.return_action.value = argReturnAction; 
     	theForm.return_id.value = argReturnId;
     }
     

    버튼 추가 2

    • vi custom/modules/Opportunities/metadata/detailviewdefs.php 파일 하단에 다음을 추가 합니다.

     
     $viewdefs['Opportunities']['DetailView']['templateMeta']['form'][buttons][](.md) = array (
         'customCode' => '
             {if $bean->aclAccess("edit")} 
                 
              {/if}'
     );
     
    • vi Extension/modules/Opportunities/Ext/Language/ko_KR.customDivide.php

     
     $mod_strings['LNK_DIVIDE']('LNK_DIVIDE'.md) = 'MA/PJT 분할';
     

    버튼의 위치 조정

     $new_array = array();
     $MyNewCustomCodeButton = "";
      
     $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][0](0.md); // EDIT
     $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][1](1.md); // DUPLICATE
     $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][2](2.md); // DELETE
     $new_array[](.md) = array('customCode' => $MyNewCustomCodeButton);
     $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][3](3.md); // quote2opp
     $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][4](4.md); // quote2pdf
     
     $this->dv->defs['templateMeta']['form']['buttons']('buttons'.md) = $new_array;
      
     parent::display();
     

    Field

     
     

    Database에 없는 필드 추가

    • vi /custom/Extension/modules/$Module/Ext/Vardefs/custom_fileds.php

     
     $dictionary[$Module]['fields'][$field]($field.md)= array(
            'name' => '$field',
            'vname' => 'LBL_$FIELD',
            'type' => 'varchar',
            'len' => '255',
            'source' => 'non-db',                                   //--- Database에서 관리되지 않는 필드임을 명시함
     );
     
    • vi /custom/Extension/modules/$Module/Ext/LogicHooks/logichooks.custom.php

     
     if (!isset($hook_array['process_record']('process_record'.md))) {
     	$hook_array['process_record']('process_record'.md) = Array();
     }
     $hook_array['process_record'][](.md) = Array(
     		count($hook_array['process_record']('process_record'.md)) + 1, 'Custom${Module}LogicHooks', 
     		'custom/modules/$Module/Custom${Module}LogicHooks.php',
     		'Custom${Module}LogicHooks', 'ProcessRecord');
     
    • vi /custom/modules/$Module/Custom${Module}LogicHooks.php

      • ProcessRecord() 함수에서 $field의 값을 계산하여 저장함

      • $field의 값으로 html tag를 사용하여 이미지 등을 표시할 수 있음

       
    • vi /custom/modules/$Module/Dashlets//.data.php

     
     $dashletData['MyCasesDashletWR']['columns']('columns'.md) = array(
         '$field' => array(
             'width' => '2',
             'label' =>'',
             'default' => true,
             'sortable' => false,
             ),
     );
     

    Parent 선택 목록에 항목 추가

    • vi custom/Extension/application/Ext/Language/ko_KR.custom.php

     
     $app_list_strings['parent_type_display']['da03_Voc']('da03_Voc'.md) = 'VOC';
     $app_list_strings['record_type_display_notes']['da18_ProjHistory']('da18_ProjHistory'.md) = '프로젝트 작업내역';
     

    선택목록 값 변경

    • vi custom/include/language/ko_KR.lang.php

     
     $GLOBALS['app_list_strings']['sba__snbServiceContract__c_sba__Owner_Expiration_Notice__c_list']('sba__snbServiceContract__c_sba__Owner_Expiration_Notice__c_list'.md)=array (
      '' => '',
      '15 Days' => '15 Days',
      '30 Days' => '30일 전',
      '45 Days' => '45 Days',
      '60 Days' => '60일 전',
      '90 Days' => '90일 전',
      '120 Days' => '120 Days',
     );
     

    선택목록 값 파싱

    • 선택목록값 파싱 : $aField = unencodeMultienum($fieldValue);

    • 선택목록값 생성 : encodeMultienumValue($arr);

     
     

    선택목록 키에 특수문자 사용

    • 선택목록 키에 한글 또는 공백 등을 사용하는 방법

      • vi modules/ModuleBuilder/javascript/SimpleList.js

     
     //--- 78 line을 주석 처리
     // addToValidate('dropdown_form', 'drop_name', 'error', false, SUGAR.language.get("ModuleBuilder", "LBL_JS_VALIDATE_KEY"));
     
     //--- 102 line을 수정
     // liObj.id = escape(drop_name.value);
     liObj.id = drop_name.value;
     

    ReadOnly Field

    • 1안 : 자기 자신의 값을 할당하는 수식 필드로 선언

    • 2안 : vi custom/Extension/modules/$Module/Ext/Vardefs/~.customReadOnly.php

     
     $dictionary['$module']['fields']['$field']['readonly']('readonly'.md) = true;
     

    Filed의 레이블 가져오기

     $displayFieldValue = $GLOBALS['app_list_strings'][$bean->field_defs[$fieldname]['options'][$bean->$fieldname]]($bean->$fieldname].md);
     
     //--- Multi-Select
     $displayFieldValues = unencodeMultienum($bean->$fieldname);
     array_walk($displayFieldValues, function($val) use($bean,$fieldname) { 
         $val = $GLOBALS['app_list_strings'][$bean->field_defs[$fieldname]['options'][$bean->$fieldname]]($bean->$fieldname].md);
     });
     

    의존 관계

    • vi custom/Extension/modules/$Modules/Ext/Vardefs/sugarfield_$field.php

     
     $dictionary['Account']['fields']['fld_industrytype2_sf_c']['visibility_grid']('visibility_grid'.md) = array (
         'trigger' => 'fld_industrytype1_sf_c',
         'values' => array (
             'parent_value' => array (
                  0 => 'chield_value1',
                  2 => 'chield_value2',
              );
         ),
     );
     

    관계(Relate) 필드명 확인

    • query 문

     
     select distinct custom_module
       from fields_meta_data;
         
     select name, type, ext2, ext3 
       from fields_meta_data 
      where custom_module = 'Opportunities' 
        and type = 'relate';
     
    • vi include/SugarFields/Fields/Relate/SugarFieldRelate.php

      • vi [custom/]include/SugarFields/Fields/Relate/ko_KR.DetailView.tpl

     
     

    Expression

    • 수식 편집기

      • Module : ExpressionEngine, Action : editFormula

      • vi jssource/src_files/include/Expressions/javascript/expressions.js

      • vi jssource/src_files/modules/ExpressionEngine/javascript/formulaBuilder.js

      • vi include/Expressions/javascript/expressions.js

      • vi include/Expressions/javascript/sugar_expressions.php

      • vi modules/ExpressionEngine/javascript/formulaBuilder.js

       
    • 롤업 필드 삽입

      • Module : ExpressionEngine, Action : rollupWizard

      • 예) rollupSum($reports_to_link, "sp_master_sf_c")

       
    • 관련 필드 삽입

      • Module : ExpressionEngine, Action : selectRelatedField

      • 예) related($accounts,"field19_sf_c")

       
    • 수식 편집기에서 함수 정의

      • include/Expressions/Expression//Expression.php 파일에서 getOperationName()가 함수의 이름을 반환함

      • include/Expressions/updatecache.php 파일이 cache/Expressions/functionmap.php 파일을 생성

      • 관련 모듈/필드 처리

        • SUGAR.forms.AssignmentHandler.getRelatedField(linkField, 'rollupSum', relField);

        • vi modules/ExpressionEngine/controller.php 파일의 action_getRelatedValues() 함수에서 처리

       
    • 두 날자의 일자 차이를 구하는 함수

     
     abs(subtract(daysUntil($datefieldA),daysUntil($datefieldB)))
     
    • Parameter

      • vi include/Expressions/Expression/Parser/Parser.php : evaluate() 함수가 전달하는 Parameter를 생성

      • vi include/Expressions/Expression/Generic/SugarFieldExpression.php : Sugar 필드의 경우 전달되는 Parameter 객체

     
     

    Custom Expression

    • custom/include/Expressions/Expression/$returnType/~Expression.php 파일 생성

      • cache/Expressions 폴더 삭제

     
     require_once("include/Expressions/Expression/String/StringExpression.php");
     /**
      * 이 Expression에 대한 도움말을 여기에 작성 합니다.
      * 
      * subStr(String s, Number from, Number length)
    * Returns length characters starting at 0-based index from.
    * ex: subStr("Hello", 1, 3) = "ell" */ class SubStrExpression extends StringExpression { //--- PHP로 Expression을 실행하고 그 결과를 반환 합니다. //--- $param = $this->getParameters()->evaluate(); //--- Parameter 1개 //--- $params = $this->getParameters(); //--- Parameter 여러개 //--- $param1 = $params[0](0.md)->evaluate(); //--- $paramCnt = $this->getParamCount(); //--- -1, 0, 1, ... //--- return ~ function evaluate() { } //--- JavaScript Expression을 실행하고 그 결과를 반환하는 코드를 문자열로 반환 합니다. //--- var param = this.getParameters().evaluate(); //--- Parameter 1개 //--- var params = this.getParameters(); //--- Parameter 여러개 //--- var param1 = params[0](0.md).evaluate(); //--- return ~ static function getJSEvaluate() { } //--- Expression의 이름을 반환 합니다. static function getOperationName() { } //--- Parameter의 type또는 type 배열을 반환 합니다. static function getParameterTypes() { } //--- Parameter의 갯수를 반환 합니다. static function getParamCount() { } function toString() { } }
     

    Custom Validation

    • 방안 1 : JavaScript로 오류 처리를 합니다.

      • vi custom/modules/Opportunities/metadata/editviewdefs.php

     
     'includes'=> array( array( 'file'=>'custom/modules/Opportunities/checkOpportunitiesDate.js'), ),
    • JavaScript file

     
     addtovalidate(form name,field name, type, mandatory,your message); to validate your field, I guess you have one validation name should be addtovalidateDateBefore().
     document.EditView.phone_work.onblur
     
    • 방안 2 : 테스트 필요

      • custom/include/MVC/Controller/SugarController.php 파일을 생성 합니다.

      • handle_action() 함수에서 오류가 발생하면 다음 처리를 하지 않고 넘어가도록 수정 합니다.

      • pre_save() 함수에서 validation check를 합니다.

      • 오류가 발생하면 오류메시지 저장후 view를 edit로 변경하고 pre_edit(), action_eidt(), post_edit()를 수행하고 다음으로 넘어가도록 합니다.

       
    • 참고 문헌

     
     

    Custom Mask

     
     

    Sugar Field Control 생성

     require_once('modules/Import/Forms.php');
     $obj= BeanFactory::getBean($Module);
     echo getControl($Module, $field, $obj->getFieldDefinition($field), "");
     

    customCode

    • vi custom/modules/$Module/metadata/detailviewdefs.php

      • 'customCode' => '<span style="color: red">{$fields.interest_c.value}</span>'

     
     array (
         'name' => 'date_modified',
         'label' => 'LBL_DATE_MODIFIED',
         'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}',
     ),
     
    • vi custom/modules/$Module/metadata/editviewdefs.php

     
     array (
         'name' => 'first_name',
         'customCode' => '{html_options name="salutation" id="salutation" options=$fields.salutation.options selected=$fields.salutation.value}'
                      .  ' ',
     ),
     
    • vi custom/modules/$Module/metadata/listviewdefs.php

     
     'PHONE_WORK' => array (
         'width' => '15%',
         'label' => 'LBL_OFFICE_PHONE',
         'default' => true,
         'related_fields' => 
             array (
             0 => 'extended_phone_c',                               //--- 추가로 사용할 필드명, 소문자로
         ),
         'customCode' => '{$PHONE_WORK} | {$EXTENDED_PHONE_C}',     //--- 필드명은 대문자로
      ),
     
    • custom/modules/Opportunities/views/view.detail.php

     
     $this->dv->defs['templateMeta']['form']['buttons']('buttons'.md) = array('EDIT', 'DUPLICATE', 'DELETE',
         array('customCode'=>'
    '), array('customCode'=>'
    ') );
     

    amount_usdollar

    • amount_usdollar에는 환율이 반영된 기본 통화의 금액이 저장 됩니다.

      • 예) amount에 1$가 저장될 경우, 환율 1000원이 반영되어 amount_usdollar에는 1000 이 저장 됩니다.

     
     

    금액 필드 오른쪽 정렬

    • vi [custom/]include/SugarFields/Fields/Currency/ko_KR.DetailView.tpl, EditView.tpl, ListView.tpl, WirelessDetailView.tpl 파일을 수정하여 변경할 수 있습니다.

     
     

    Relate 관계

    Standard Relate 관계 Records

    • 1:1 relate 관계 : Master record 가져오기

    • 1:1 relate 관계 : Slave record 가져오기

    • 1:n relate 관계 : Master record 가져오기

    • 1:n relate 관계 : Slave records 가져오기

    • n:m relate 관계 : Master records 가져오기

      • $relationshipName 확인 방법

        • 방안 1 : rollupSum($relationshipName, $field) 함수에서 첫번째 인수값

        • 방안 2 : vi modules/$Module/vardefs.php 파일에서 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름을 relationship으로 가지는 것의 name

          • type이 link이고 relationship이 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름과 같은 필드의 name

     
     'quotes' => array (
         'name' => 'quotes',
         'type' => 'link',
         'relationship' => 'quotes_opportunities',
         'source'=>'non-db',
         'vname'=>'LBL_QUOTES',
     ),
    - 방안 3 : DB Query 사용, lhs_module 필드값의 소문자 사용 (추가 확인 필요)  
    • load_relationship 함수에 전달하는 인수는 아래 query에서 relationship_name을 사용 합니다.

     
     select relationship_name, relationship_type, lhs_module, lhs_key, join_key_lhs,  
               rhs_module, rhs_key, join_key_rhs
       from relationships 
      where lhs_module = '$masterModule' 
        and rhs_module = '$slaveModule'
      order by relationship_type, relationship_name;
    • $relationshipName으로 데이터 가져오기

     
     $data = $newBean->get_linked_beans('quotes', 'Quote');
     
    • n:m relate 관계 : Slave records 가져오기

     
     

    Custom Relate 관계 Records

    • 1:1 relate 관계 : Master record 가져오기

    • 1:1 relate 관계 : Slave record 가져오기

    • 1:n relate 관계 : Master record 가져오기

    • 1:n relate 관계 : Slave records 가져오기

      • $relationshipName 확인 방법

        • 방안 1 : "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름

        • 방안 2 : rollupSum($relationshipName, $field) 함수에서 첫번째 인수값

        • 방안 3 : vi custom/modules/$Module/Ext/Vardefs/vardefs.ext.php

          • type이 link이고 relationship이 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름과 같은 필드의 name

        • 방안 4 : DB Query 사용, relationship_name 필드값 사용

      • load_relationship 함수에 전달하는 인수는 아래 query에서 relationship_name을 사용 합니다.

     
     select relationship_name, relationship_type, lhs_module, lhs_key, join_key_lhs,  
               rhs_module, rhs_key, join_key_rhs
       from relationships 
      where lhs_module = '$masterModule' 
        and rhs_module = '$slaveModule'
      order by relationship_type, relationship_name;
    • $relationshipName으로 데이터 가져오기

     
     if (!isset($bean->$relationshipName)) {
         $bean->load_relationship($relationshipName);
     }
     $data= $bean->$relationshipName->getBeans();
     
     
     

    Related Records 가져오기

    • Standard Relationship records 가져오기

      • $module->relationship_fields의 value를 참조하여 관계명 지정

      • $rel_~ 변수의 값으로 관계명 지정

     
     $data = $newBean->get_linked_beans('quotes');
     foreach ($data as $item) {
     }
    • 모듈에서 다른 모듈의 id를 저장하고 있는 필드명은 join_key_lhs, join_key_rhs를 사용 합니다.

     
     select relationship_name, relationship_type, lhs_module, lhs_key, join_key_lhs,  
               rhs_module, rhs_key, join_key_rhs
       from relationships 
      where (lhs_module = 'Opportunities' and rhs_module = 'Quotes')
           or (lhs_module = 'Quotes' and rhs_module = 'Opportunities')
      order by lhs_module;
     
     

    모듈간 Relation 관계에서 레이블 변경

    • 작업실(Studio)의 라벨 편집 화면에서 변경 가능

    • XXX vi custom/Extension/modules/$Module/Ext/Language/ko_KR.custom${othermodule}_${module}_1.php

     
     $mod_strings['LBL_$OTHERMODULE_$MODULE_1_FROM_$OTHERMODULE_TITLE']('LBL_$OTHERMODULE_$MODULE_1_FROM_$OTHERMODULE_TITLE'.md) = '연락처';
     //--- $mod_strings['LBL_CONTACTS_DA05_OPPCONTACTROLE_1_FROM_CONTACTS_TITLE']('LBL_CONTACTS_DA05_OPPCONTACTROLE_1_FROM_CONTACTS_TITLE'.md) = '연락처';
     

    모듈간 Relation 관계에서 필수 필드 선언

    • vi custom/Extension/modules/$Module/Ext/Vardefs/${othermodule}_${module}1${Module}.php

      • required 속성 추가

     
     $dictionary["da05_OppContactRole"]["fields"]["contacts_da05_oppcontactrole_1_name"]("contacts_da05_oppcontactrole_1_name".md) = array (
         'name' => 'contacts_da05_oppcontactrole_1_name',
         'type' => 'relate',
         'required' => true,
     );
     

    Related Module을 삭제

    • after_relationship_delete Logic Hook에서 호출

     
     public function deleteRecord(&$bean, $event, $arguments) 
     {
         if (($beanToDelete = BeanFactory::getBean($arguments['related_module'], $arguments['related_id']('related_id'.md))) === FALSE) {
             return;
         }
         $beanToDelete->mark_deleted($beanToDelete->id);
     }
     

    Related 연결 추가 및 삭제

     $opp = BeanFactory::getBean('Opportunities', $bean->opportunity_id);
     $opp->load_relationship('opportunities_products_1');
     $opp->opportunities_products_1->add($item->id);
     $opp->opportunities_products_1->delete($bean->opportunity_id, $item->id);
     

    Query문으로 관련 데이터 가져오기

     	function get_products() 
     	{
     		// First, get the list of IDs.
      		$query = "SELECT product_id as id 
     					from  $this->rel_products
     					where bundle_id='$this->id' AND deleted=0 ORDER BY product_index";
     
     		return $this->build_related_list($query, new Product());
     	}
     

    관계 이름 확인 방법

     $linked_fields = $bean->get_linked_fields();
     foreach($linked_fields as $name => $properties) {
         $GLOBALS['log']('log'.md)->info('Start Logic Hooks : CustomOpportunitiesLogicHooks linked_fields - '.$name);
     }

    Relate 필드에서 버튼 삭제

    • vi custom/modules/$Module/metadata/editviewdefs.php

     
     0 => 
               array (
                 'name' => '',
                 'studio' => 'visible',
                 'label' => '',
                 'displayParams' => array('hideButtons' => true),               //--- hideButtons를 true로 설정
               ),
     

    Subpanel

    Subpanel 파일 위치

    • Subpanel의 항목 정의 사항이 저장되는 파일

      • 영업기회의 연락처 subpanel 변경시

      • custom/Extension/modules/Opportunities/Ext/Layoutdefs/_overrideOpportunity_subpanel_contacts.php

      • custom/modules/Contacts/metadata/subpanels/Opportunity_subpanel_contacts.php

     
     $subpanel_layout['list_fields']('list_fields'.md) = array(
         'name' => array (
             'name' => 'name',
             'vname' => 'LBL_LIST_NAME',
             'widget_class' => 'SubPanelDetailViewLink',
             'module' => 'Contacts',
             'width' => '20%',
             'default' => true,
      ),
     );
     
    • Subpanel 정의 파일

      • modules/$module/metadata/subpaneldefs.php

      • custom/modules/$module/Ext/Layoutdefs/layoutdefs.ext.php

     
     

    Subpanel 필터

     
     

    Custom Subpanel

    • vi custom/Extension/modules/$Module/Ext/Layoutdefs/layoutdefs.custom.php

      • vi custom/modules/pn01_Organization/Ext/Layoutdefs/layoutdefs.ext.php

     
     $layout_defs['pn01_Organization']['subpanel_setup']['teams']('teams'.md) = array(
     	'order' => 100,
     	'sort_by' => 'name',
     	'sort_order' => 'asc',
     	'title_key' => 'LBL_TEAMS',
     		
     	'module' => 'Teams',
     	'subpanel_name' => 'default',       //--- modules/Teams/subpanels/ 폴더 아래에 있는 파일명
     	'get_subpanel_data' => 'function:getUserTeams',
     	'generate_select' => true,
     	'top_buttons' => array(),
     	'function_parameters' => array(
     		'import_function_file' => 'custom/modules/$Module/customSubpanel.php',
     		'id' => $this->_focus->id,
     		'user_id' => $this->_focus->user_id_c,
     		'return_as_array' => 'true',
     	),
     );
     
    • vi custom/modules/$Module/customSubpanel.php

     
     function getUserTeams($params) {
     //	$bean = $GLOBALS['app']('app'.md)->controller->bean;
     	
     	$user_id = $params['user_id']('user_id'.md);
     
     	$return_array['select']('select'.md) = ' SELECT teams.* ';
     	$return_array['from']('from'.md) 	= ' FROM teams ';
     	$return_array['where']('where'.md) 	= ' WHERE teams.id in (select b.team_id from team_memberships b where b.user_id = \''.$user_id.'\')';
      	$return_array['join']('join'.md) 	= '';
      	$return_array['join_tables']('join_tables'.md) = '';
     	return $return_array;
     }
     
     
     

    Multi-Select checkbox 삭제

    • display()

     
     $this->lv->multiSelect = false;
     

    ListView

     
     

    ListView에 Duration Custom Code 추가

    • customCode를 활용하여 이미지 등 html 코드를 추가할 수 있음

    • vi ~listviewdefs.php

     
     'DURATION' => array (
         'type' => 'varchar',
         'label' => 'LBL_DURATION',
         'customCode' => '{$DURATION_HOURS}:{$DURATION_MINUTES}',
         'width' => '10% ',
         'default' => true,
         'sortable' => false,
         'related_fields' => array('duration_hours','duration_minutes'),
     ),
     

    like search 대신 동일한 값 검색

     $searchFields['<>']['<>']('<>'.md) = array(
         'query_type' => 'default',
         'operator'   => '='
     );
     

    Debug

    Sugar Logger 확장

    • vi include/SugarLogger/LoggerManager.php

      • Request로 showlog=true 가 요청이된 세션에서 모든 로그 표시

     
      	public function __call($method, $message)
      	{
      	 	if (isset($_REQUEST['showlog']('showlog'.md))) {
      			$_SESSION['showlog'] = ($_REQUEST['showlog']('showlog'.md) == 'true');
      		}
      		
      		if ( !isset(self::$_levelMapping[$method]($method.md)) )
                 $method = $this->_level;
     
      		//if the method is a direct match to our level let's let it through this allows for custom levels
      		if (($method == $this->_level) ||
      		    (isset($_SESSION['showlog']) && ($_SESSION['showlog']('showlog'.md) == true)) ||
                 (!empty(self::$_levelMapping[$method]) && self::$_levelMapping[$this->_level] >= self::$_levelMapping[$method]($method.md)) ) {
     
    • Trace Log 표시

      • vi config_override.php

     
     $sugar_config['stack_trace_errors']('stack_trace_errors'.md) = true;
     
     

    로그 메시지

     $GLOBALS['log']('log'.md)->info('~');
     $GLOBALS['log']('log'.md)->error('~');
     $GLOBALS['log']('log'.md)->debug('~');
     

    Error message 표시

     SugarApplication::appendErrorMessage('Enter your message string');
     

    krumo를 사용한 디버깅

     
     url = "http://ServerUrl/InstanceName/custom/net/sourceforge/krumo/"
     
    • 사용법

     
     require_once('custom/net/sourceforge/krumo/class.krumo.php');
     krumo($this->bean);
     

    다른 Sugar Page로 분기

     $queryParams = array(
         'module' => 'Accounts',
         'action' => 'DetailView',
         'record' => $recordId,
     );
     SugarApplication::redirect('index.php?' . http_build_query($queryParams));
     

    LogicHooks

    • LogicHooks의 종류

      • after_ui_frame, after_ui_footer

      • after_save, before_save

      • before_retrieve, after_retrieve

      • process_record

      • before_delete, after_delete

      • before_restore, after_restore

      • server_roundtrip

      • before_logout, after_logout

      • before_login, after_login, login_failed

      • after_session_start

      • after_entry_point

       
    • Logic Hooks 선언 (Module별 실행 후 Application별 실행)

      • Module별 실행

        • custom/modules/$module/logic_hooks.php

        • custom/module/$module/Ext/LogicHooks/logichooks.ext.php

          • custom/Extenstion/module/$module/Ext/LogicHooks/logichooks.custom.php

      • Application별 실행

        • custom/modules/logic_hooks.php

        • custom/application/Ext/LogicHooks/logichooks.ext.php

          • custom/Extenstion/application/Ext/LogicHooks/logichooks.ext.php

       
    • $hook_array

     
     $hook_array[$event][](.md) = array($order_idx, 'fts', $file, $class, $function);
         $class = new $hook_class([]($this->bean,)$event, $arguments);
         $class->$hook_function([]($this->bean,)$event, $arguments)
     
    • vi custom/Extenstion/module/$module/Ext/LogicHooks/logichooks.custom.php

     
     if (!isset($hook_array['before_save']('before_save'.md))) {
     	$hook_array['before_save']('before_save'.md) = Array();
     }
     $hook_array['before_save'][](.md) = Array(
     		count($hook_array['before_save']('before_save'.md)) + 1, 'CustomAccountsLogicHooks', 
     		'custom/modules/Accounts/CustomAccountsLogicHooks.php',
     		'CustomAccountsLogicHooks', 'BeforeSave');
     
    • vi custom/modules/$Module/Custom${Module}LogicHooks.php

     
        /*
         * $bean					: Event가 발생한 모듈
         * 		Old value			: $bean->fetched_row['$field']('$field'.md)
         * 		New value			: $bean->$field
         * $event					: Event의 종류
         * 		before_delete, after_delete / before_save, after_save / after_retrieve, process_record
         * $arguments				: Event에 따른 인수값
         * 		array ( 'check_notify' => false, )
         * 
         * 조건 체크
         * 		after_save && $bean->fetched_row == false		: 등록
         * 		after_save && $bean->fetched_row == true		: 수정
         */
     
     
     

    Administration에 메뉴 추가

    • vi custom/Extension/modules/Administration/Ext/Administration/administration.custom.php

     
     global $current_user,$admin_group_header;
     $admin_group_header[4][3]['Administration']['ShowModule']('ShowModule'.md) = array(
     		'ConfigureTabs','LBL_SHOW_MODULE','LBL_SHOW_MODULE_DESC','./index.php?module=Administration&action=ShowModule'
     		);
     

    SugarBean

    SugarBean 가져오기

    • moduleName : include/modules.php 파일의 $moduleList 참조

    • data/BeanFactory.php

     
     $bean = BeanFactory::newBean($module);
     $bean = BeanFactory::getBean($module);
     
    • include/MVC/SugarModule.php

     
     $sugarModule = SugarModule::get($module);
     $bean = $sugarModule ->loadBean();
     

    SugarBean item 가져오기

    • data/BeanFactory.php

      • 모듈별 10개의 cache된 bean 관리

     
     $bean = BeanFactory::getBean($module, $id);
     
    • data/SugarBean.php

     
     $bean = $bean->getRelatedFields($module, $id, null, true);
     

    SugarBean data 가져오기

     $bean->load_relationship('opportunities_products_1');
     $products = $bean->opportunities_products_1->getBeans();
     

    SchedulersJob

        //---	SchedulersJobs을 실행 합니다.
        //---	$this->target = $method::$option
        //---	$method
        //---		function				: modules/Schedulers/_AddJobsHere.php에 등록된 함수($option) 실행
        //---				[custom/](custom/.md)modules/Schedulers/_AddJobsHere.php
        //---				custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php
        //---		link					: 등록된 URL($option)을 호출하고 그 결과를 반환
        //---		class					: RunnableSchedulerJob를 구현한 class($option)를 실행
        //---			custom/include/SugarQueue/SugarCrontJobs.php 에 추가 class를 정의할 것
     
     
     

    Scheduler 추가

    • vi custom/Extension/modules/Schedulers/Ext/Language/ko_KR.custom.php

     
     $mod_strings['LBL_CUSTOMSCHEDULER001']('LBL_CUSTOMSCHEDULER001'.md) = '수식 필드 일배치 갱신';
     
    • vi custom/Extension/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.custom.php

     
     if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
     
     require_once('data/BeanFactory.php');
     require_once('include/SugarDateTime.php');
     require_once('include/TimeDate.php');
     
     $job_strings[](.md) = 'CustomScheduler001';                     //---	새로 추가하는 스케쥴러 Task
     function CustomScheduler001($data) {
      	$today = new DateTime();
      	$today->setDate(date("Y"), date("m"), date("d"));
      	$today->setTime(0, 0, 0);
      	
      	$bean = BeanFactory::getBean('Contracts');
      	$data = $bean->get_full_list('', "'".$today->format('Y-m-d')."' < end_date or 0 < contract_days_sf_c");
      	foreach ($data as $item) {
      		CustomScheduler001_setDays($item, $today);
      	}
            return true;                                        //---   반드시 true를 반환할 것
     }
     
    • "관리자모드 -> 스케쥴러" 메뉴에서 위에서 추가한 기능을 스케쥴러로 등록

     
     

    Scheduler를 사용하여 수식을 동적으로 갱신

    • 수식을 동적으로 갱신

     
     $module = "Quotes"; // Set the module where you calculated field is.
     $order_by = ""; //
     $where = ""; // If you want to filter the records to update, specify it here.  See SugarBean->getFullList for docs on how to
     require_once('include/utils.php');
     require_once('include/export_utils.php');
     
     $cnt = 0;
     $moduleBean = BeanFactory::getBean($module);
     $beanList = $moduleBean->get_full_list($order_by,$where);
     if( $beanList != null ) {
         foreach($beanList as $b) {
             // These lines prevent the modified date and user from being changed.
             $b->update_date_modified = false;
             $b->update_modified_by = false;
             $b->tracker_visibility = false;
             $b->save();
             $cnt++;
         }
     }
     

    run_job

    • vi run_job.php

      • CLI 방식으로 호출되어 실행

      • run_job.php $jobId $clientId

        • $jobId : SchedulersJob의 ID

        • SchedulersJob에 등록된 해당 Job을 실행할 수 있는 Client ID

     
     

    User에 Default Role 추가

     
     

    SugarCharts

    • include/SugarCharts/

      • saved_reports 모듈

    • modules/Charts/

      • include/Dashlets/DashletGenericChart.php

     
     

    SugarCharts Customize

    • vi include/SugarCharts/SugarChartFactory.php

      • $sugar_config'chartEngine' = 'Jit';

      • custom/include/SugarCharts/$chartEngine/${chartEngine}$Module.php, ${chartEngine}$Module class

       
    • vi custom/include/SugarCharts/Jit/JitReports.php

      • 상속 관계

        • vi include/SugarCharts/Jit/Jit.php

        • vi include/SugarCharts/JsChart.php

        • vi include/SugarCharts/SugarCharts.php

      • 함수

        • setData() : $this->data_set 에 데이터 저장

        • setProperties() : $this->chart_properties의 값 지정

        • generateXML() : XML 데이터 생성

        • saveXMLFile() : 생성된 XML 데이터를 파일로 저장 (cache/xml/~_saved_chart.xml)

        • display() : Chart를 화면에 표시

        • getChartResources() : Chart에서 사용할 JavaScript를 반환

     
     include/SugarCharts/Jit/FlashCanvas/flashcanvas.js
     include/SugarCharts/Jit/js/Jit/jit.js
     include/SugarCharts/Jit/js/sugarCharts.js
     
    • vi include/SugarCharts/Jit/js/sugarCharts.js

      • loadSugarChart() 함수에 각 chart별 처리 로직이 구현되어 있음

       
    • SugarCharts의 종류

      • "bar chart", "group by chart", "stacked group by chart"

      • "horizontal"/"horizontal bar chart", , "horizontal group by chart"

      • "pie chart", "funnel chart 3D", "line chart", "gauge chart"

       
    • ChartConfigParams

     
     chartType    : barChart(막대), pieChart(원형), funnelChart(깔때기), lineChart(줄), gaugeChart(게이지)
     orientation  : virtical, horizontal
     barType      : basic, grouped, stacked
     
    • cache/xml/_saved_chart.xml (는 report의 uid임) 파일의 구조

      • 420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.xml

     
     
     
         
             //--- Chart의 Properties
         
         
             //--- Chart를 위해 생성된 데이터
             
                 곽재용 과장
                 9
                 
                     
                         나인소프트
                         1
                         
                         
                     
                 
             
         
         
             0
             21
             5
             1
         
    • cache/xml/_saved_chart.js (는 report의 uid임) 파일의 구조

      • 420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.js

     
     {
         "properties": [{
             //--- Chart의 Properties
         }],
         "label": [~ ](),
         "color": [~ ](),
         "values": [{
             "label": "곽재용 과장",
              "values": [~ ](),
              "valuelabels": [~ ](),
              "links": [~](),
         }],
     }
     
    • cache/images/420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.png 파일

    • SugarCharts에 새로운 chartType 추가

      • JitReports.getChartResources() 함수에서 아래 JavaScript를 추가하도록 수정

        • vi custom/include/SugarCharts/Jit/js/sugarCharts.js 생성

     
     

    보고서에서 Chart 사용

    • 보고서 마법사

      • vi custom/modules/Reports/ReportsWizard.php

     
     $sugarChart = SugarChartFactory::getInstance();
     $resources = $sugarChart->getChartResources();
     $sugar_smarty->assign('chartResources', $resources);
    • vi modules/Reports/templates/templates_reports.php

     
     $sugarChart = SugarChartFactory::getInstance();
     $resources = $sugarChart->getChartResources();
     $smarty->assign('chartResources', $resources);
     
    • 보고서

      • vi modules/Reports/templates/templates_chart.php

     
     $sugarChart = SugarChartFactory::getInstance('','Reports');
     $sugarChart->setData($chart_rows);
     $sugarChart->setProperties($chartTitle, '', $chartType, 'on', 'value', 'on', $do_thousands);
     $xmlFile = get_cache_file_name($reporter);
     $sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML());
     echo $sugarChart->display($guid, $xmlFile, $width, $height, $reportChartDivStyle);
     
    • SugarCharts에 새로운 chartType 추가

      • vi custom/modules/Reports/ReportsWizard.php

        • $chart_types 에 새로운 chartType 추가

      • vi modules/Reports/templates/templates_reports.php

        • ReportsWizard.php 파일에서 template_reports_chart_options() 함수를 override 하는 방법 검토 필요

        • $chart_types 에 새로운 chartType 추가

        • vi modules/Reports/templates/templates_chart.php

        • ReportsWizard.php 파일에서 draw_chart() 함수를 override 하는 방법 검토 필요

          • draw_chart() 함수에서 새로운 chartType 처리 기능 추가

       
    • 보고서에서 Chart 호출

     
     var css = new Array();
     css["gridLineColor"]("gridLineColor".md) = '#cccccc';
     css["font-family"]("font-family".md) = 'Arial';
     css["color"]("color".md) = '#000000';
      
     var chartConfig = new Array();
     chartConfig["orientation"]("orientation".md) = 'horizontal';
     chartConfig["barType"]("barType".md) = 'stacked';
     chartConfig["tip"]("tip".md) = 'name';
     chartConfig["chartType"]("chartType".md) = 'barChart';
     chartConfig["imageExportType"]("imageExportType".md) = 'png';
     
     loadSugarChart('420b0a67-4227-7ab2-170a-51675cd154dc','cache/xml/420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.js',css,chartConfig);
     

    SugarPDF

    • index.php?module=$Module&action=sugarpdf&sugarpdf=$pdfAction

      • include/MVC/View/views/view.sugarpdf.php

      • custom/modules/$Module/views/view.sugarpdf.php

      • $pdfAction : smarty (Defalut), 이 값을 사용하여 다양한 양식의 PDF 문서를 작성할 수 있습니다.

        • include/Sugarpdf/sugarpdf/sugarpdf.$pdfAction.php

        • custom/modules//sugarpdf/sugarpdf.$pdfAction.php

       
    • Sugarpdf

      • include/Sugarpdf/Sugarpdf.php

        • include/tcpdf/tcpdf.php

      • Header(), Setfont(), Cell(), getNumLines()

      • predisplay(), display(), process(), writeCellTable(), writeHTMLTable()

     
     

    Chart

    • vi custom/Charts/chartDefs.ext.php

     
     

    Global 설정

     
     

    Sugar Limit

    • vi config.php

     
     $sugar_config['resource_management']['default_limit']('default_limit'.md) = 1000;
     $sugar_config['resource_management']['special_query_limit']('special_query_limit'.md) = 50000;
     $sugar_config['resource_management']['special_query_modules'][](.md) = 'Opportunities';
     

    성능 개선

    튜닝

     
    • vi config_override.php

     
     $sugar_config['disable_count_query']('disable_count_query'.md) = true;
     $sugar_config['verify_client_ip']('verify_client_ip'.md) = false;
     $sugar_config['disable_vcr']('disable_vcr'.md) = true;
     
     
     

    권한 설정

    • vi data/SugarBean.php

      • add_team_security_where_clause() 함수에서 user id에 해당하는 데이터만 가져오도록 query문에 where 조건을 설정 합니다.

       
    • 활용 방안

      • 이슈 1 : 모듈별 데이터에 대한 공유 설정을 지원하지 않음

      • 이슈 2 : 관리자가 데이터에 대한 공유 설정을 할 수 있는 기능이 없음

      • 활용

        • team_memberships 테이블에 모듈 필드를 추가함, 이 필드에 값이 있을 경우 관리자가 설정한 공유 설정임

        • 조직도를 추가하고 관리자가 설정할 수 있는 공유 설정 화면을 추가함

     
     

    Java에서 RESTful 함수 사용

     
     

    .htaccess를 사용한 custom 설정

    • 세션 이름 변경

     
     php_value session.name TEST
     
     
     

    SugarCache

     sugar_cache_put($key,$mod_strings);
     $return_result = sugar_cache_retrieve($key);
     

    SugarTheme

    • 테마에서 이미지 또는 JavaScript 파일을 찾는 순서

     
     [custom/](custom/.md)themes/$imagePath/images/$imageName
     [custom/](custom/.md)themes/$parentTheme_imagePath/images/$imageName
     [custom/](custom/.md)themes/default/images/$imageName
     include/images/$imageName
     

    MultiLanguage

    • $app_strings

     
     $lang : en_us, $sugar_config->default_language, $language
     include/language/$lang.lang.php, $lang.lang.override.php, $lang.lang.php.override
     custom/application/Ext/Language/$lang.lang.ext.php
     custom/include/language/$language/$lang.lang.php
     
    • $mod_strings

     
     $lang : en_us, $sugar_config->default_language, $language
     include/SugarObjects/templates/$template/language/$lang.lang.php
     include/SugarObjects/implements/$template/language/$lang.lang.php
     modules/$module/language/$lang.lang[.override](.override.md).php
     custom/modules/$module/Ext/Language/$lang.lang.ext.php
     custom/modules/$module/language/$lang.lang.php
     
    • $mod_list_strings

     
     modules/$module/language/en_us.lang.php
     modules/$module/language/$language.lang[.override](.override.md).php, $language.lang.php.override
     
    • $theme_strings

     
     $lang : $language, $sugar_config->default_language
     themes/$theme/language/$lang.lang[.override](.override.md).php, $lang.lang.php.override
    • notify template file

     
     [custom/](custom/.md)include/language/$language.notify_template.html
     [custom/](custom/.md)include/language/en_us.notify_template.html
     

    TimeDate

    PHP#DateTime

     
    • DB 포맷으로 저장된 Datetime을 datetime 형식으로 변환

     
     $tmpDateStart = SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->date_start);
     $tmpDateStart->add(new DateInterval("PT9H"));   //--- 9시간 더하기
     
    • vi include/TimeDate.php

    • datetime과 datetime간의 일수 계산

     
     $dateTo = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType($timedate->fromDbType($bean->date_closed_sf_c, 'datetime'), 'date'));
     $dateFr = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType($timedate->fromDbType($bean->date_opened_sf_c, 'datetime'), 'date'));
     $tmpDateInterval = date_diff($dateTo, $dateFr);
     $bean->time_to_close_sf_c = $tmpDateInterval ->days;
     
    • date와 datetime간의 일수 계산

     
     $dateTo = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->initial_touch_sf_c.' 00:00:00'), 'date'));
     $dateFr = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType($timedate->fromDbType($bean->date_opened_sf_c, 'datetime'), 'date'));
     $tmpDateInterval = date_diff($dateTo, $dateFr);
     $duration = $tmpDateInterval->days;
     
    • date와 date간의 일수 계산

     
     $dateTo = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->initial_touch_sf_c.' 00:00:00'), 'date'));
     $dateFr = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->date_opened_sf_c.' 00:00:00'), 'date'));
     $tmpDateInterval = date_diff($dateTo, $dateFr);
     $duration = $tmpDateInterval->days;
     
    • date와 date간의 일수 계산

     
     $dateTo = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->date_closed.' 00:00:00'), 'date'));
     $dateFr = SugarDateTime::createFromFormat($timedate->get_date_format(), $timedate->asUserType(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, $bean->sfdc_paymentdate_sf_c.' 00:00:00'), 'date'));
     $tmpDateInterval = date_diff($dateTo, $dateFr);
     $duration = $tmpDateInterval->days;
     

    Email Archiving

    • vi config.php

     
     'host_name' => 'demo.smartprocess.co.kr:88',
     'site_url' => 'http://demo.smartprocess.co.kr:88/testEnt',
     

    Inbound Email

    • vi run_job.php

    • vi modules/Schedulers/_AddJobsHere.php

      • pollMonitoredInboxes()

      • vi modules/InboundEmail/InboundEmail.php 파일의 handleCreateCase() 함수가 호출됨

       
    • Case 생성시 description에 한줄로 표시되는 현상

      • Email에 description과 description_html이 저장되는데 cases에서는 Email의 description 필드가 저장됨

      • description 필드의 값이 줄바꿈이 있을 경우 화면에서는 줄이 변경되어 표시됨

     
     

    team_sets의 team_md5

     $team_md5 = '';
     sort($team_ids, SORT_STRING);
     $team_md5 .= $team_id;
     $team_md5 = md5($team_md5);
     
    • Team Set의 아이디와 Team 아이디가 같고 Team Set에 하나의 팀만 등록되어 있을 경우

     
     select id, name, team_md5, md5(id)
       from team_sets
      where team_md5 != md5(id);
        
     update team_sets
        set name = md5(id),
            team_md5 = md5(id)
      where id like 'update_%'
        and team_md5 != md5(id);
     
    • Team Set에 속한 팀 조회

     
     select id, team_id, team_set_id 
       from team_sets_teams 
      where team_set_id = '3ac43ff5-3886-36e4-db35-5140567d78f7';
     
    • 팀 구성원 조회

     
     select id, user_id, explicit_assign, implicit_assign, deleted 
       from team_memberships 
      where team_id = 'update_team_16' 
        and explicit_assign = 1
        and deleted = 0;
     

    Authentication 구조

     
     SugarApplication.execute()
         loadUser()
             global $authController = new AuthenticationController((!empty($GLOBALS['sugar_config']['authenticationClass'])? $GLOBALS['sugar_config']['authenticationClass']('authenticationClass'.md) : 'SugarAuthenticate'));
                 //---   $this->authController = custom/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php
                 //---       $this->userAuthenticate = custom/modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php
         SugarController.execute().process().callLegacyCode()
             modules/Users/Authenticate.php
                 $authController.login($user_name, $password);
                     SugarAuthenticate.loginAuthenticate($username, $password, false, $PARAMS);
                         SugarAuthenticateUser.loadUserOnLogin($username, $password, $fallback, $PARAMS).authenticateUser($name, $input_hash, $fallback)
                             User::findUserPassword($name, $password, ~).checkPasswordMD5($password, $row['user_hash']('user_hash'.md))
     

    검색에서 담당자명 정렬

    • vi include/utils.php 파일의 758 라인을 수정

      • get_user_array 함수

     
     // $query = $query.' ORDER BY user_name ASC';
     $query = $query.' ORDER BY last_name ASC';
     

    Custom Files

    • QuickCreateModules : custom/modules/Emails/metadata/qcmodulesdefs.php

    • View

      • custom/modules/$Module/metadata/editviewdefs.php

       
    • vi custom/Charts/chartDefs.ext.php

      • vi modules/Charts/chartdefs.php

    • vi custom/Charts/$chart.php

    • custom/$dashletDirectory$dashletClassname/$dashletClassname$current_language.lang.php

    • custom/Extension/application/Ext/TableDictionary/, custom/application/Ext/TableDictionary/

    • custom/backup/

     
     

    초대자 추가하기

    • "회의일정"의 초대자 추가하기 관련 파일

      • vi modules/Meetings/jsclass_scheduler.js

     
     

    지원하는 Cache

     
     

    참고 자료

     
     

    Sugar Metadata


    dictionary

    • $dictionary 정의 파일

      • vi modules/$Module/vardefs.php

      • vi custom/Extension/modules/$Module/Ext/Vardefs/vardefs.custom.php

       
    • $dictionary$Module

      • table : 테이블명

      • audited : true. audit 대상 테이블

      • unified_search, unified_search_default_enabled : true. Global Search 대상 모듈

      • full_text_search

      • duplicate_merge

      • comment

      • fields$field

        • name : 필드명

        • vname : 레이블명

        • type : id, name, enum, currency, datetime, date, varchar, int, link, relate

          • 'function' : call_user_func_array($execute_function, $execute_params);
            :*function_name, function_require : include할 PHP 파일명, function_class, function_params, function_params_source = 'this/parent', source = 'function'

        • dbType : id, varchar, char, double

        • source

          • 'non-db'. Database에서 관리되지 않는 필드

          • 'function'

        • len

        • options : 선택목록일 경우 사용할 list 이름

        • comment

        • function : call_user_func($function, $this->focus, $name, $value, $this->view);

          • include : include할 PHP 파일명

          • name : 함수명

          • returns
            :*'html'. html 문자열을 값으로 반환 
            :*returns가 선언되지 않았을 경우, function의 결과값이 필드의 options에 저장됨

          • params

          • onListView : true, false

        • readonly : Read Only 필드

        • required : true. 필수 필드

        • validation

          • type, min, max : array('type' => 'range', 'min' => 0, 'max' => 100)

        • dependency : 의존 관계

        • visibility_grid : 의존 관계

          • trigger : 상위 필드명

          • values$parent_value : array ($chield_value1, $chield_value2)

        • unified_search : true. Global Search 대상 필드

        • full_text_search

        • group

        • id_name : type이 relate일 경우 사용할 key 필드명

        • table, module, join_name, link, rname

        • relationship, link_type, rel_fields

        • acl

        • merge_filter, isnull, audited, importable, reportable, massupdate, duplicate_merge, disable_num_format, enable_range_search

        • studio

          • wirelesseditview, wirelessdetailview, editview, detailview, quickcreate

      • indices

        • name

        • type

        • fields : array('id','deleted')

      • relationships$relationshipName

        • lhs_module, lhs_table, lhs_key

        • rhs_module, rhs_table, rhs_key

        • relationship_type, relationship_role_column, relationship_role_column_value

     
     

    Sugar 검토


    활동 내역과 활동 기록에서 관련 자료 선택 목록에 표시되는 모듈 추가

    • vi custom/Extension/application/Ext/Language/ko_KR.custom.php

     
     
     

    Cases에서 거래처(account_name)를 필수 필드에서 삭제

    • vi config_override.php

     
     $sugar_config['require_accounts']('require_accounts'.md) = false;
     

    Sugar 버그


    화면이 깨어지고 Ajax 오류 창이 표시됨

    • 원인 : CentOS에 설치된 PHP 라이브러리의 버전이 달라 문제가 발생 합니다.

    • vi jssource/Minifier.php 파일의 158 라인

     
     // $this->input = preg_replace('/\h/u', ' ', $this->input);
     $this->input = preg_replace('/[\t]()/u', ' ', $this->input); 
    • "Admin -> Repair -> Repair JS Files" 실행

    • cache/ 폴더의 파일을 모두 삭제

     
     

    Home 화면에서 Dashlet의 탭이 계속 실행중으로 표시됨

    • cache/xml/ 폴더를 apache:apache 권한으로 생성을 합니다.

     
     

    한글로 모듈 목록 검색시 빈화면 표시

    • 현상 : AJAX 목록 화면에서 한글로 검색시 화면이 표시되지 않고 또한 한글이 깨어짐

    • vi include/ListView/ListViewData.php 파일의 529 라인

     
     // $queryString = htmlentities($_REQUEST[$field_name]($field_name.md));
     $queryString = htmlentities($_REQUEST[$field_name]($field_name.md), null, "UTF-8");
     

    메일 발송시 보낸 사람 이름

    • vi modules/Emails/Email.php 파일에서 851 라인

      • 근본적으로 해결을 하려면 $mail->FromName 값이 MIME으로 인코딩 되었을 경우에만 decode를 하도록 수정할 것

     
     // $this->from_addr_name = $this->from_addr;
     $this->from_addr_name = "{$mail->FromName} <{$mail->From}>";
     

    의존 관계에서 Drag-Drop 오류

    • 현상 : 상위 선택목록에 따른 하위 선택목록 구성시 오류 발생

    • 원인 : 상위 선택목록의 값으로 JavaScript에서 index를 사용함으로 인한 오류

    • 해결 방안 : 값과는 별개로 index를 관리하여야 함

    • vi custom/modules/ModuleBuilder/views/view.depdropdown.php

    • vi custom/modules/ModuleBuilder/tpls/depdropdown.tpl

     
     

    ACLAction 오류

    • 오류 메시지 : FATAL Error evaluating expression: Non-static method ACLAction::getUserAccessLevel() should not be called statically, assuming $this from incompatible context

    • 조치 방법

      • vi modules/ACLActions/ACLAction.php 파일의 365라인

     
     // function getUserAccessLevel($user_id, $category, $action,$type='module'){
     public static function getUserAccessLevel($user_id, $category, $action,$type='module'){
     

    PDF 생성시 암호를 물어볼 경우

    • vi /etc/php.ini

     
     [mbstring](mbstring.md)
     mbstring.language = UTF-8
     mbstring.internal_encoding = UTF-8
     mbstring.http_input = auto
     ;mbstring.http_output = UTF-8                           //--- 이 라인을 지우고
     mbstring.http_output = pass                             //--- 이 라인을 추가 하세요
     mbstring.encoding_translation = On
     mbstring.detect_order = auto
     mbstring.substitute_character = none
     

    Sugar 개선


    Relate 필드에서 필드명 표시

    • vi modules/DynamicFields/templates/Fields/Forms/relate.tpl

     
     

    기능 추가


    자동 번호 필드

    • vi custom/modules/DynamicFields/templates/Fields/TemplateAutoincrement.php

    • vi custom/modules/DynamicFields/templates/Fields/Forms/autoincrement.php

    • vi custom/modules/DynamicFields/templates/Fields/Forms/autoincrement.tpl

    • vi custom/include/SugarFields/Fields/Autoincrement/SugarFieldAutoincrement.php

    • vi custom/include/SugarFields/Fields/Autoincrement/EditView.tpl

    • vi custom/Extension/modules/DynamicFields/Ext/Language/ko_KR.Autoincrement.lang.php

    • vi custom/Extension/modules/ModuleBuilder/Ext/Language/ko_KR.Autoincrement.lang.php

    • Core 소스 수정 사항

      • vi modules/ExpressEngine/formulaHelper.php

      • vi data/SugarBean.php

     
     updateCalculatedFields() 함수 최상단에
     SugarFieldAutoincrement::saveBean($this); 추가
     
    • LogicHooks 등에서 자동번호 필드값을 설정하고 싶은 경우

      • 위에서 SugarBean.php를 수정하였을 경우에는 사용할 필요가 없습니다.

     
     require_once('include/SugarFields/SugarFieldHandler.php');
     
     $quote = BeanFactory::getBean('Quotes');
     $field = 'no_c';
     $sugarField = SugarFieldHandler::getSugarField($quote->field_defs[$field]['type']('type'.md));
     $sugarField->save($quote, array($field => ''), $field, $quote->field_defs[$field]($field.md));
     

    Multi-Layout 지원

    • 구현 방안

      • Record별로 recordType 저장

      • 사용자별로 모듈별 사용할 수 있는 레코드 타입을 저장

      • 초기 레코드 생성시 사용자가 사용할 수 있는 레코드 타입이 2개 이상이면 레코드 타입을 선택하는 화면을 표시

       
    • 일반 모듈에서 Layout (metadata/~viewdefs.php) 지정 방법

      • include/MVC/View/views/view.detail.php 파일에서 getMetaDataFile() 함수 호출

        • 결론 : include/MVC/View/SugarView.php, getMetaDataFile() 함수에서 metadata 파일명을 반환

      • $this->module, $this->type 정보와 $this->bean 정보를 사용하여 metadataFile명을 지정

      • 대안 : custom/modules/$Module/metadata/metafiles.php 파일을 수정하여 구현 가능

       
    • Studio에서 Layout 지정 방법

      • modules/ModulerBuilder/controller.php, action_editLayout() 함수에서 $this->view에 작업할 view 이름 지정

        • Parameter : 'view_module' => 'Accounts', 'view' => 'editview'

      • modules/ModulerBuilder/views/view.layoutview.php

        • $this->type = $this->sm->getViewType($this->editLayout);

        • modules/ModuleBuilder/Module/StudioModule.php, getViewType() 함수가 type을 반환

          • $this->editModule, $this->editLayout 를 사용하여 type 지정

      • 결론 : 아래 두 파일의 getFileName()에서 반환하는 Layout (metadata/~viewdefs.php) 파일을 사용

        • modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation

        • modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation

      • $view , $moduleName , $packageName를 사용하여 파일명 확인 가능

     
     

    이번 주 검색 지원

    • 보고서와 화면에서 "지난 주", "이번 주", "다음 주" 검색 조건을 추가 합니다.

     
     

    보고서

    • vi custom/Extension/modules/Reports/Ext/Language/ko_KR.custom.php

      • vi modules/Reports/language/ko_KR.lang.php

     
     $mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md) = '지난 주';
     $mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md) = '이번 주';
     $mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md) = '다음 주';
     
    • vi modules/Reports/templates/templates_modules_def_js.php

     
        qualifiers[qualifiers.length] = {name:'tp_last_week',value:''};
        qualifiers[qualifiers.length] = {name:'tp_this_week',value:''};
        qualifiers[qualifiers.length] = {name:'tp_next_week',value:''};
        
    • vi custom/include/generic/SugarWidgets/SugarWidgetFielddatetime.php

      • function displayInput(&$layout_def) 수정

     
            'TP_last_week'     => $home_mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md),
            'TP_this_week'     => $home_mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md),
            'TP_next_week'     => $home_mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md),
    • function queryFilterTP_last_week($layout_def) 생성

     
            function queryFilterTP_last_week($layout_def)
            {
                    global $timedate;
                    $end = new SugarDateTime();
                    switch ($end->format('w')) {                            //--- 0. 일요일, 1. 월요일, ...
                            case '1' : $end->add(new DateInterval("P6D"));  break;
                            case '2' : $end->add(new DateInterval("P5D"));  break;
                            case '3' : $end->add(new DateInterval("P4D"));  break;
                            case '4' : $end->add(new DateInterval("P3D"));  break;
                            case '5' : $end->add(new DateInterval("P2D"));  break;
                            case '6' : $end->add(new DateInterval("P1D"));  break;
                            case '0' :
                            default :
                                    break;
                    }
                    $begin = clone $end;
                    $begin = $begin->sub(new DateInterval("P13D"))->get_day_begin();
                    $end = $end->sub(new DateInterval("P7D"))->get_day_end();
                    return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
            }
    • function queryFilterTP_this_week($layout_def) 생성

     
            function queryFilterTP_this_week($layout_def)
            {
                    global $timedate;
                    $end = new SugarDateTime();
                    switch ($end->format('w')) {                            //--- 0. 일요일, 1. 월요일, ...
                            case '1' : $end->add(new DateInterval("P6D"));  break;
                            case '2' : $end->add(new DateInterval("P5D"));  break;
                            case '3' : $end->add(new DateInterval("P4D"));  break;
                            case '4' : $end->add(new DateInterval("P3D"));  break;
                            case '5' : $end->add(new DateInterval("P2D"));  break;
                            case '6' : $end->add(new DateInterval("P1D"));  break;
                            case '0' :
                            default :
                                    break;
                    }
                    $begin = clone $end;
                    $begin = $begin->sub(new DateInterval("P6D"))->get_day_begin();
                    $end = $end->get_day_end();
                    return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
            }
    • function queryFilterTP_next_week($layout_def) 생성

     
            function queryFilterTP_next_week($layout_def)
            {
                    global $timedate;
                    $end = new SugarDateTime();
                    switch ($end->format('w')) {                            //--- 0. 일요일, 1. 월요일, ...
                            case '1' : $end->add(new DateInterval("P6D"));  break;
                            case '2' : $end->add(new DateInterval("P5D"));  break;
                            case '3' : $end->add(new DateInterval("P4D"));  break;
                            case '4' : $end->add(new DateInterval("P3D"));  break;
                            case '5' : $end->add(new DateInterval("P2D"));  break;
                            case '6' : $end->add(new DateInterval("P1D"));  break;
                            case '0' :
                            default :
                                    break;
                    }
                    $begin = clone $end;
                    $begin = $begin->add(new DateInterval("P1D"))->get_day_begin();
                    $end = $end->add(new DateInterval("P7D"))->get_day_end();
                    return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
            }
     

    고급검색

    • vi custom/Extension/application/Ext/Language/ko_KR.custom.php

      • vi include/language/ko_KR.lang.php

     
     $app_list_strings['date_range_search_dom']['last_week']('last_week'.md) = '지난 주';
     $app_list_strings['date_range_search_dom']['this_week']('this_week'.md) = '이번 주';
     $app_list_strings['date_range_search_dom']['next_week']('next_week'.md) = '다음 주';
     $app_list_strings['kbdocument_date_filter_options']['last_week']('last_week'.md) = '지난 주';
     $app_list_strings['kbdocument_date_filter_options']['this_week']('this_week'.md) = '이번 주';
     $app_list_strings['kbdocument_date_filter_options']['next_week']('next_week'.md) = '다음 주';
     
    • vi include/SearchForm/SearchForm2.php

      • generateSearchWhere()

     
            case 'last_week':
            case 'this_week':
            case 'next_week':
     
    • vi include/TimeDate.php

      • parseDateRange()

     
            case 'next_week':
                return $this->diffWeek(1,  $user, $adjustForTimezone);
            case 'last_week':
                return $this->diffWeek(-1,  $user, $adjustForTimezone);
            case 'this_week':
                return $this->diffWeek(0,  $user, $adjustForTimezone);
    • diffWeek() 생성

     
            protected function diffWeek($mdiff, User $user = null, $adjustForTimezone = true)
            {
                global $timedate;
     
                    $end = new SugarDateTime();
                    switch ($end->format('w')) {                            //--- 0. 일요일, 1. 월요일, ...
                            case '1' : $end->add(new DateInterval("P6D"));  break;
                            case '2' : $end->add(new DateInterval("P5D"));  break;
                            case '3' : $end->add(new DateInterval("P4D"));  break;
                            case '4' : $end->add(new DateInterval("P3D"));  break;
                            case '5' : $end->add(new DateInterval("P2D"));  break;
                            case '6' : $end->add(new DateInterval("P1D"));  break;
                            case '0' :
                            default :
                                    break;
                    }
                    $begin = clone $end;
                    $begin->sub(new DateInterval("P6D"));
                if ($mdiff == 1) {
                    $begin->add(new DateInterval("P7D"));
                    $end->add(new DateInterval("P7D"));
                }
                if ($mdiff == -1) {
                    $begin->sub(new DateInterval("P7D"));
                    $end->sub(new DateInterval("P7D"));
                }
                $begin = $begin->get_day_begin();
                $end = $end->get_day_end();
                return array($begin, $end);
            }
     

    미확인 항목

    • vi custom/Extension/modules/Home/Ext/Language/ko_KR.custom.php

      • vi modules/Home/language/ko_KR.lang.php

     
     $mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md) = '지난 주';
     $mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md) = '이번 주';
     $mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md) = '다음 주';
     

    Sugar Tip


    자신만의 로그 보기

    • vi include/SugarLogger/LoggerManager.php

      • 214 라인 아래에 다음을 추가 합니다.

     
     } else {
        if (isset($_REQUEST['showlog']('showlog'.md))) {
            if ($_REQUEST['showlog']('showlog'.md) == 'true') {
                $_SESSION['showlog']('showlog'.md) = true;
            } else {
                $_SESSION['showlog']('showlog'.md) = false;
            }
        }
     
        if (isset($_SESSION['showlog']('showlog'.md))) {
            if ($_SESSION['showlog']('showlog'.md) == true) {
                $logger = (!empty(self::$_logMapping[$method])) ? self::$_logMapping[$method] : self::$_logMapping['default']('default'.md);
                if (!isset(self::$_loggers[$logger]($logger.md))) {
                    self::$_loggers[$logger]($logger.md) = new $logger();
                }
                self::$_loggers[$logger]($logger.md)->log($method, $message);
            }
        }
     

    회의일정에 사용자 초대 화면이 보이지 않을 경우

    • 화면에 "기간" 필드를 추가 하세요.

     
     

    백업 파일 확장자

    • Upgrade 등을 할 경우, layout은 ~.suback.php 확장자를 가진 파일로 백업 됩니다.

      • 예)custom/modules/Contacts/metadata/detailviewdefs.php.suback.php

     
     

    지원 업체


    {{지원업체}}

     

    [[Category:오픈소스|Category:오픈소스]]
    [[Category:CRM|Category:CRM]]
    [[Category:한글화|Category:한글화]]
    [[Category:Sugar|Category:Sugar]]
    분류: WebSite

    최종 수정일: 2024-09-30 12:26:18

    이전글 :
    다음글 :