"Sugar Customize"의 두 판 사이의 차이
둘러보기로 가기
검색하러 가기
잔글 |
잔글 |
||
1,707번째 줄: | 1,707번째 줄: | ||
== 지원 업체 == | == 지원 업체 == | ||
+ | {{지원업체}} | ||
− | + | [[Category:오픈소스|Category:오픈소스]]<br/>[[Category:CRM|Category:CRM]]<br/>[[Category:한글화|Category:한글화]]<br/>[[Category:Sugar|Category:Sugar]]<br/>[[Category:WebSite|Category:WebSite]] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
2018년 1월 31일 (수) 13:22 기준 최신판
SugarCRM Customize 방법을 정리 합니다.
목차
- 1 Sugar 분석
- 1.1 Home
- 1.2 Request Type
- 1.3 DetailView
- 1.4 Field
- 1.4.1 Database에 없는 필드 추가
- 1.4.2 Parent 선택 목록에 항목 추가
- 1.4.3 선택목록 값 변경
- 1.4.4 선택목록 값 파싱
- 1.4.5 선택목록 키에 특수문자 사용
- 1.4.6 ReadOnly Field
- 1.4.7 Filed의 레이블 가져오기
- 1.4.8 의존 관계
- 1.4.9 관계(Relate) 필드명 확인
- 1.4.10 Expression
- 1.4.11 Custom Expression
- 1.4.12 Custom Validation
- 1.4.13 Custom Mask
- 1.4.14 Sugar Field Control 생성
- 1.4.15 customCode
- 1.4.16 amount_usdollar
- 1.4.17 금액 필드 오른쪽 정렬
- 1.5 Relate 관계
- 1.6 Subpanel
- 1.7 ListView
- 1.8 Debug
- 1.9 LogicHooks
- 1.10 Administration에 메뉴 추가
- 1.11 SugarBean
- 1.12 SchedulersJob
- 1.13 User에 Default Role 추가
- 1.14 SugarCharts
- 1.15 SugarPDF
- 1.16 Chart
- 1.17 Global 설정
- 1.18 Sugar Limit
- 1.19 성능 개선
- 1.20 권한 설정
- 1.21 Java에서 RESTful 함수 사용
- 1.22 .htaccess를 사용한 custom 설정
- 1.23 SugarCache
- 1.24 SugarTheme
- 1.25 MultiLanguage
- 1.26 TimeDate
- 1.27 Email Archiving
- 1.28 Inbound Email
- 1.29 team_sets의 team_md5
- 1.30 Authentication 구조
- 1.31 검색에서 담당자명 정렬
- 1.32 Custom Files
- 1.33 초대자 추가하기
- 1.34 지원하는 Cache
- 1.35 참고 자료
- 2 Sugar Metadata
- 3 Sugar 검토
- 4 Sugar 버그
- 5 Sugar 개선
- 6 기능 추가
- 7 Sugar Tip
- 8 지원 업체
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
- 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
버튼 추가 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
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에 대한 도움말을 여기에 작성 합니다. * * 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]->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()를 수행하고 다음으로 넘어가도록 합니다.
- 참고 문헌
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}' . ' <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를 가져오는 방법
모듈간 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에 필터 추가
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; }
- 참고 문헌
- 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'); 참조
- 참고 문헌
로그 메시지
$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 : 수정 */
- 참고 문헌
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를 정의할 것
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 추가
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> //--- Chart를 위해 생성된 데이터 <group> <title>곽재용 과장</title> <value>9</value> <subgroups> <group> <title>나인소프트</title> <value>1</value> <label>1</label> <link></link> </group> </subgroups> </group> <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/
- 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 함수 사용
.htaccess를 사용한 custom 설정
- 세션 이름 변경
php_value session.name TEST
- 참고 문헌
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
- 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 구조
- 로그인 화면
-
- 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)
- 참고 문헌
참고 자료
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
지원 업체
SuiteCRM을 사용한 영업관리, 고객관리는 아래 담당자에게 연락하여 주시면, 빠르고 친절하게 전문적인 답변을 드리겠습니다.
영업 문의 | sales@obcon.biz | 010-4667-1106 | 영업 대표 |
기술 문의 | tech@obcon.biz | 구축/컨설팅 담당 | |
고객 지원 | support@obcon.biz | 고객 지원 담당 |