Sugar Customize 문서 원본 보기
←
Sugar Customize
둘러보기로 가기
검색하러 가기
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
이 문서는 편집하거나 다른 명령을 할 수 없도록 보호되어 있습니다.
문서의 원본을 보거나 복사할 수 있습니다.
[[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'] = true; $dictionary['test1_vacation']['unified_search_default_enabled'] = true; $dictionary[‘test1_vacation']['fields']['subject']['unified_search'] = true; *vi custom/modules/test1_vacation/metadata/SearchFields.php <?php if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); require_once('modules/test1_vacation/metadata/SearchFields.php'); $searchFields[$module_name]['subject'] = array( 'query_type'=>'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[]= Array( "index.php?module=Import&action=Step1&import_module=Opportunities&return_module=Opportunities&return_action=index", $mod_strings['LNK_DIVIDE'], "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"}]', '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"}]', '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=== *[http://urdhva-tech.blogspot.kr/2013/02/hide-select-and-cancel-buttons-from.html Hide Select and Cancel buttons from Relate type fields, 201302] ====버튼 추가 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.'<input title="{$MOD.LNK_DIVIDE}" class="button" '; //--- "button primary", "button" $tmpStr = $tmpStr.' onclick="funcClickButton(this.form, null, \'Divide\', \'{$fields.id.value}\', \'Opportunities\', \'DetailView\', \'{$fields.id.value}\');"'; $tmpStr = $tmpStr.' id="divide_button" name="button" value="{$MOD.LNK_DIVIDE}" type="submit">'; $tmpStr = $tmpStr.'{/if}'; $this->dv->defs['templateMeta']['form']['buttons'][] = array ('customCode' => $tmpStr); //--- 계약 생성 버튼 추가 $tmpStr = ''; $tmpStr = $tmpStr.'{if $bean->aclAccess("edit")}'; $tmpStr = $tmpStr.'<input title="{$MOD.LNK_CONTRACT}" class="button" '; //--- "button primary", "button" $tmpStr = $tmpStr.' onclick="funcClickButton(this.form, \'Contracts\', \'EditView\', \'\', \'Opportunities\', \'DetailView\', \'{$fields.id.value}\');"'; $tmpStr = $tmpStr.' id="contract_button" name="button" value="{$MOD.LNK_CONTRACT}" type="submit">'; $tmpStr = $tmpStr.'{/if}'; $this->dv->defs['templateMeta']['form']['buttons'][] = array ('customCode' => $tmpStr); $this->dv->defs['templateMeta']['includes'][] = array ('file' => $this::JS_COMMON); $this->dv->defs['templateMeta']['includes'][] = 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][] = array ( 'customCode' => ' {if $bean->aclAccess("edit")} <input title="{$MOD.LNK_DIVIDE}" class="button" onclick="this.form.action.value=\'Divide\';this.form.return_module.value=\'Opportunities\';this.form.return_action.value=\'DetailView\'; this.form.return_id.value=\'{$fields.id.value}\'" id="divide_button" name="button" value="{$MOD.LNK_DIVIDE}" type="submit"> {/if}' ); *vi Extension/modules/Opportunities/Ext/Language/ko_KR.customDivide.php $mod_strings['LNK_DIVIDE'] = 'MA/PJT 분할'; ====버튼의 위치 조정==== $new_array = array(); $MyNewCustomCodeButton = "<input type='button' onclick='SomeAction();' value='Click me' />"; $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][0]; // EDIT $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][1]; // DUPLICATE $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][2]; // DELETE $new_array[] = array('customCode' => $MyNewCustomCodeButton); $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][3]; // quote2opp $new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][4]; // quote2pdf $this->dv->defs['templateMeta']['form']['buttons'] = $new_array; parent::display(); ===Field=== *http://developers.sugarcrm.com/wordpress/2012/05/14/new-for-sugar-6-5-in-with-jquery-and-the-beginning-of-the-move-away-from-yui/ ====Database에 없는 필드 추가==== *vi /custom/Extension/modules/$Module/Ext/Vardefs/custom_fileds.php $dictionary[$Module]['fields'][$field]= 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'])) { $hook_array['process_record'] = Array(); } $hook_array['process_record'][] = Array( count($hook_array['process_record']) + 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'] = 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'] = 'VOC'; $app_list_strings['record_type_display_notes']['da18_ProjHistory'] = '프로젝트 작업내역'; ====선택목록 값 변경==== *vi custom/include/language/ko_KR.lang.php $GLOBALS['app_list_strings']['sba__snbServiceContract__c_sba__Owner_Expiration_Notice__c_list']=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'] = true; ====Filed의 레이블 가져오기==== $displayFieldValue = $GLOBALS['app_list_strings'][$bean->field_defs[$fieldname]['options'][$bean->$fieldname]]; //--- 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]]; }); ====의존 관계==== *vi custom/Extension/modules/$Modules/Ext/Vardefs/sugarfield_$field.php $dictionary['Account']['fields']['fld_industrytype2_sf_c']['visibility_grid'] = 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에 대한 도움말을 여기에 작성 합니다. * * <b>subStr(String s, Number from, Number length)</b><br> * Returns <i>length</i> characters starting at 0-based index <i>from</i>.<br /> * ex: <em>subStr("Hello", 1, 3)</em> = "ell" */ class SubStrExpression extends StringExpression { //--- PHP로 Expression을 실행하고 그 결과를 반환 합니다. //--- $param = $this->getParameters()->evaluate(); //--- Parameter 1개 //--- $params = $this->getParameters(); //--- Parameter 여러개 //--- $param1 = $params[0]->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].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()를 수행하고 다음으로 넘어가도록 합니다. *참고 문헌 :*http://forums.sugarcrm.com/f6/custom-field-validation-before-opportunity-submit-form-sugar-6-5-0-a-82162/ ====Custom Mask==== *http://developers.sugarcrm.com/wordpress/2010/03/05/masked-input-field/ ====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}' . ' <input name="first_name" id="first_name" size="25" maxlength="25" type="text" value="{$fields.first_name.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'] = array('EDIT', 'DUPLICATE', 'DELETE', array('customCode'=>'<form action="index.php" method="POST" name="Quote2Opp" id="form"><input type="hidden" name="module" value="Quotes"><input type="hidden" name="record" value="{$fields.id.value}"><input type="hidden" name="user_id" value="{$current_user->id}"><input type="hidden" name="team_id" value="{$fields.team_id.value}"><input type="hidden" name="user_name" value="{$current_user->user_name}"><input type="hidden" name="action" value="QuoteToOpportunity"><input type="hidden" name="opportunity_subject" value="{$fields.name.value}"><input type="hidden" name="opportunity_name" value="{$fields.name.value}"><input type="hidden" name="opportunity_id" value="{$fields.billing_account_id.value}"><input type="hidden" name="amount" value="{$fields.new_sub.value}"><input type="hidden" name="valid_until" value="{$fields.date_quote_expected_closed.value}"><input type="hidden" name="currency_id" value="{$fields.currency_id.value}"><input title="{$APP.LBL_QUOTE_TO_OPPORTUNITY_TITLE}" class="button" type="submit" name="opp_to_quote_button" value="{$APP.LBL_QUOTE_TO_OPPORTUNITY_LABEL}"></form>'), array('customCode'=>'<form action="index.php" method="{$PDFMETHOD}" name="ViewPDF" id="form" onsubmit="this.layout.value =(document.getElementById(\'layout\'))? document.getElementById(\'layout\').value: \'\';"><input type="hidden" name="layout" value=""><input type="hidden" name="module" value="Quotes"><input type="hidden" name="record" value="{$fields.id.value}"><input type="hidden" name="action" value="Layouts"><input type="hidden" name="entryPoint" value="pdf"><input type="hidden" name="email_action"><input title="{$APP.LBL_EMAIL_PDF_BUTTON_TITLE}" class="button" type="submit" name="button" value="{$APP.LBL_EMAIL_PDF_BUTTON_LABEL}" onclick="this.form.email_action.value=\'EmailLayout\';"> <input title="{$APP.LBL_VIEW_PDF_BUTTON_TITLE}" class="button" type="submit" name="button" value="{$APP.LBL_VIEW_PDF_BUTTON_LABEL}"></form>') ); ====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(); *n:m relate 관계 : Master records 가져오기 *n:m relate 관계 : Slave records 가져오기 *참고 문헌 :*http://developers.sugarcrm.com/wordpress/2012/03/23/howto-using-the-bean-instead-of-sql-all-the-time/ :*http://developers.sugarcrm.com/wordpress/2012/04/23/howto-get-related-bean-record-details-from-the-vardef/ :*http://developers.sugarcrm.com/wordpress/2012/04/26/howto-grab-a-filtered-list-of-related-record-to-the-current-record-using-beans/ ====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; :*조건을 지정하여 Relationship records를 가져오는 방법 ::*http://developers.sugarcrm.com/wordpress/2012/04/26/howto-grab-a-filtered-list-of-related-record-to-the-current-record-using-beans/ ====모듈간 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'] = '연락처'; //--- $mod_strings['LBL_CONTACTS_DA05_OPPCONTACTROLE_1_FROM_CONTACTS_TITLE'] = '연락처'; ====모듈간 Relation 관계에서 필수 필드 선언==== *vi custom/Extension/modules/$Module/Ext/Vardefs/${othermodule}_${module}_1_${Module}.php :*required 속성 추가 $dictionary["da05_OppContactRole"]["fields"]["contacts_da05_oppcontactrole_1_name"] = 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'])) === 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']->info('Start Logic Hooks : CustomOpportunitiesLogicHooks linked_fields - '.$name); } ====Relate 필드에서 버튼 삭제==== *vi custom/modules/$Module/metadata/editviewdefs.php 0 => array ( 'name' => '<YOUR_FIELD_NAME>', 'studio' => 'visible', 'label' => '<LBL_YOUR_FIELD_NAME>', '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'] = 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 필터==== *Subpanel에 필터 추가 :*http://developers.sugarcrm.com/wordpress/2012/12/06/creating-a-subpanel-filter/ ====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'] = 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']->controller->bean; $user_id = $params['user_id']; $return_array['select'] = ' SELECT teams.* '; $return_array['from'] = ' FROM teams '; $return_array['where'] = ' WHERE teams.id in (select b.team_id from team_memberships b where b.user_id = \''.$user_id.'\')'; $return_array['join'] = ''; $return_array['join_tables'] = ''; return $return_array; } *참고 문헌 :*http://developers.sugarcrm.com/wordpress/2012/10/08/customizing-the-query-used-for-a-subpanel/ :*http://urdhva-tech.blogspot.kr/2013/02/add-custom-subpanel-in-accounts-module.html *Subpanel을 동적으로 관리 :*http://support.sugarcrm.com/02_Documentation/04_Sugar_Developer/Sugar_Developer_Guide_6.5/03_Module_Framework/06_Subpanels/Examples/Dynamically_Hiding_Subpanels_Based_on_Record_Values :*http://support.sugarcrm.com/02_Documentation/04_Sugar_Developer/Sugar_Developer_Guide_6.5/03_Module_Framework/06_Subpanels/Examples/Dynamically_Collapsing_Subpanels_Based_on_Record_Values :*http://developers.sugarcrm.com/wordpress/2012/04/06/howto-add-the-more-info-popup-to-subpanels/ ====Multi-Select checkbox 삭제==== *display() $this->lv->multiSelect = false; ===ListView=== *http://developers.sugarcrm.com/wordpress/2012/05/15/howto-drop-a-listview-in-anywhere-with-the-listviewfacade/ *http://developers.sugarcrm.com/wordpress/2011/04/26/howto-add-a-field-from-a-related-module-into-the-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['<<moduleName>>']['<<searchFieldName>>'] = 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'])) { $_SESSION['showlog'] = ($_REQUEST['showlog'] == 'true'); } if ( !isset(self::$_levelMapping[$method]) ) $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'] == true)) || (!empty(self::$_levelMapping[$method]) && self::$_levelMapping[$this->_level] >= self::$_levelMapping[$method]) ) { *Trace Log 표시 :*vi config_override.php $sugar_config['stack_trace_errors'] = true; :*vi include/utils.php ::*set_error_handler('StackTraceErrorHandler'); 참조 *참고 문헌 :*http://www.php.net/manual/kr/function.debug-backtrace.php :*http://www.php.net/manual/kr/function.debug-print-backtrace.php ====로그 메시지==== $GLOBALS['log']->info('~'); $GLOBALS['log']->error('~'); $GLOBALS['log']->debug('~'); ====Error message 표시==== SugarApplication::appendErrorMessage('Enter your message string'); ====krumo를 사용한 디버깅==== *http://sourceforge.net/projects/krumo/files/ 사이트에서 krumo를 다운로드하여 custom/net/sourceforge/krumo 폴더에 저장 합니다. :*vi custom/net/sourceforge/krumo/krumo.ini 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][] = 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'])) { $hook_array['before_save'] = Array(); } $hook_array['before_save'][] = Array( count($hook_array['before_save']) + 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'] * 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 : 수정 */ *참고 문헌 :*http://developers.sugarcrm.com/wordpress/2012/04/12/howto-restore-automatically-inviting-the-organizer-to-calls-and-meetings-in-sugar-6-3-and-later/ ===Administration에 메뉴 추가=== *vi custom/Extension/modules/Administration/Ext/Administration/administration.custom.php global $current_user,$admin_group_header; $admin_group_header[4][3]['Administration']['ShowModule'] = 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/]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를 정의할 것 *http://developers.sugarcrm.com/wordpress/2012/08/09/use-the-new-job-queue-to-make-logic-hooks-perform-faster/ ====Scheduler 추가==== *vi custom/Extension/modules/Schedulers/Ext/Language/ko_KR.custom.php $mod_strings['LBL_CUSTOMSCHEDULER001'] = '수식 필드 일배치 갱신'; *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[] = '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 추가=== *http://developers.sugarcrm.com/wordpress/2012/10/31/set-a-default-role-for-newly-created-users/ ===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 <?xml version="1.0" encoding="UTF-8"?> <sugarcharts version="1.0"> <properties> //--- Chart의 Properties </properties> <data> //--- Chart를 위해 생성된 데이터 <group> <title>곽재용 과장</title> <value>9</value> <subgroups> <group> <title>나인소프트</title> <value>1</value> <label>1</label> <link></link> </group> </subgroups> </group> </data> <yAxis> <yMin>0</yMin> <yMax>21</yMax> <yStep>5</yStep> <yLog>1</yLog> </yAxis> </sugarcharts> *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"] = '#cccccc'; css["font-family"] = 'Arial'; css["color"] = '#000000'; var chartConfig = new Array(); chartConfig["orientation"] = 'horizontal'; chartConfig["barType"] = 'stacked'; chartConfig["tip"] = 'name'; chartConfig["chartType"] = 'barChart'; chartConfig["imageExportType"] = '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/<module>/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 설정=== *Global Utility 정보 :*$GLOBALS['sugar_config'] ::*SugarConfig::getInstance()->get('logger.level', $this->_level); :*$GLOBALS['app_strings'] :*$GLOBALS['mod_strings'] :*$GLOBALS['log'] :*$GLOBALS['db'] *Global 정보 :*$GLOBALS['current_user'] :*$GLOBALS['app'] :*$GLOBALS['app']->controller ::*$GLOBALS['module'], $GLOBALS['action'] :*$GLOBALS['current_view'], $GLOBALS['view'] ::*$GLOBALS['FOCUS'] : 현재 읽은 레코드 *기타 Global 정보 :*$GLOBALS['current_language'] :*$GLOBALS['beanList'], $GLOBALS['beanFiles'] :*$GLOBALS['moduleList'] :*$GLOBALS['app_list_strings'] :*$GLOBALS['system_config'] :*$GLOBALS['logic_hook'] :*$GLOBALS['current_sugarfeed'] :*$GLOBALS['request_string'] :*$GLOBALS['adminOnlyList'] :*$GLOBALS['modListHeader'] :*$GLOBALS['modInvisList'], $GLOBALS['modInvisListActivities'] :*$GLOBALS['sugar_version'], $GLOBALS['sugar_db_version'], $GLOBALS['sugar_flavor'], $GLOBALS['server_unique_key'] :*$GLOBALS['image_path'] :*$GLOBALS['gridline'] :*$GLOBALS['updateSilent'] :*global $theme;, global $max_tabs; ===Sugar Limit=== *vi config.php $sugar_config['resource_management']['default_limit'] = 1000; $sugar_config['resource_management']['special_query_limit'] = 50000; $sugar_config['resource_management']['special_query_modules'][] = 'Opportunities'; ===성능 개선=== [[튜닝]] *vi config_override.php $sugar_config['disable_count_query'] = true; $sugar_config['verify_client_ip'] = false; $sugar_config['disable_vcr'] = true; *참고 문헌 :*http://developers.sugarcrm.com/wordpress/2010/06/16/quick-pointers-on-sugarcrm-performance/ :*http://developers.sugarcrm.com/wordpress/category/performance-2/ :*http://kb.siteground.com/how_to_optimize_sugarcrm_for_better_performance/ :*[http://developers.sugarcrm.com/wordpress/2013/02/05/php-profiling-via-xhprof-now-built-into-sugarcrm-6-5-10-and-later/ XHProf, 2013.02] :*http://developers.sugarcrm.com/wordpress/2012/09/28/adding-indices-to-custom-fields-thru-the-vardefs/ :*http://developers.sugarcrm.com/wordpress/2012/09/19/using-the-sugar-external-cache-api/ :*http://developers.sugarcrm.com/wordpress/2012/09/18/speeding-up-sugar-using-an-external-cache/ :*http://www.cr38.co/2012/04/04/optimising-sugar/ ===권한 설정=== *vi data/SugarBean.php :*add_team_security_where_clause() 함수에서 user id에 해당하는 데이터만 가져오도록 query문에 where 조건을 설정 합니다. *활용 방안 :*이슈 1 : 모듈별 데이터에 대한 공유 설정을 지원하지 않음 :*이슈 2 : 관리자가 데이터에 대한 공유 설정을 할 수 있는 기능이 없음 :*활용 ::*team_memberships 테이블에 모듈 필드를 추가함, 이 필드에 값이 있을 경우 관리자가 설정한 공유 설정임 ::*조직도를 추가하고 관리자가 설정할 수 있는 공유 설정 화면을 추가함 ===Java에서 RESTful 함수 사용=== *http://developers.sugarcrm.com/wordpress/2013/02/11/being-restful-with-sugarcrm-api-and-java/ :*http://www.providentcrm.com/news/being-restful-with-sugarcrm-api-and-java/ ===.htaccess를 사용한 custom 설정=== *세션 이름 변경 php_value session.name TEST *참고 문헌 :*http://community.365managed.com/?document_srl=333731 :*http://php.net/manual/kr/configuration.changes.php ===SugarCache=== sugar_cache_put($key,$mod_strings); $return_result = sugar_cache_retrieve($key); ===SugarTheme=== *테마에서 이미지 또는 JavaScript 파일을 찾는 순서 [custom/]themes/$imagePath/images/$imageName [custom/]themes/$parentTheme_imagePath/images/$imageName [custom/]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].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].php, $language.lang.php.override *$theme_strings $lang : $language, $sugar_config->default_language themes/$theme/language/$lang.lang[.override].php, $lang.lang.php.override *notify template file [custom/]include/language/$language.notify_template.html [custom/]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 구조=== *로그인 화면 :*http://cloud.smartprocess.co.kr/daouall/index.php?action=Login&module=Users&login_module=Home&login_action=index ::*Request - array ( 'module' => 'Users', 'action' => 'Authenticate', 'login_language' => 'ko_KR', 'user_name' => '사용자명', 'user_password' => '비밀번호', ) *로그인 실행 순서 :*$sugar_config['authenticationClass'] : SugarAuthenticate 클래스명 SugarApplication.execute() loadUser() global $authController = new AuthenticationController((!empty($GLOBALS['sugar_config']['authenticationClass'])? $GLOBALS['sugar_config']['authenticationClass'] : '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']) ===검색에서 담당자명 정렬=== *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=== *APC *Wincache *Zend Cache *Memcache (using either the memcache or memcached extension) *Redis (using the PHP Redis extension) *참고 문헌 :*http://developers.sugarcrm.com/wordpress/2012/09/18/speeding-up-sugar-using-an-external-cache/ :*http://developers.sugarcrm.com/wordpress/2013/04/29/setting-up-memcache-with-sugar-on-windows/ ===참고 자료=== *[http://developers.sugarcrm.com/wordpress/2013/01/02/create-an-email-record-thru-web-services/ Create an Email record thru Web Services, 2013.01] ==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 <?php //--- 관련 자료 선택 목록에 표시되는 모듈 추가 $app_list_strings['parent_type_display']['da03_Voc'] = 'VOC'; //--- 메모(Notes) 모듈의 관련 자료 선택 목록에 표시되는 모듈 추가 $app_list_strings['record_type_display_notes']['da03_Voc'] = 'VOC'; ?> ===Cases에서 거래처(account_name)를 필수 필드에서 삭제=== *vi config_override.php $sugar_config['require_accounts'] = 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]); $queryString = htmlentities($_REQUEST[$field_name], 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.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']); $sugarField->save($quote, array($field => ''), $field, $quote->field_defs[$field]); ===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'] = '지난 주'; $mod_strings['LBL_THIS_WEEK'] = '이번 주'; $mod_strings['LBL_NEXT_WEEK'] = '다음 주'; *vi modules/Reports/templates/templates_modules_def_js.php qualifiers[qualifiers.length] = {name:'tp_last_week',value:'<?php echo $mod_strings['LBL_LAST_WEEK']; ?>'}; qualifiers[qualifiers.length] = {name:'tp_this_week',value:'<?php echo $mod_strings['LBL_THIS_WEEK']; ?>'}; qualifiers[qualifiers.length] = {name:'tp_next_week',value:'<?php echo $mod_strings['LBL_NEXT_WEEK']; ?>'}; *vi custom/include/generic/SugarWidgets/SugarWidgetFielddatetime.php :*function displayInput(&$layout_def) 수정 'TP_last_week' => $home_mod_strings['LBL_LAST_WEEK'], 'TP_this_week' => $home_mod_strings['LBL_THIS_WEEK'], 'TP_next_week' => $home_mod_strings['LBL_NEXT_WEEK'], :*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'] = '지난 주'; $app_list_strings['date_range_search_dom']['this_week'] = '이번 주'; $app_list_strings['date_range_search_dom']['next_week'] = '다음 주'; $app_list_strings['kbdocument_date_filter_options']['last_week'] = '지난 주'; $app_list_strings['kbdocument_date_filter_options']['this_week'] = '이번 주'; $app_list_strings['kbdocument_date_filter_options']['next_week'] = '다음 주'; *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'] = '지난 주'; $mod_strings['LBL_THIS_WEEK'] = '이번 주'; $mod_strings['LBL_NEXT_WEEK'] = '다음 주'; ==Sugar Tip== ===자신만의 로그 보기=== *vi include/SugarLogger/LoggerManager.php :* 214 라인 아래에 다음을 추가 합니다. } else { if (isset($_REQUEST['showlog'])) { if ($_REQUEST['showlog'] == 'true') { $_SESSION['showlog'] = true; } else { $_SESSION['showlog'] = false; } } if (isset($_SESSION['showlog'])) { if ($_SESSION['showlog'] == true) { $logger = (!empty(self::$_logMapping[$method])) ? self::$_logMapping[$method] : self::$_logMapping['default']; if (!isset(self::$_loggers[$logger])) { self::$_loggers[$logger] = new $logger(); } self::$_loggers[$logger]->log($method, $message); } } ===회의일정에 사용자 초대 화면이 보이지 않을 경우=== *화면에 "기간" 필드를 추가 하세요. ===백업 파일 확장자=== *Upgrade 등을 할 경우, layout은 ~.suback.php 확장자를 가진 파일로 백업 됩니다. :*예)custom/modules/Contacts/metadata/detailviewdefs.php.suback.php == 지원 업체 == {{지원업체}} [[Category:오픈소스|Category:오픈소스]]<br/>[[Category:CRM|Category:CRM]]<br/>[[Category:한글화|Category:한글화]]<br/>[[Category:Sugar|Category:Sugar]]<br/>[[Category:WebSite|Category:WebSite]]
이 문서에서 사용한 틀:
틀:지원업체
(
원본 보기
)
Sugar Customize
문서로 돌아갑니다.
둘러보기 메뉴
개인 도구
로그인
이름공간
문서
토론
변수
보기
읽기
원본 보기
역사 보기
더 보기
검색
주요 메뉴
오픈소스 컨설팅
오픈소스
오픈소스 라이선스
오픈소스 커뮤니티
오픈소스 종류
오픈소스 현황
오픈소스 한글화
문자셋과 인코딩
Storage
Network
보안
고가용성
모니터링
오픈 API
오픈 서비스
Cloud
BigData
Android
산사랑 노트
둘러보기
인기 문서
최근 수정 문서
모든 문서
모든 분류
임의 문서
위키 사용법
자매 사이트
CMS
오비컨 홈페이지
오비컨 CMS
블로그
데모 - SuiteCRM
산사랑의 Twitter
산사랑의 Facebook
친구 사이트
공개SW 포털
OLIS
한국공개소프트웨어협회
AppCenter 지원본부
OLC
PSEG
개발자 블로그
블로터
개인 메뉴
메뉴 수정
양식함
도구
여기를 가리키는 문서
가리키는 글의 최근 바뀜
특수 문서 목록
문서 정보