- Sugar 분석
- Home
- Global Search 필드 추가
- ElasticSearch
- 레코드의 요약 정보 표시 변경
- Module Menu 추가
- Request Type
- DetailView
- 버튼 추가 1
- 버튼 추가 2
- 버튼의 위치 조정
- Field
- Database에 없는 필드 추가
- Parent 선택 목록에 항목 추가
- 선택목록 값 변경
- 선택목록 값 파싱
- 선택목록 키에 특수문자 사용
- ReadOnly Field
- Filed의 레이블 가져오기
- 의존 관계
- 관계(Relate) 필드명 확인
- Expression
- Custom Expression
- Custom Validation
- Custom Mask
- Sugar Field Control 생성
- customCode
- amount_usdollar
- 금액 필드 오른쪽 정렬
- Relate 관계
- Standard Relate 관계 Records
- Custom Relate 관계 Records
- Related Records 가져오기
- 모듈간 Relation 관계에서 레이블 변경
- 모듈간 Relation 관계에서 필수 필드 선언
- Related Module을 삭제
- Related 연결 추가 및 삭제
- Query문으로 관련 데이터 가져오기
- 관계 이름 확인 방법
- Relate 필드에서 버튼 삭제
- Subpanel
- Subpanel 파일 위치
- Subpanel 필터
- Custom Subpanel
- Multi-Select checkbox 삭제
- ListView
- ListView에 Duration Custom Code 추가
- like search 대신 동일한 값 검색
- Debug
- Sugar Logger 확장
- 로그 메시지
- Error message 표시
- krumo를 사용한 디버깅
- 다른 Sugar Page로 분기
- LogicHooks
- Administration에 메뉴 추가
- SugarBean
- SugarBean 가져오기
- SugarBean item 가져오기
- SugarBean data 가져오기
- SchedulersJob
- Scheduler 추가
- Scheduler를 사용하여 수식을 동적으로 갱신
- run_job
- User에 Default Role 추가
- SugarCharts
- SugarCharts Customize
- 보고서에서 Chart 사용
- SugarPDF
- Chart
- Global 설정
- Sugar Limit
- 성능 개선
- 권한 설정
- Java에서 RESTful 함수 사용
- .htaccess를 사용한 custom 설정
- SugarCache
- SugarTheme
- MultiLanguage
- TimeDate
- Email Archiving
- Inbound Email
- team_sets의 team_md5
- Authentication 구조
- 검색에서 담당자명 정렬
- Custom Files
- 초대자 추가하기
- 지원하는 Cache
- 참고 자료
- Sugar Metadata
- dictionary
- Sugar 검토
- 활동 내역과 활동 기록에서 관련 자료 선택 목록에 표시되는 모듈 추가
- Cases에서 거래처(account_name)를 필수 필드에서 삭제
- Sugar 버그
- 화면이 깨어지고 Ajax 오류 창이 표시됨
- Home 화면에서 Dashlet의 탭이 계속 실행중으로 표시됨
- 한글로 모듈 목록 검색시 빈화면 표시
- 메일 발송시 보낸 사람 이름
- 의존 관계에서 Drag-Drop 오류
- ACLAction 오류
- PDF 생성시 암호를 물어볼 경우
- Sugar 개선
- Relate 필드에서 필드명 표시
- 기능 추가
- 자동 번호 필드
- Multi-Layout 지원
- 이번 주 검색 지원
- 보고서
- 고급검색
- 미확인 항목
- Sugar Tip
- 자신만의 로그 보기
- 회의일정에 사용자 초대 화면이 보이지 않을 경우
- 백업 파일 확장자
- 지원 업체
Global Search (Unified Search) 필드 추가 사례
모듈명 : test1_vacation
테이블명 : test1_vacation
검색에 포함할 필드명 : subject
vi custom/Extension/modules/test1_vacation/Ext/Vardefs/customGlobalSearchFields.php
SugarCRM Customize 방법을 정리 합니다.
Sugar 분석
Home
Global Search 필드 추가
$dictionary['test1_vacation']['unified_search']('unified_search'.md) = true;
$dictionary['test1_vacation']['unified_search_default_enabled']('unified_search_default_enabled'.md) = true;
$dictionary[‘test1_vacation']['fields']['subject']['unified_search']('unified_search'.md) = true;
vi custom/modules/test1_vacation/metadata/SearchFields.php
'default');
?>
"관리자 모드 -> 검색" 메뉴에서 test1_vacation을 "사용가능한 모듈"에 추가
ElasticSearch
vi include/SugarSearchEngine/SugarSearchEngineFactory.php
검색 엔진 ($sugar_config->full_text_engine)
include/SugarSearchEngine/SugarSearchEngine.php
include/SugarSearchEngine/Elastic/SugarSearchEngineElastic.php
vi include/SugarSearchEngine/Elastic/SugarSearchEngineElastic.php
index (Database) : $_indexName($sugar_config->unique_key)으로 지정
type (Table) : $bean->module_dir (default. SugarBean) 로 지정
레코드의 요약 정보 표시 변경
표시 위치
Global Search 결과
Recently Viewed, Favorites
class Ticket extends Issue
{
public function get_summary_text() {
return "Ticket #{$this->ticket_number} - {$this->name}"
}
}
Module Menu 추가
vi custom/Extension/module/Opportunities/Ext/Menus/menu.customDivide.php
global $mod_strings, $app_strings, $sugar_config;
$module_menu[](.md)= Array(
"index.php?module=Import&action=Step1&import_module=Opportunities&return_module=Opportunities&return_action=index",
$mod_strings['LNK_DIVIDE']('LNK_DIVIDE'.md),
"Opportunies",
"Opportunies"
);
Request Type
목록 화면
- Request - Module : Cases, Action : favorites
- Request - Module : Cases, Action : modulelistmenu
- Request - Module : Cases, Action : index
편집 화면 (등록)
- Request - Module : Cases, Action : EditView
Request - array ( 'module' => 'Cases', 'action' => 'EditView', 'return_module' => 'Cases', 'return_action' => 'DetailView', )
- Request - Module : ExpressionEngine, Action : getRelatedValues
Request - array ( 'module' => 'ExpressionEngine', 'action' => 'getRelatedValues', 'record_id' => '', 'tmodule' => 'Cases', 'fields' => '[{"link":"contacts","type":"related","relate":"email_c"}]({"link":"contacts","type":"related","relate":"email_c"}.md)', 'to_pdf' => '1', )
편집 화면 (수정)
- Request - Module : Cases, Action : EditView, Record : 5ffc4f56-1f11-9147-3f69-515e69ad90a6
Request - array (
'module' => 'Cases', 'action' => 'EditView', 'record' => '5ffc4f56-1f11-9147-3f69-515e69ad90a6',
'return_module' => 'Cases', 'return_action' => 'DetailView', 'return_id' => '5ffc4f56-1f11-9147-3f69-515e69ad90a6',
'module_tab' => '', 'isDuplicate' => 'false', 'offset' => '1', 'sugar_body_only' => '', )
- Request - Module : ExpressionEngine, Action : getRelatedValues
관련 목록에서 빠른 편집 화면 (등록) : view type - classic
custom/modules/Home/SubpanelEdits.php 파일 실행
custom/modules/Cases/metadata/quickcreatedefs.php
- Request - Module : Home, Action : SubpanelCreates, Record :
Request - array (
'module' => 'Home', 'action' => 'SubpanelCreates', 'record' => '', 'target_module' => 'Cases', 'target_action' => 'QuickCreate',
'parent_type' => 'Accounts', 'parent_id' => 'sfdc_00120000005hOWpAAM', 'parent_name' => '다우기술',
'return_module' => 'Accounts', 'return_action' => 'DetailView', 'return_id' => 'sfdc_00120000005hOWpAAM',
'return_relationship' => 'account_cases', 'return_name' => '다우기술',
'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술', 'account_cases_name' => '다우기술',
'to_pdf' => 'true', 'tpl' => 'QuickCreate.tpl', 'account_cases_신규자료추가하기_button' => '신규자료 추가하기', )
관련 목록에서 빠른 편집 화면 (수정) : view type - classic
custom/modules/Home/SubpanelEdits.php 파일 실행
custom/modules/Cases/metadata/quickcreatedefs.php
- Request - Module : Home, Action : SubpanelEdits, Record : cc180f6e-36e1-ee71-fb4a-515d0ad0af20
Request - array (
'module' => 'Home', 'action' => 'SubpanelEdits', 'record' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20', 'target_module' => 'Cases', 'target_action' => 'QuickCreate',
'parent_type' => 'Accounts', 'parent_id' => 'sfdc_00120000005hOWpAAM', 'parent_name' => '다우기술',
'return_module' => 'Accounts', 'return_action' => 'DetailView', 'return_id' => 'sfdc_00120000005hOWpAAM',
'return_relationship' => 'account_cases', 'return_name' => '다우기술',
'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술', 'account_cases_name' => '다우기술',
'to_pdf' => 'true', 'tpl' => 'QuickCreate.tpl', 'Cases_subpanel_cancel_button' => '취소', )
- Request - Module : ExpressionEngine, Action : getRelatedValues
Request - array ( 'module' => 'ExpressionEngine', 'action' => 'getRelatedValues', 'record_id' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20', 'tmodule' => 'Cases', 'fields' => '[{"link":"contacts","type":"related","relate":"email_c"}]({"link":"contacts","type":"related","relate":"email_c"}.md)', 'to_pdf' => '1', )
관련 목록에서 빠른 편집 전체 화면 (등록)
- Request - Module : Cases, Action : EditView, Record :
Request - array (
'module' => 'Cases', 'action' => 'EditView', 'record' => '',
'return_module' => 'Accounts', 'return_action' => 'DetailView', 'return_id' => 'sfdc_00120000005hOWpAAM',
'relate_to' => 'account_cases', 'relate_id' => 'sfdc_00120000005hOWpAAM',
'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술',
'full_form' => 'full_form',
'assigned_user_id' => 'sfdc_00520000000shVfAAI', 'assigned_user_name' => '김계현 수석',
'isDuplicate' => 'false', 'module_tab' => '', 'contact_role' => '', 'offset' => '1',
'user_id1_c' => '', 생략)
관련 목록에서 빠른 편집 전체 화면 (수정)
- Request - Module : Cases, Action : EditView, Record : cc180f6e-36e1-ee71-fb4a-515d0ad0af20
Request - array (
'module' => 'Cases', 'action' => 'EditView', 'record' => 'cc180f6e-36e1-ee71-fb4a-515d0ad0af20',
'return_module' => 'Accounts', 'return_action' => 'DetailView', 'return_id' => 'sfdc_00120000005hOWpAAM',
'relate_to' => 'account_cases', 'relate_id' => 'sfdc_00120000005hOWpAAM',
'account_id' => 'sfdc_00120000005hOWpAAM', 'account_name' => '다우기술',
'full_form' => 'full_form',
'assigned_user_id' => 'sfdc_00520000000slI0AAI', 'assigned_user_name' => '송솔잎 차장',
'isDuplicate' => 'false', 'module_tab' => '', 'offset' => '1',
'contact_role' => '', 생략)
보고서에서 빠른 편집 화면 (수정)
- Request - Module : Accounts, Action : Quickedit, Record : sfdc_00120000005hOWpAAM
Request - array ( 'to_pdf' => '1', 'module' => 'Accounts', 'action' => 'Quickedit', 'record' => 'sfdc_00120000005hOWpAAM', )
데이터 저장 (등록)
- Request - Module : Accounts, Action : Save, Record :
Request - array (
'module' => 'Accounts', 'action' => 'Save', 'record' => '',
'return_module' => 'Accounts', 'return_action' => 'index', 'return_id' => '',
'relate_to' => 'Accounts', 'relate_id' => '',
'module_tab' => '', 'isDuplicate' => 'false',
'contact_role' => '', 생략 )
데이터 저장 (수정)
- Request - Module : Accounts, Action : Save, Record : 705aabbb-22d4-fd77-c66e-516226ae32f4
Request - array (
'module' => 'Accounts', 'action' => 'Save', 'record' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
'return_module' => 'Accounts', 'return_action' => 'DetailView', 'return_id' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
'relate_to' => 'Accounts', 'relate_id' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
'parent_name' => '', 'parent_id' => '',
'isDuplicate' => 'false', 'module_tab' => '', 'contact_role' => '', 'offset' => '1',
'name' => 'zzaaa', 생략 )
삭제 화면
- Request - Module : Accounts, Action : Delete, Record : 705aabbb-22d4-fd77-c66e-516226ae32f4
Request - array (
'module' => 'Accounts', 'action' => 'Delete', 'record' => '705aabbb-22d4-fd77-c66e-516226ae32f4',
'return_module' => 'Accounts', 'return_action' => 'ListView', 'return_id' => '',
'module_tab' => '', 'isDuplicate' => 'false', 'offset' => '1', 'sugar_body_only' => '', )
조회 화면
- Request - Module : Accounts, Action : DetailView, Record : sfdc_00120000005hOWpAAM
Request - array ( 'module' => 'Accounts', 'action' => 'DetailView', 'record' => 'sfdc_00120000005hOWpAAM', )
목록 화면에서 고급 검색 화면만 불러 오기
Request - Module : Cases, Action : index
Request - array ( 'module' => 'Cases', 'action' => 'index', 'search_form_only' => 'true', 'to_pdf' => 'true', 'search_form_view' => 'advanced_search', )
DetailView
버튼 추가 1
vi custom/modules/Opportunities/views/view.detail.php
class CustomOpportunitiesViewDetail extends OpportunitiesViewDetail {
const JS_COMMON = 'custom/include/javascript/viewdefs.js';
const JS_MODULE = 'custom/modules/Opportunities/Opportunities.js';
public function preDisplay() {
parent::preDisplay();
//--- 영업기회 분할 버튼 추가
$tmpStr = '';
$tmpStr = $tmpStr.'{if $bean->aclAccess("edit")}';
$tmpStr = $tmpStr.'';
$tmpStr = $tmpStr.'{/if}';
$this->dv->defs['templateMeta']['form']['buttons'][](.md) = array ('customCode' => $tmpStr);
//--- 계약 생성 버튼 추가
$tmpStr = '';
$tmpStr = $tmpStr.'{if $bean->aclAccess("edit")}';
$tmpStr = $tmpStr.'';
$tmpStr = $tmpStr.'{/if}';
$this->dv->defs['templateMeta']['form']['buttons'][](.md) = array ('customCode' => $tmpStr);
$this->dv->defs['templateMeta']['includes'][](.md) = array ('file' => $this::JS_COMMON);
$this->dv->defs['templateMeta']['includes'][](.md) = array ('file' => $this::JS_MODULE);
}
}
vi custom/include/javascript/viewdefs.js
function funcClickButton(theForm, argModule, argAction, argRecord, argReturnModule, argReturnAction, argReturnId) {
if (argModule != null) {
theForm.module.value = argModule;
}
theForm.action.value = argAction;
theForm.record.value = argRecord;
theForm.return_module.value = argReturnModule;
theForm.return_action.value = argReturnAction;
theForm.return_id.value = argReturnId;
}
버튼 추가 2
vi custom/modules/Opportunities/metadata/detailviewdefs.php 파일 하단에 다음을 추가 합니다.
$viewdefs['Opportunities']['DetailView']['templateMeta']['form'][buttons][](.md) = array (
'customCode' => '
{if $bean->aclAccess("edit")}
{/if}'
);
vi Extension/modules/Opportunities/Ext/Language/ko_KR.customDivide.php
$mod_strings['LNK_DIVIDE']('LNK_DIVIDE'.md) = 'MA/PJT 분할';
버튼의 위치 조정
$new_array = array();
$MyNewCustomCodeButton = "";
$new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][0](0.md); // EDIT
$new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][1](1.md); // DUPLICATE
$new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][2](2.md); // DELETE
$new_array[](.md) = array('customCode' => $MyNewCustomCodeButton);
$new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][3](3.md); // quote2opp
$new_array[] = $this->dv->defs['templateMeta']['form']['buttons'][4](4.md); // quote2pdf
$this->dv->defs['templateMeta']['form']['buttons']('buttons'.md) = $new_array;
parent::display();
Field
Database에 없는 필드 추가
vi /custom/Extension/modules/$Module/Ext/Vardefs/custom_fileds.php
$dictionary[$Module]['fields'][$field]($field.md)= array(
'name' => '$field',
'vname' => 'LBL_$FIELD',
'type' => 'varchar',
'len' => '255',
'source' => 'non-db', //--- Database에서 관리되지 않는 필드임을 명시함
);
vi /custom/Extension/modules/$Module/Ext/LogicHooks/logichooks.custom.php
if (!isset($hook_array['process_record']('process_record'.md))) {
$hook_array['process_record']('process_record'.md) = Array();
}
$hook_array['process_record'][](.md) = Array(
count($hook_array['process_record']('process_record'.md)) + 1, 'Custom${Module}LogicHooks',
'custom/modules/$Module/Custom${Module}LogicHooks.php',
'Custom${Module}LogicHooks', 'ProcessRecord');
vi /custom/modules/$Module/Custom${Module}LogicHooks.php
ProcessRecord() 함수에서 $field의 값을 계산하여 저장함
$field의 값으로 html tag를 사용하여 이미지 등을 표시할 수 있음
vi /custom/modules/$Module/Dashlets/
/.data.php
$dashletData['MyCasesDashletWR']['columns']('columns'.md) = array(
'$field' => array(
'width' => '2',
'label' =>'',
'default' => true,
'sortable' => false,
),
);
Parent 선택 목록에 항목 추가
vi custom/Extension/application/Ext/Language/ko_KR.custom.php
$app_list_strings['parent_type_display']['da03_Voc']('da03_Voc'.md) = 'VOC';
$app_list_strings['record_type_display_notes']['da18_ProjHistory']('da18_ProjHistory'.md) = '프로젝트 작업내역';
선택목록 값 변경
vi custom/include/language/ko_KR.lang.php
$GLOBALS['app_list_strings']['sba__snbServiceContract__c_sba__Owner_Expiration_Notice__c_list']('sba__snbServiceContract__c_sba__Owner_Expiration_Notice__c_list'.md)=array (
'' => '',
'15 Days' => '15 Days',
'30 Days' => '30일 전',
'45 Days' => '45 Days',
'60 Days' => '60일 전',
'90 Days' => '90일 전',
'120 Days' => '120 Days',
);
선택목록 값 파싱
선택목록값 파싱 : $aField = unencodeMultienum($fieldValue);
선택목록값 생성 : encodeMultienumValue($arr);
선택목록 키에 특수문자 사용
선택목록 키에 한글 또는 공백 등을 사용하는 방법
vi modules/ModuleBuilder/javascript/SimpleList.js
//--- 78 line을 주석 처리
// addToValidate('dropdown_form', 'drop_name', 'error', false, SUGAR.language.get("ModuleBuilder", "LBL_JS_VALIDATE_KEY"));
//--- 102 line을 수정
// liObj.id = escape(drop_name.value);
liObj.id = drop_name.value;
ReadOnly Field
1안 : 자기 자신의 값을 할당하는 수식 필드로 선언
2안 : vi custom/Extension/modules/$Module/Ext/Vardefs/~.customReadOnly.php
$dictionary['$module']['fields']['$field']['readonly']('readonly'.md) = true;
Filed의 레이블 가져오기
$displayFieldValue = $GLOBALS['app_list_strings'][$bean->field_defs[$fieldname]['options'][$bean->$fieldname]]($bean->$fieldname].md);
//--- Multi-Select
$displayFieldValues = unencodeMultienum($bean->$fieldname);
array_walk($displayFieldValues, function($val) use($bean,$fieldname) {
$val = $GLOBALS['app_list_strings'][$bean->field_defs[$fieldname]['options'][$bean->$fieldname]]($bean->$fieldname].md);
});
의존 관계
vi custom/Extension/modules/$Modules/Ext/Vardefs/sugarfield_$field.php
$dictionary['Account']['fields']['fld_industrytype2_sf_c']['visibility_grid']('visibility_grid'.md) = array (
'trigger' => 'fld_industrytype1_sf_c',
'values' => array (
'parent_value' => array (
0 => 'chield_value1',
2 => 'chield_value2',
);
),
);
관계(Relate) 필드명 확인
query 문
select distinct custom_module
from fields_meta_data;
select name, type, ext2, ext3
from fields_meta_data
where custom_module = 'Opportunities'
and type = 'relate';
vi include/SugarFields/Fields/Relate/SugarFieldRelate.php
vi [custom/]include/SugarFields/Fields/Relate/ko_KR.DetailView.tpl
Expression
수식 편집기
Module : ExpressionEngine, Action : editFormula
vi jssource/src_files/include/Expressions/javascript/expressions.js
vi jssource/src_files/modules/ExpressionEngine/javascript/formulaBuilder.js
vi include/Expressions/javascript/expressions.js
vi include/Expressions/javascript/sugar_expressions.php
vi modules/ExpressionEngine/javascript/formulaBuilder.js
롤업 필드 삽입
Module : ExpressionEngine, Action : rollupWizard
예) rollupSum($reports_to_link, "sp_master_sf_c")
관련 필드 삽입
Module : ExpressionEngine, Action : selectRelatedField
예) related($accounts,"field19_sf_c")
수식 편집기에서 함수 정의
include/Expressions/Expression/
/Expression.php 파일에서 getOperationName()가 함수의 이름을 반환함include/Expressions/updatecache.php 파일이 cache/Expressions/functionmap.php 파일을 생성
관련 모듈/필드 처리
SUGAR.forms.AssignmentHandler.getRelatedField(linkField, 'rollupSum', relField);
vi modules/ExpressionEngine/controller.php 파일의 action_getRelatedValues() 함수에서 처리
두 날자의 일자 차이를 구하는 함수
abs(subtract(daysUntil($datefieldA),daysUntil($datefieldB)))
Parameter
vi include/Expressions/Expression/Parser/Parser.php : evaluate() 함수가 전달하는 Parameter를 생성
vi include/Expressions/Expression/Generic/SugarFieldExpression.php : Sugar 필드의 경우 전달되는 Parameter 객체
Custom Expression
custom/include/Expressions/Expression/$returnType/~Expression.php 파일 생성
cache/Expressions 폴더 삭제
require_once("include/Expressions/Expression/String/StringExpression.php");
/**
* 이 Expression에 대한 도움말을 여기에 작성 합니다.
*
* subStr(String s, Number from, Number length)
* Returns length characters starting at 0-based index from.
* ex: subStr("Hello", 1, 3) = "ell"
*/
class SubStrExpression extends StringExpression
{
//--- PHP로 Expression을 실행하고 그 결과를 반환 합니다.
//--- $param = $this->getParameters()->evaluate(); //--- Parameter 1개
//--- $params = $this->getParameters(); //--- Parameter 여러개
//--- $param1 = $params[0](0.md)->evaluate();
//--- $paramCnt = $this->getParamCount(); //--- -1, 0, 1, ...
//--- return ~
function evaluate() {
}
//--- JavaScript Expression을 실행하고 그 결과를 반환하는 코드를 문자열로 반환 합니다.
//--- var param = this.getParameters().evaluate(); //--- Parameter 1개
//--- var params = this.getParameters(); //--- Parameter 여러개
//--- var param1 = params[0](0.md).evaluate();
//--- return ~
static function getJSEvaluate() {
}
//--- Expression의 이름을 반환 합니다.
static function getOperationName() {
}
//--- Parameter의 type또는 type 배열을 반환 합니다.
static function getParameterTypes() {
}
//--- Parameter의 갯수를 반환 합니다.
static function getParamCount() {
}
function toString() {
}
}
Custom Validation
방안 1 : JavaScript로 오류 처리를 합니다.
vi custom/modules/Opportunities/metadata/editviewdefs.php
'includes'=> array( array( 'file'=>'custom/modules/Opportunities/checkOpportunitiesDate.js'), ),
JavaScript file
addtovalidate(form name,field name, type, mandatory,your message); to validate your field, I guess you have one validation name should be addtovalidateDateBefore().
document.EditView.phone_work.onblur
방안 2 : 테스트 필요
custom/include/MVC/Controller/SugarController.php 파일을 생성 합니다.
handle_action() 함수에서 오류가 발생하면 다음 처리를 하지 않고 넘어가도록 수정 합니다.
pre_save() 함수에서 validation check를 합니다.
오류가 발생하면 오류메시지 저장후 view를 edit로 변경하고 pre_edit(), action_eidt(), post_edit()를 수행하고 다음으로 넘어가도록 합니다.
참고 문헌
Custom Mask
Sugar Field Control 생성
require_once('modules/Import/Forms.php');
$obj= BeanFactory::getBean($Module);
echo getControl($Module, $field, $obj->getFieldDefinition($field), "");
customCode
vi custom/modules/$Module/metadata/detailviewdefs.php
'customCode' => '<span style="color: red">{$fields.interest_c.value}</span>'
array (
'name' => 'date_modified',
'label' => 'LBL_DATE_MODIFIED',
'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}',
),
vi custom/modules/$Module/metadata/editviewdefs.php
array (
'name' => 'first_name',
'customCode' => '{html_options name="salutation" id="salutation" options=$fields.salutation.options selected=$fields.salutation.value}'
. ' ',
),
vi custom/modules/$Module/metadata/listviewdefs.php
'PHONE_WORK' => array (
'width' => '15%',
'label' => 'LBL_OFFICE_PHONE',
'default' => true,
'related_fields' =>
array (
0 => 'extended_phone_c', //--- 추가로 사용할 필드명, 소문자로
),
'customCode' => '{$PHONE_WORK} | {$EXTENDED_PHONE_C}', //--- 필드명은 대문자로
),
custom/modules/Opportunities/views/view.detail.php
$this->dv->defs['templateMeta']['form']['buttons']('buttons'.md) = array('EDIT', 'DUPLICATE', 'DELETE',
array('customCode'=>''),
array('customCode'=>'')
);
amount_usdollar
amount_usdollar에는 환율이 반영된 기본 통화의 금액이 저장 됩니다.
예) amount에 1$가 저장될 경우, 환율 1000원이 반영되어 amount_usdollar에는 1000 이 저장 됩니다.
금액 필드 오른쪽 정렬
vi [custom/]include/SugarFields/Fields/Currency/ko_KR.DetailView.tpl, EditView.tpl, ListView.tpl, WirelessDetailView.tpl 파일을 수정하여 변경할 수 있습니다.
Relate 관계
Standard Relate 관계 Records
1:1 relate 관계 : Master record 가져오기
1:1 relate 관계 : Slave record 가져오기
1:n relate 관계 : Master record 가져오기
1:n relate 관계 : Slave records 가져오기
n:m relate 관계 : Master records 가져오기
$relationshipName 확인 방법
방안 1 : rollupSum($relationshipName, $field) 함수에서 첫번째 인수값
방안 2 : vi modules/$Module/vardefs.php 파일에서 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름을 relationship으로 가지는 것의 name
type이 link이고 relationship이 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름과 같은 필드의 name
'quotes' => array (
'name' => 'quotes',
'type' => 'link',
'relationship' => 'quotes_opportunities',
'source'=>'non-db',
'vname'=>'LBL_QUOTES',
),
- 방안 3 : DB Query 사용, lhs_module 필드값의 소문자 사용 (추가 확인 필요)
load_relationship 함수에 전달하는 인수는 아래 query에서 relationship_name을 사용 합니다.
select relationship_name, relationship_type, lhs_module, lhs_key, join_key_lhs,
rhs_module, rhs_key, join_key_rhs
from relationships
where lhs_module = '$masterModule'
and rhs_module = '$slaveModule'
order by relationship_type, relationship_name;
$relationshipName으로 데이터 가져오기
$data = $newBean->get_linked_beans('quotes', 'Quote');
n:m relate 관계 : Slave records 가져오기
Custom Relate 관계 Records
1:1 relate 관계 : Master record 가져오기
1:1 relate 관계 : Slave record 가져오기
1:n relate 관계 : Master record 가져오기
1:n relate 관계 : Slave records 가져오기
$relationshipName 확인 방법
방안 1 : "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름
방안 2 : rollupSum($relationshipName, $field) 함수에서 첫번째 인수값
방안 3 : vi custom/modules/$Module/Ext/Vardefs/vardefs.ext.php
type이 link이고 relationship이 "작업실 -> $Module -> 관계" 메뉴에서 표시되는 이름과 같은 필드의 name
방안 4 : DB Query 사용, relationship_name 필드값 사용
load_relationship 함수에 전달하는 인수는 아래 query에서 relationship_name을 사용 합니다.
select relationship_name, relationship_type, lhs_module, lhs_key, join_key_lhs,
rhs_module, rhs_key, join_key_rhs
from relationships
where lhs_module = '$masterModule'
and rhs_module = '$slaveModule'
order by relationship_type, relationship_name;
$relationshipName으로 데이터 가져오기
if (!isset($bean->$relationshipName)) {
$bean->load_relationship($relationshipName);
}
$data= $bean->$relationshipName->getBeans();
n:m relate 관계 : Master records 가져오기
n:m relate 관계 : Slave records 가져오기
참고 문헌
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']('LBL_$OTHERMODULE_$MODULE_1_FROM_$OTHERMODULE_TITLE'.md) = '연락처';
//--- $mod_strings['LBL_CONTACTS_DA05_OPPCONTACTROLE_1_FROM_CONTACTS_TITLE']('LBL_CONTACTS_DA05_OPPCONTACTROLE_1_FROM_CONTACTS_TITLE'.md) = '연락처';
모듈간 Relation 관계에서 필수 필드 선언
vi custom/Extension/modules/$Module/Ext/Vardefs/${othermodule}_${module}1${Module}.php
required 속성 추가
$dictionary["da05_OppContactRole"]["fields"]["contacts_da05_oppcontactrole_1_name"]("contacts_da05_oppcontactrole_1_name".md) = array (
'name' => 'contacts_da05_oppcontactrole_1_name',
'type' => 'relate',
'required' => true,
);
Related Module을 삭제
after_relationship_delete Logic Hook에서 호출
public function deleteRecord(&$bean, $event, $arguments)
{
if (($beanToDelete = BeanFactory::getBean($arguments['related_module'], $arguments['related_id']('related_id'.md))) === FALSE) {
return;
}
$beanToDelete->mark_deleted($beanToDelete->id);
}
Related 연결 추가 및 삭제
$opp = BeanFactory::getBean('Opportunities', $bean->opportunity_id);
$opp->load_relationship('opportunities_products_1');
$opp->opportunities_products_1->add($item->id);
$opp->opportunities_products_1->delete($bean->opportunity_id, $item->id);
Query문으로 관련 데이터 가져오기
function get_products()
{
// First, get the list of IDs.
$query = "SELECT product_id as id
from $this->rel_products
where bundle_id='$this->id' AND deleted=0 ORDER BY product_index";
return $this->build_related_list($query, new Product());
}
관계 이름 확인 방법
$linked_fields = $bean->get_linked_fields();
foreach($linked_fields as $name => $properties) {
$GLOBALS['log']('log'.md)->info('Start Logic Hooks : CustomOpportunitiesLogicHooks linked_fields - '.$name);
}
Relate 필드에서 버튼 삭제
vi custom/modules/$Module/metadata/editviewdefs.php
0 =>
array (
'name' => '',
'studio' => 'visible',
'label' => '',
'displayParams' => array('hideButtons' => true), //--- hideButtons를 true로 설정
),
Subpanel
Subpanel 파일 위치
Subpanel의 항목 정의 사항이 저장되는 파일
영업기회의 연락처 subpanel 변경시
custom/Extension/modules/Opportunities/Ext/Layoutdefs/_overrideOpportunity_subpanel_contacts.php
custom/modules/Contacts/metadata/subpanels/Opportunity_subpanel_contacts.php
$subpanel_layout['list_fields']('list_fields'.md) = array(
'name' => array (
'name' => 'name',
'vname' => 'LBL_LIST_NAME',
'widget_class' => 'SubPanelDetailViewLink',
'module' => 'Contacts',
'width' => '20%',
'default' => true,
),
);
Subpanel 정의 파일
modules/$module/metadata/subpaneldefs.php
custom/modules/$module/Ext/Layoutdefs/layoutdefs.ext.php
Subpanel 필터
Custom Subpanel
vi custom/Extension/modules/$Module/Ext/Layoutdefs/layoutdefs.custom.php
vi custom/modules/pn01_Organization/Ext/Layoutdefs/layoutdefs.ext.php
$layout_defs['pn01_Organization']['subpanel_setup']['teams']('teams'.md) = array(
'order' => 100,
'sort_by' => 'name',
'sort_order' => 'asc',
'title_key' => 'LBL_TEAMS',
'module' => 'Teams',
'subpanel_name' => 'default', //--- modules/Teams/subpanels/ 폴더 아래에 있는 파일명
'get_subpanel_data' => 'function:getUserTeams',
'generate_select' => true,
'top_buttons' => array(),
'function_parameters' => array(
'import_function_file' => 'custom/modules/$Module/customSubpanel.php',
'id' => $this->_focus->id,
'user_id' => $this->_focus->user_id_c,
'return_as_array' => 'true',
),
);
vi custom/modules/$Module/customSubpanel.php
function getUserTeams($params) {
// $bean = $GLOBALS['app']('app'.md)->controller->bean;
$user_id = $params['user_id']('user_id'.md);
$return_array['select']('select'.md) = ' SELECT teams.* ';
$return_array['from']('from'.md) = ' FROM teams ';
$return_array['where']('where'.md) = ' WHERE teams.id in (select b.team_id from team_memberships b where b.user_id = \''.$user_id.'\')';
$return_array['join']('join'.md) = '';
$return_array['join_tables']('join_tables'.md) = '';
return $return_array;
}
참고 문헌
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을 동적으로 관리
Multi-Select checkbox 삭제
display()
$this->lv->multiSelect = false;
ListView
ListView에 Duration Custom Code 추가
customCode를 활용하여 이미지 등 html 코드를 추가할 수 있음
vi ~listviewdefs.php
'DURATION' => array (
'type' => 'varchar',
'label' => 'LBL_DURATION',
'customCode' => '{$DURATION_HOURS}:{$DURATION_MINUTES}',
'width' => '10% ',
'default' => true,
'sortable' => false,
'related_fields' => array('duration_hours','duration_minutes'),
),
like search 대신 동일한 값 검색
$searchFields['<>']['<>']('<>'.md) = array(
'query_type' => 'default',
'operator' => '='
);
Debug
Sugar Logger 확장
vi include/SugarLogger/LoggerManager.php
Request로 showlog=true 가 요청이된 세션에서 모든 로그 표시
public function __call($method, $message)
{
if (isset($_REQUEST['showlog']('showlog'.md))) {
$_SESSION['showlog'] = ($_REQUEST['showlog']('showlog'.md) == 'true');
}
if ( !isset(self::$_levelMapping[$method]($method.md)) )
$method = $this->_level;
//if the method is a direct match to our level let's let it through this allows for custom levels
if (($method == $this->_level) ||
(isset($_SESSION['showlog']) && ($_SESSION['showlog']('showlog'.md) == true)) ||
(!empty(self::$_levelMapping[$method]) && self::$_levelMapping[$this->_level] >= self::$_levelMapping[$method]($method.md)) ) {
Trace Log 표시
vi config_override.php
$sugar_config['stack_trace_errors']('stack_trace_errors'.md) = true;
vi include/utils.php
set_error_handler('StackTraceErrorHandler'); 참조
참고 문헌
로그 메시지
$GLOBALS['log']('log'.md)->info('~');
$GLOBALS['log']('log'.md)->error('~');
$GLOBALS['log']('log'.md)->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][](.md) = array($order_idx, 'fts', $file, $class, $function);
$class = new $hook_class([]($this->bean,)$event, $arguments);
$class->$hook_function([]($this->bean,)$event, $arguments)
vi custom/Extenstion/module/$module/Ext/LogicHooks/logichooks.custom.php
if (!isset($hook_array['before_save']('before_save'.md))) {
$hook_array['before_save']('before_save'.md) = Array();
}
$hook_array['before_save'][](.md) = Array(
count($hook_array['before_save']('before_save'.md)) + 1, 'CustomAccountsLogicHooks',
'custom/modules/Accounts/CustomAccountsLogicHooks.php',
'CustomAccountsLogicHooks', 'BeforeSave');
vi custom/modules/$Module/Custom${Module}LogicHooks.php
/*
* $bean : Event가 발생한 모듈
* Old value : $bean->fetched_row['$field']('$field'.md)
* New value : $bean->$field
* $event : Event의 종류
* before_delete, after_delete / before_save, after_save / after_retrieve, process_record
* $arguments : Event에 따른 인수값
* array ( 'check_notify' => false, )
*
* 조건 체크
* after_save && $bean->fetched_row == false : 등록
* after_save && $bean->fetched_row == true : 수정
*/
Administration에 메뉴 추가
vi custom/Extension/modules/Administration/Ext/Administration/administration.custom.php
global $current_user,$admin_group_header;
$admin_group_header[4][3]['Administration']['ShowModule']('ShowModule'.md) = array(
'ConfigureTabs','LBL_SHOW_MODULE','LBL_SHOW_MODULE_DESC','./index.php?module=Administration&action=ShowModule'
);
SugarBean
SugarBean 가져오기
moduleName : include/modules.php 파일의 $moduleList 참조
data/BeanFactory.php
$bean = BeanFactory::newBean($module);
$bean = BeanFactory::getBean($module);
include/MVC/SugarModule.php
$sugarModule = SugarModule::get($module);
$bean = $sugarModule ->loadBean();
SugarBean item 가져오기
data/BeanFactory.php
모듈별 10개의 cache된 bean 관리
$bean = BeanFactory::getBean($module, $id);
data/SugarBean.php
$bean = $bean->getRelatedFields($module, $id, null, true);
SugarBean data 가져오기
$bean->load_relationship('opportunities_products_1');
$products = $bean->opportunities_products_1->getBeans();
SchedulersJob
//--- SchedulersJobs을 실행 합니다.
//--- $this->target = $method::$option
//--- $method
//--- function : modules/Schedulers/_AddJobsHere.php에 등록된 함수($option) 실행
//--- [custom/](custom/.md)modules/Schedulers/_AddJobsHere.php
//--- custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php
//--- link : 등록된 URL($option)을 호출하고 그 결과를 반환
//--- class : RunnableSchedulerJob를 구현한 class($option)를 실행
//--- custom/include/SugarQueue/SugarCrontJobs.php 에 추가 class를 정의할 것
Scheduler 추가
vi custom/Extension/modules/Schedulers/Ext/Language/ko_KR.custom.php
$mod_strings['LBL_CUSTOMSCHEDULER001']('LBL_CUSTOMSCHEDULER001'.md) = '수식 필드 일배치 갱신';
vi custom/Extension/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.custom.php
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
require_once('data/BeanFactory.php');
require_once('include/SugarDateTime.php');
require_once('include/TimeDate.php');
$job_strings[](.md) = 'CustomScheduler001'; //--- 새로 추가하는 스케쥴러 Task
function CustomScheduler001($data) {
$today = new DateTime();
$today->setDate(date("Y"), date("m"), date("d"));
$today->setTime(0, 0, 0);
$bean = BeanFactory::getBean('Contracts');
$data = $bean->get_full_list('', "'".$today->format('Y-m-d')."' < end_date or 0 < contract_days_sf_c");
foreach ($data as $item) {
CustomScheduler001_setDays($item, $today);
}
return true; //--- 반드시 true를 반환할 것
}
"관리자모드 -> 스케쥴러" 메뉴에서 위에서 추가한 기능을 스케쥴러로 등록
Scheduler를 사용하여 수식을 동적으로 갱신
수식을 동적으로 갱신
$module = "Quotes"; // Set the module where you calculated field is.
$order_by = ""; //
$where = ""; // If you want to filter the records to update, specify it here. See SugarBean->getFullList for docs on how to
require_once('include/utils.php');
require_once('include/export_utils.php');
$cnt = 0;
$moduleBean = BeanFactory::getBean($module);
$beanList = $moduleBean->get_full_list($order_by,$where);
if( $beanList != null ) {
foreach($beanList as $b) {
// These lines prevent the modified date and user from being changed.
$b->update_date_modified = false;
$b->update_modified_by = false;
$b->tracker_visibility = false;
$b->save();
$cnt++;
}
}
run_job
vi run_job.php
CLI 방식으로 호출되어 실행
run_job.php $jobId $clientId
$jobId : SchedulersJob의 ID
SchedulersJob에 등록된 해당 Job을 실행할 수 있는 Client ID
User에 Default Role 추가
SugarCharts
include/SugarCharts/
saved_reports 모듈
modules/Charts/
include/Dashlets/DashletGenericChart.php
SugarCharts Customize
vi include/SugarCharts/SugarChartFactory.php
$sugar_config'chartEngine' = 'Jit';
custom/include/SugarCharts/$chartEngine/${chartEngine}$Module.php, ${chartEngine}$Module class
vi custom/include/SugarCharts/Jit/JitReports.php
상속 관계
vi include/SugarCharts/Jit/Jit.php
vi include/SugarCharts/JsChart.php
vi include/SugarCharts/SugarCharts.php
함수
setData() : $this->data_set 에 데이터 저장
setProperties() : $this->chart_properties의 값 지정
generateXML() : XML 데이터 생성
saveXMLFile() : 생성된 XML 데이터를 파일로 저장 (cache/xml/~_saved_chart.xml)
display() : Chart를 화면에 표시
getChartResources() : Chart에서 사용할 JavaScript를 반환
include/SugarCharts/Jit/FlashCanvas/flashcanvas.js
include/SugarCharts/Jit/js/Jit/jit.js
include/SugarCharts/Jit/js/sugarCharts.js
vi include/SugarCharts/Jit/js/sugarCharts.js
loadSugarChart() 함수에 각 chart별 처리 로직이 구현되어 있음
SugarCharts의 종류
"bar chart", "group by chart", "stacked group by chart"
"horizontal"/"horizontal bar chart", , "horizontal group by chart"
"pie chart", "funnel chart 3D", "line chart", "gauge chart"
ChartConfigParams
chartType : barChart(막대), pieChart(원형), funnelChart(깔때기), lineChart(줄), gaugeChart(게이지)
orientation : virtical, horizontal
barType : basic, grouped, stacked
cache/xml/
_saved_chart.xml (는 report의 uid임) 파일의 구조420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.xml
//--- Chart의 Properties
//--- Chart를 위해 생성된 데이터
곽재용 과장
9
나인소프트
1
0
21
5
1
cache/xml/
_saved_chart.js (는 report의 uid임) 파일의 구조420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.js
{
"properties": [{
//--- Chart의 Properties
}],
"label": [~ ](),
"color": [~ ](),
"values": [{
"label": "곽재용 과장",
"values": [~ ](),
"valuelabels": [~ ](),
"links": [~](),
}],
}
cache/images/420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.png 파일
SugarCharts에 새로운 chartType 추가
JitReports.getChartResources() 함수에서 아래 JavaScript를 추가하도록 수정
vi custom/include/SugarCharts/Jit/js/sugarCharts.js 생성
보고서에서 Chart 사용
보고서 마법사
vi custom/modules/Reports/ReportsWizard.php
$sugarChart = SugarChartFactory::getInstance();
$resources = $sugarChart->getChartResources();
$sugar_smarty->assign('chartResources', $resources);
vi modules/Reports/templates/templates_reports.php
$sugarChart = SugarChartFactory::getInstance();
$resources = $sugarChart->getChartResources();
$smarty->assign('chartResources', $resources);
보고서
vi modules/Reports/templates/templates_chart.php
$sugarChart = SugarChartFactory::getInstance('','Reports');
$sugarChart->setData($chart_rows);
$sugarChart->setProperties($chartTitle, '', $chartType, 'on', 'value', 'on', $do_thousands);
$xmlFile = get_cache_file_name($reporter);
$sugarChart->saveXMLFile($xmlFile, $sugarChart->generateXML());
echo $sugarChart->display($guid, $xmlFile, $width, $height, $reportChartDivStyle);
SugarCharts에 새로운 chartType 추가
vi custom/modules/Reports/ReportsWizard.php
$chart_types 에 새로운 chartType 추가
vi modules/Reports/templates/templates_reports.php
ReportsWizard.php 파일에서 template_reports_chart_options() 함수를 override 하는 방법 검토 필요
$chart_types 에 새로운 chartType 추가
vi modules/Reports/templates/templates_chart.php
ReportsWizard.php 파일에서 draw_chart() 함수를 override 하는 방법 검토 필요
draw_chart() 함수에서 새로운 chartType 처리 기능 추가
보고서에서 Chart 호출
var css = new Array();
css["gridLineColor"]("gridLineColor".md) = '#cccccc';
css["font-family"]("font-family".md) = 'Arial';
css["color"]("color".md) = '#000000';
var chartConfig = new Array();
chartConfig["orientation"]("orientation".md) = 'horizontal';
chartConfig["barType"]("barType".md) = 'stacked';
chartConfig["tip"]("tip".md) = 'name';
chartConfig["chartType"]("chartType".md) = 'barChart';
chartConfig["imageExportType"]("imageExportType".md) = 'png';
loadSugarChart('420b0a67-4227-7ab2-170a-51675cd154dc','cache/xml/420b0a67-4227-7ab2-170a-51675cd154dc_saved_chart.js',css,chartConfig);
SugarPDF
index.php?module=$Module&action=sugarpdf&sugarpdf=$pdfAction
include/MVC/View/views/view.sugarpdf.php
custom/modules/$Module/views/view.sugarpdf.php
$pdfAction : smarty (Defalut), 이 값을 사용하여 다양한 양식의 PDF 문서를 작성할 수 있습니다.
include/Sugarpdf/sugarpdf/sugarpdf.$pdfAction.php
custom/modules/
/sugarpdf/sugarpdf.$pdfAction.php
Sugarpdf
include/Sugarpdf/Sugarpdf.php
include/tcpdf/tcpdf.php
Header(), Setfont(), Cell(), getNumLines()
predisplay(), display(), process(), writeCellTable(), writeHTMLTable()
Chart
vi custom/Charts/chartDefs.ext.php
Global 설정
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']('default_limit'.md) = 1000;
$sugar_config['resource_management']['special_query_limit']('special_query_limit'.md) = 50000;
$sugar_config['resource_management']['special_query_modules'][](.md) = 'Opportunities';
성능 개선
vi config_override.php
$sugar_config['disable_count_query']('disable_count_query'.md) = true;
$sugar_config['verify_client_ip']('verify_client_ip'.md) = false;
$sugar_config['disable_vcr']('disable_vcr'.md) = true;
참고 문헌
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/2012/09/19/using-the-sugar-external-cache-api/
http://developers.sugarcrm.com/wordpress/2012/09/18/speeding-up-sugar-using-an-external-cache/
권한 설정
vi data/SugarBean.php
add_team_security_where_clause() 함수에서 user id에 해당하는 데이터만 가져오도록 query문에 where 조건을 설정 합니다.
활용 방안
이슈 1 : 모듈별 데이터에 대한 공유 설정을 지원하지 않음
이슈 2 : 관리자가 데이터에 대한 공유 설정을 할 수 있는 기능이 없음
활용
team_memberships 테이블에 모듈 필드를 추가함, 이 필드에 값이 있을 경우 관리자가 설정한 공유 설정임
조직도를 추가하고 관리자가 설정할 수 있는 공유 설정 화면을 추가함
Java에서 RESTful 함수 사용
.htaccess를 사용한 custom 설정
세션 이름 변경
php_value session.name TEST
참고 문헌
SugarCache
sugar_cache_put($key,$mod_strings);
$return_result = sugar_cache_retrieve($key);
SugarTheme
테마에서 이미지 또는 JavaScript 파일을 찾는 순서
[custom/](custom/.md)themes/$imagePath/images/$imageName
[custom/](custom/.md)themes/$parentTheme_imagePath/images/$imageName
[custom/](custom/.md)themes/default/images/$imageName
include/images/$imageName
MultiLanguage
$app_strings
$lang : en_us, $sugar_config->default_language, $language
include/language/$lang.lang.php, $lang.lang.override.php, $lang.lang.php.override
custom/application/Ext/Language/$lang.lang.ext.php
custom/include/language/$language/$lang.lang.php
$mod_strings
$lang : en_us, $sugar_config->default_language, $language
include/SugarObjects/templates/$template/language/$lang.lang.php
include/SugarObjects/implements/$template/language/$lang.lang.php
modules/$module/language/$lang.lang[.override](.override.md).php
custom/modules/$module/Ext/Language/$lang.lang.ext.php
custom/modules/$module/language/$lang.lang.php
$mod_list_strings
modules/$module/language/en_us.lang.php
modules/$module/language/$language.lang[.override](.override.md).php, $language.lang.php.override
$theme_strings
$lang : $language, $sugar_config->default_language
themes/$theme/language/$lang.lang[.override](.override.md).php, $lang.lang.php.override
notify template file
[custom/](custom/.md)include/language/$language.notify_template.html
[custom/](custom/.md)include/language/en_us.notify_template.html
TimeDate
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']('authenticationClass'.md) : 'SugarAuthenticate'));
//--- $this->authController = custom/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php
//--- $this->userAuthenticate = custom/modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php
SugarController.execute().process().callLegacyCode()
modules/Users/Authenticate.php
$authController.login($user_name, $password);
SugarAuthenticate.loginAuthenticate($username, $password, false, $PARAMS);
SugarAuthenticateUser.loadUserOnLogin($username, $password, $fallback, $PARAMS).authenticateUser($name, $input_hash, $fallback)
User::findUserPassword($name, $password, ~).checkPasswordMD5($password, $row['user_hash']('user_hash'.md))
검색에서 담당자명 정렬
vi include/utils.php 파일의 758 라인을 수정
get_user_array 함수
// $query = $query.' ORDER BY user_name ASC';
$query = $query.' ORDER BY last_name ASC';
Custom Files
QuickCreateModules : custom/modules/Emails/metadata/qcmodulesdefs.php
View
custom/modules/$Module/metadata/editviewdefs.php
vi custom/Charts/chartDefs.ext.php
vi modules/Charts/chartdefs.php
vi custom/Charts/$chart.php
custom/$dashletDirectory$dashletClassname/$dashletClassname$current_language.lang.php
custom/Extension/application/Ext/TableDictionary/, custom/application/Ext/TableDictionary/
custom/backup/
초대자 추가하기
"회의일정"의 초대자 추가하기 관련 파일
vi modules/Meetings/jsclass_scheduler.js
지원하는 Cache
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
Cases에서 거래처(account_name)를 필수 필드에서 삭제
vi config_override.php
$sugar_config['require_accounts']('require_accounts'.md) = false;
Sugar 버그
화면이 깨어지고 Ajax 오류 창이 표시됨
원인 : CentOS에 설치된 PHP 라이브러리의 버전이 달라 문제가 발생 합니다.
vi jssource/Minifier.php 파일의 158 라인
// $this->input = preg_replace('/\h/u', ' ', $this->input);
$this->input = preg_replace('/[\t]()/u', ' ', $this->input);
"Admin -> Repair -> Repair JS Files" 실행
cache/ 폴더의 파일을 모두 삭제
Home 화면에서 Dashlet의 탭이 계속 실행중으로 표시됨
cache/xml/ 폴더를 apache:apache 권한으로 생성을 합니다.
한글로 모듈 목록 검색시 빈화면 표시
현상 : AJAX 목록 화면에서 한글로 검색시 화면이 표시되지 않고 또한 한글이 깨어짐
vi include/ListView/ListViewData.php 파일의 529 라인
// $queryString = htmlentities($_REQUEST[$field_name]($field_name.md));
$queryString = htmlentities($_REQUEST[$field_name]($field_name.md), null, "UTF-8");
메일 발송시 보낸 사람 이름
vi modules/Emails/Email.php 파일에서 851 라인
근본적으로 해결을 하려면 $mail->FromName 값이 MIME으로 인코딩 되었을 경우에만 decode를 하도록 수정할 것
// $this->from_addr_name = $this->from_addr;
$this->from_addr_name = "{$mail->FromName} <{$mail->From}>";
의존 관계에서 Drag-Drop 오류
현상 : 상위 선택목록에 따른 하위 선택목록 구성시 오류 발생
원인 : 상위 선택목록의 값으로 JavaScript에서 index를 사용함으로 인한 오류
해결 방안 : 값과는 별개로 index를 관리하여야 함
vi custom/modules/ModuleBuilder/views/view.depdropdown.php
vi custom/modules/ModuleBuilder/tpls/depdropdown.tpl
ACLAction 오류
오류 메시지 : FATAL Error evaluating expression: Non-static method ACLAction::getUserAccessLevel() should not be called statically, assuming $this from incompatible context
조치 방법
vi modules/ACLActions/ACLAction.php 파일의 365라인
// function getUserAccessLevel($user_id, $category, $action,$type='module'){
public static function getUserAccessLevel($user_id, $category, $action,$type='module'){
PDF 생성시 암호를 물어볼 경우
vi /etc/php.ini
[mbstring](mbstring.md)
mbstring.language = UTF-8
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
;mbstring.http_output = UTF-8 //--- 이 라인을 지우고
mbstring.http_output = pass //--- 이 라인을 추가 하세요
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none
Sugar 개선
Relate 필드에서 필드명 표시
vi modules/DynamicFields/templates/Fields/Forms/relate.tpl
기능 추가
자동 번호 필드
vi custom/modules/DynamicFields/templates/Fields/TemplateAutoincrement.php
vi custom/modules/DynamicFields/templates/Fields/Forms/autoincrement.php
vi custom/modules/DynamicFields/templates/Fields/Forms/autoincrement.tpl
vi custom/include/SugarFields/Fields/Autoincrement/SugarFieldAutoincrement.php
vi custom/include/SugarFields/Fields/Autoincrement/EditView.tpl
vi custom/Extension/modules/DynamicFields/Ext/Language/ko_KR.Autoincrement.lang.php
vi custom/Extension/modules/ModuleBuilder/Ext/Language/ko_KR.Autoincrement.lang.php
Core 소스 수정 사항
vi modules/ExpressEngine/formulaHelper.php
vi data/SugarBean.php
updateCalculatedFields() 함수 최상단에
SugarFieldAutoincrement::saveBean($this); 추가
LogicHooks 등에서 자동번호 필드값을 설정하고 싶은 경우
위에서 SugarBean.php를 수정하였을 경우에는 사용할 필요가 없습니다.
require_once('include/SugarFields/SugarFieldHandler.php');
$quote = BeanFactory::getBean('Quotes');
$field = 'no_c';
$sugarField = SugarFieldHandler::getSugarField($quote->field_defs[$field]['type']('type'.md));
$sugarField->save($quote, array($field => ''), $field, $quote->field_defs[$field]($field.md));
Multi-Layout 지원
구현 방안
Record별로 recordType 저장
사용자별로 모듈별 사용할 수 있는 레코드 타입을 저장
초기 레코드 생성시 사용자가 사용할 수 있는 레코드 타입이 2개 이상이면 레코드 타입을 선택하는 화면을 표시
일반 모듈에서 Layout (metadata/~viewdefs.php) 지정 방법
include/MVC/View/views/view.detail.php 파일에서 getMetaDataFile() 함수 호출
결론 : include/MVC/View/SugarView.php, getMetaDataFile() 함수에서 metadata 파일명을 반환
$this->module, $this->type 정보와 $this->bean 정보를 사용하여 metadataFile명을 지정
대안 : custom/modules/$Module/metadata/metafiles.php 파일을 수정하여 구현 가능
Studio에서 Layout 지정 방법
modules/ModulerBuilder/controller.php, action_editLayout() 함수에서 $this->view에 작업할 view 이름 지정
Parameter : 'view_module' => 'Accounts', 'view' => 'editview'
modules/ModulerBuilder/views/view.layoutview.php
$this->type = $this->sm->getViewType($this->editLayout);
modules/ModuleBuilder/Module/StudioModule.php, getViewType() 함수가 type을 반환
$this->editModule, $this->editLayout 를 사용하여 type 지정
결론 : 아래 두 파일의 getFileName()에서 반환하는 Layout (metadata/~viewdefs.php) 파일을 사용
modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation
modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation
$view , $moduleName , $packageName를 사용하여 파일명 확인 가능
이번 주 검색 지원
보고서와 화면에서 "지난 주", "이번 주", "다음 주" 검색 조건을 추가 합니다.
보고서
vi custom/Extension/modules/Reports/Ext/Language/ko_KR.custom.php
vi modules/Reports/language/ko_KR.lang.php
$mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md) = '지난 주';
$mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md) = '이번 주';
$mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md) = '다음 주';
vi modules/Reports/templates/templates_modules_def_js.php
qualifiers[qualifiers.length] = {name:'tp_last_week',value:''};
qualifiers[qualifiers.length] = {name:'tp_this_week',value:''};
qualifiers[qualifiers.length] = {name:'tp_next_week',value:''};
vi custom/include/generic/SugarWidgets/SugarWidgetFielddatetime.php
function displayInput(&$layout_def) 수정
'TP_last_week' => $home_mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md),
'TP_this_week' => $home_mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md),
'TP_next_week' => $home_mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md),
function queryFilterTP_last_week($layout_def) 생성
function queryFilterTP_last_week($layout_def)
{
global $timedate;
$end = new SugarDateTime();
switch ($end->format('w')) { //--- 0. 일요일, 1. 월요일, ...
case '1' : $end->add(new DateInterval("P6D")); break;
case '2' : $end->add(new DateInterval("P5D")); break;
case '3' : $end->add(new DateInterval("P4D")); break;
case '4' : $end->add(new DateInterval("P3D")); break;
case '5' : $end->add(new DateInterval("P2D")); break;
case '6' : $end->add(new DateInterval("P1D")); break;
case '0' :
default :
break;
}
$begin = clone $end;
$begin = $begin->sub(new DateInterval("P13D"))->get_day_begin();
$end = $end->sub(new DateInterval("P7D"))->get_day_end();
return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
}
function queryFilterTP_this_week($layout_def) 생성
function queryFilterTP_this_week($layout_def)
{
global $timedate;
$end = new SugarDateTime();
switch ($end->format('w')) { //--- 0. 일요일, 1. 월요일, ...
case '1' : $end->add(new DateInterval("P6D")); break;
case '2' : $end->add(new DateInterval("P5D")); break;
case '3' : $end->add(new DateInterval("P4D")); break;
case '4' : $end->add(new DateInterval("P3D")); break;
case '5' : $end->add(new DateInterval("P2D")); break;
case '6' : $end->add(new DateInterval("P1D")); break;
case '0' :
default :
break;
}
$begin = clone $end;
$begin = $begin->sub(new DateInterval("P6D"))->get_day_begin();
$end = $end->get_day_end();
return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
}
function queryFilterTP_next_week($layout_def) 생성
function queryFilterTP_next_week($layout_def)
{
global $timedate;
$end = new SugarDateTime();
switch ($end->format('w')) { //--- 0. 일요일, 1. 월요일, ...
case '1' : $end->add(new DateInterval("P6D")); break;
case '2' : $end->add(new DateInterval("P5D")); break;
case '3' : $end->add(new DateInterval("P4D")); break;
case '4' : $end->add(new DateInterval("P3D")); break;
case '5' : $end->add(new DateInterval("P2D")); break;
case '6' : $end->add(new DateInterval("P1D")); break;
case '0' :
default :
break;
}
$begin = clone $end;
$begin = $begin->add(new DateInterval("P1D"))->get_day_begin();
$end = $end->add(new DateInterval("P7D"))->get_day_end();
return $this->get_start_end_date_filter($layout_def,$begin->asDb(),$end->asDb());
}
고급검색
vi custom/Extension/application/Ext/Language/ko_KR.custom.php
vi include/language/ko_KR.lang.php
$app_list_strings['date_range_search_dom']['last_week']('last_week'.md) = '지난 주';
$app_list_strings['date_range_search_dom']['this_week']('this_week'.md) = '이번 주';
$app_list_strings['date_range_search_dom']['next_week']('next_week'.md) = '다음 주';
$app_list_strings['kbdocument_date_filter_options']['last_week']('last_week'.md) = '지난 주';
$app_list_strings['kbdocument_date_filter_options']['this_week']('this_week'.md) = '이번 주';
$app_list_strings['kbdocument_date_filter_options']['next_week']('next_week'.md) = '다음 주';
vi include/SearchForm/SearchForm2.php
generateSearchWhere()
case 'last_week':
case 'this_week':
case 'next_week':
vi include/TimeDate.php
parseDateRange()
case 'next_week':
return $this->diffWeek(1, $user, $adjustForTimezone);
case 'last_week':
return $this->diffWeek(-1, $user, $adjustForTimezone);
case 'this_week':
return $this->diffWeek(0, $user, $adjustForTimezone);
diffWeek() 생성
protected function diffWeek($mdiff, User $user = null, $adjustForTimezone = true)
{
global $timedate;
$end = new SugarDateTime();
switch ($end->format('w')) { //--- 0. 일요일, 1. 월요일, ...
case '1' : $end->add(new DateInterval("P6D")); break;
case '2' : $end->add(new DateInterval("P5D")); break;
case '3' : $end->add(new DateInterval("P4D")); break;
case '4' : $end->add(new DateInterval("P3D")); break;
case '5' : $end->add(new DateInterval("P2D")); break;
case '6' : $end->add(new DateInterval("P1D")); break;
case '0' :
default :
break;
}
$begin = clone $end;
$begin->sub(new DateInterval("P6D"));
if ($mdiff == 1) {
$begin->add(new DateInterval("P7D"));
$end->add(new DateInterval("P7D"));
}
if ($mdiff == -1) {
$begin->sub(new DateInterval("P7D"));
$end->sub(new DateInterval("P7D"));
}
$begin = $begin->get_day_begin();
$end = $end->get_day_end();
return array($begin, $end);
}
미확인 항목
vi custom/Extension/modules/Home/Ext/Language/ko_KR.custom.php
vi modules/Home/language/ko_KR.lang.php
$mod_strings['LBL_LAST_WEEK']('LBL_LAST_WEEK'.md) = '지난 주';
$mod_strings['LBL_THIS_WEEK']('LBL_THIS_WEEK'.md) = '이번 주';
$mod_strings['LBL_NEXT_WEEK']('LBL_NEXT_WEEK'.md) = '다음 주';
Sugar Tip
자신만의 로그 보기
vi include/SugarLogger/LoggerManager.php
214 라인 아래에 다음을 추가 합니다.
} else {
if (isset($_REQUEST['showlog']('showlog'.md))) {
if ($_REQUEST['showlog']('showlog'.md) == 'true') {
$_SESSION['showlog']('showlog'.md) = true;
} else {
$_SESSION['showlog']('showlog'.md) = false;
}
}
if (isset($_SESSION['showlog']('showlog'.md))) {
if ($_SESSION['showlog']('showlog'.md) == true) {
$logger = (!empty(self::$_logMapping[$method])) ? self::$_logMapping[$method] : self::$_logMapping['default']('default'.md);
if (!isset(self::$_loggers[$logger]($logger.md))) {
self::$_loggers[$logger]($logger.md) = new $logger();
}
self::$_loggers[$logger]($logger.md)->log($method, $message);
}
}
회의일정에 사용자 초대 화면이 보이지 않을 경우
화면에 "기간" 필드를 추가 하세요.
백업 파일 확장자
Upgrade 등을 할 경우, layout은 ~.suback.php 확장자를 가진 파일로 백업 됩니다.
예)custom/modules/Contacts/metadata/detailviewdefs.php.suback.php
지원 업체
{{지원업체}}
[[Category:오픈소스|Category:오픈소스]]
[[Category:CRM|Category:CRM]]
[[Category:한글화|Category:한글화]]
[[Category:Sugar|Category:Sugar]]
분류: WebSite