SugarCRM

오픈소스 비즈니스 컨설팅
둘러보기로 가기 검색하러 가기

오픈소스로 제공되는, On-Premise/On-Demand/Appliance 방식의 CRM인 sugarCRM (Sugar Community Edition)을 소개한다.

  • 홈페이지

Document

  • 기술지원

관리자 가이드

로그 설정

  • 로그 파일
  • $SUGAR_HOME/include/SugarLogger/LoggerManager.php
  • $SUGAR_HOME/include/SugarLogger/SugarLogger.php
  • $SUGAR_HOME/config.php에서 로그 설정
log_dir : 로그가 저장되는 폴더
log_file : 로그 파일명, 초기값은 "sugarcrm.log"
log_memory_usage :
logger => level : 로그 레벨 (debug, info, error, fatal, security, off)
logger => file
ext : 로그 파일 확장자, 초기값은 ".log"
name : 로그 파일명, 초기값은 "sugarcrm"
dateFormat : 날자 포맷
maxSize : 로그 파일 최대 크기
maxLogs : 로그 파일 최대 갯수
suffix : 로그 파일 뒤에 붙는 문자열, 초기값은 "%m_%Y"
  • 프로그램에서 로그 남기기
$GLOBALS['log']->debug('로그 메시지');
$GLOBALS['log']->info('로그 메시지');

License 표시 변경

  • vi include/MVC/View/SugarView.php
  • 666 라인에 있는 $copyright 를 변경 한다.

한글팩 제작

SugarCRM의 한글팩을 만들기 위해 en_us 언어로 부터 ko_kr 파일을 추출하여 한글 언어팩을 작성 한다.

  • 한글팩 작성을 위한 폴더 생성
mkdir /tmp/sugar            #--- 다운로드 받은 SugarCE-6.1.1.zip의 압축을 여기에 푼다.
mkdir /tmp/sugar_ko_kr 
  • ant를 사용하여 언어로 부터 한글 파일을 복사하기 위한 build 파일을 만든다.
  • vi /tmp/sugar_ko_kr/build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="sugar" default="init" basedir=".">
   <property name="dirSugar" value="/tmp/sugar" />
   <property name="dirSugarKoKr" value="/tmp/sugar_ko_kr" />


   <target name="init">
       <copy todir="${dirSugarKoKr}">
           <fileset
               dir="${dirSugar}"
               includes="**/en_us.*.html, **/en_us.lang.php, **/*.en_us.lang.php, 
                         **/*.en_us.php, **/en_us.*.tpl, **/*.lang-en.php, 
                         **/en.js, **/en_dlg.js"
               excludes="cache/**/*"
           />
       </copy>

       <move todir="${dirSugarKoKr}">
           <fileset
               dir="${dirSugarKoKr}"
               includes="**/en_us.*.html, **/en_us.lang.php, **/*.en_us.lang.php, 
                         **/*.en_us.php, **/en_us.*.tpl, **/*.lang-en.php, 
                         **/en.js, **/en_dlg.js"
           />
           <filtermapper>
               <replacestring from="en_us" to="ko_kr" />
               <replacestring from="en_us.lang.php" to="ko_kr.lang.php" />
               <replacestring from="en_us.php" to="ko_kr.php" />
               <replacestring from="lang-en.php" to="lang-ko.php" />
               <replacestring from="en.js" to="ko.js" />
               <replacestring from="en_dlg.js" to="ko_dlg.js" />
           </filtermapper>
       </move>
   </target>
</project>
  • 영어 파일을 복사하여 한글 파일로 이름만 변경 한다. (위에서 만든 build.xml 파일 사용)
cd /tmp/sugar_ko_kr
ant init
  • vi /tmp/sugar_ko_kr/manifest.php
<?php
$manifest = array(
       'acceptable_sugar_versions' => array (
               'exact_matches' => array(),
               'regex_matches' => array (
                       0 => "6\.6\.1.*"
               ),
       ),
       'acceptable_sugar_flavors' => array (
               0 => 'CE',
               1 => 'PRO',
               2 => 'ENT',
       ),
       'name'                  => 'Korean Language Pack',
       'description'           => 'Korean Language Pack',
       'author'                => 'pnuskgh',
       'published_date'        => '2011/01/23',
       'version'               => '0.1',
       'type'                  => 'langpack',
       'icon'                  => ,
       'is_uninstallable'      => true,
);

$installdefs = array(
       'id'=> 'langpack_ko_kr', 

       'copy' => array(
               array('from'=> '<basepath>',
                         'to'=> '.',
               ),
       ),
);
?>
  • SugarCRM 한글팩(langpack_ko_kr.zip) 작성
  • /tmp/sugar_ko_kr/ 폴더에 있는 파일을 열어 열심히 한글로 번역 한다.
  • /tmp/sugar_ko_kr/ 폴더의 내용을 묶어 langpack_ko_kr.zip 파일을 작성 한다.

한글 설치 프로그램 제작

  • vi /install.php 파일을 다음과 같이 수정 한다.
$supportedLanguages = array(
   'ko_KR' => 'Korea - 한국어',  //--- 이 라인을 추가 한다.
   'en_us' => 'English (US)',

$default_lang = 'ko_KR';          //--- 디폴트로 ko_KR을 지정 한다.
  
  • /install/language/ko_KR.lang.php 파일을 작성 한다.
  • /install/demoData.ko_KR.php 데모 데이터 파일을 작성 한다.

테마 구조

Dashlet

  • 참고 문헌

SOAP/REST

wsdl2java.bat -o . -p com.sugar http://cloud.smartprocess.co.kr/testEnt/service/v4/soap.php?wsdl
  • SugarsoapLocatior.java
//    private java.lang.String sugarsoapPort_address = "http://cloud.smartprocess.co.kr/testEnt/service/v4/soap.php";
   private java.lang.String sugarsoapPort_address = Config.getString("sugar.serverurl", "http://cloud.smartprocess.co.kr/testEnt/") + "service/v4/soap.php";
  • SugarsoapBuindingStub.java
public static String SugarServerurl = Config.getString("sugar.serverurl", "http://cloud.smartprocess.co.kr/testEnt/") + "service/v4/soap.php";
_call.setSOAPActionURI(SugarsoapBindingStub.SugarServerurl + "/login");
  • SugarsoapBuindingStub.java 함수
public com.sugar.Entry_value login(com.sugar.User_auth user_auth, java.lang.String application_name, com.sugar.Name_value[] name_value_list)
public void logout(java.lang.String session)
public com.sugar.Get_entry_result_version2 get_entry(java.lang.String session, java.lang.String module_name, java.lang.String id, 
   java.lang.String[] select_fields, com.sugar.Link_name_to_fields_array[] link_name_to_fields_array, boolean track_view)
public com.sugar.Get_entry_result_version2 get_entries(java.lang.String session, java.lang.String module_name, java.lang.String[] ids, 
   java.lang.String[] select_fields, com.sugar.Link_name_to_fields_array[] link_name_to_fields_array, boolean track_view)
public com.sugar.Get_entry_list_result_version2 get_entry_list(java.lang.String session, java.lang.String module_name, java.lang.String query, 
   java.lang.String order_by, int offset, java.lang.String[] select_fields, com.sugar.Link_name_to_fields_array[] link_name_to_fields_array, 
   int max_results, int deleted, boolean favorites)
public com.sugar.New_set_relationship_list_result set_relationship(java.lang.String session, java.lang.String module_name, 
   java.lang.String module_id, java.lang.String link_field_name, java.lang.String[] related_ids, com.sugar.Name_value[] name_value_list, int delete)
public com.sugar.New_set_relationship_list_result set_relationships(java.lang.String session, java.lang.String[] module_names, 
   java.lang.String[] module_ids, java.lang.String[] link_field_names, java.lang.String[][] related_ids, com.sugar.Name_value[][] name_value_lists, int[] delete_array)
public com.sugar.Get_entry_result_version2 get_relationships(java.lang.String session, java.lang.String module_name, java.lang.String module_id, 
   java.lang.String link_field_name, java.lang.String related_module_query, java.lang.String[] related_fields, 
   com.sugar.Link_name_to_fields_array[] related_module_link_name_to_fields_array, int deleted, java.lang.String order_by)
public com.sugar.New_set_entry_result set_entry(java.lang.String session, java.lang.String module_name, com.sugar.Name_value[] name_value_list)
public com.sugar.New_set_entries_result set_entries(java.lang.String session, java.lang.String module_name, com.sugar.Name_value[][] name_value_lists)
public com.sugar.Get_server_info_result get_server_info()
public java.lang.String get_user_id(java.lang.String session)
public com.sugar.New_module_fields get_module_fields(java.lang.String session, java.lang.String module_name, java.lang.String[] fields)
public int seamless_login(java.lang.String session)
public com.sugar.New_set_entry_result set_note_attachment(java.lang.String session, com.sugar.New_note_attachment note)
public com.sugar.New_return_note_attachment get_note_attachment(java.lang.String session, java.lang.String id)
public com.sugar.New_set_entry_result set_document_revision(java.lang.String session, com.sugar.Document_revision note)
public com.sugar.New_return_document_revision get_document_revision(java.lang.String session, java.lang.String i)
public com.sugar.Return_search_result search_by_module(java.lang.String session, java.lang.String search_string, java.lang.String[] modules, 
   int offset, int max_results, java.lang.String assigned_user_id, java.lang.String[] select_fields, boolean unified_search_only, boolean favorites)
public com.sugar.Module_list get_available_modules(java.lang.String session, java.lang.String filter)
public java.lang.String get_user_team_id(java.lang.String session)
public void set_campaign_merge(java.lang.String session, java.lang.String[] targets, java.lang.String campaign_id)
public com.sugar.Get_entries_count_result get_entries_count(java.lang.String session, java.lang.String module_name, java.lang.String query, int deleted)
public com.sugar.Get_entry_result_for_reports get_report_entries(java.lang.String session, java.lang.String[] ids, java.lang.String[] select_fields)
public java.lang.String[] get_module_fields_md5(java.lang.String session, java.lang.String[] module_names)
public com.sugar.Last_viewed_entry[] get_last_viewed(java.lang.String session, java.lang.String[] module_names)
public com.sugar.Upcoming_activity_entry[] get_upcoming_activities(java.lang.String session)

SugarCRM 아키텍처

사용 라이브러리

라이브러리 라이선스 상세 설명
Sugar Community Edition GNU GPL 3.0 오픈소스 CRM
tcpdf GNU LGPL 2.1 PDF 제작
phpmailer GNU LGPL 2.1 메일 발송
PHP_Compat PHP License 3.0
nusoap Free Web Services Toolkit for PHP
HTTP_WebDAV_Server PHP License 3.0 WebDAV 서버
HTML_Safe BSD style license
domit_rss Free DOM based RSS parser for PHP
domit Free DOM parser for PHP
Crypt_Blowfish PHP License 3.0
TreeView BSD License Javascript, Tree 형태의 항목을 표시
yui (Yahoo User Interface) BSD License Javascript, UI 모듈
tiny_mce GNU LGPL 2.1 Javascript,
Ext JS GNU LGPL 3.0 Javascript,
jscalendar GNU LGPL 3.0 Javascript, 달력

프로그램 호출 구조

  • module: /sugar/modules/Accounts/ 폴더에 있는 모듈이 사용됨
  • action::*/sugar/include/MVC/Controller/action_file_map.php 참조
  • /sugar/include/MVC/Controller/action_view_map.php 참조
  • 아래 정리된 범례. action_명 (view_명)
  • index:
  • DetailView (detail):
  • EditView (edit):
  • MultiEditView (multiedit):
  • Popup (popup):
  • Vcard (vcard):
  • ImportVcard (importvcard):
  • ImportVcardSave (importvcardsave):
  • SugarPdf (sugarpdf):
  • SaveTimezone
  • InitialSync
  • Logout
  • RetrieveEmail
  • view 명: ajax, classic, config, detail, edit, html, importvcard, importvcardsave, json, list, multedit, noaccess, popup, serialized, sidequickcreate, sugarpdf, vcard, xml
  • return_module
  • return_action
  • return_id:
  • id:
  • record:
  • view:
  • Delete:
  • entire:
  • mass:
  • type:
  • ie_assigned_user_id:
  • configure:
  • RTL:
  • LTR:
  • query_string:
  • module_tab:
  • parentTab:
  • popup:
  • lvso:
  • query:
  • displayColumns:
  • orderBy:
  • sortOrder:
  • entryPoint:
  • massupdate:
  • usertheme:
  • noThemeSave:
  • usercolor:
  • userfont:
  • userthemegrouptabs:
  • MSID:
  • 호출 URL에 따른 처리 프로그램
  • /sugar/include/MVC/Controller/SugarController.php#process();
  • /sugar/include/MVC/View/SugarView.php#process();
  • /sugar/modules/Accounts/views/view.view_명.php
  • /sugar/include/MVC/View/views/view.view_명.php
  • /sugar/modules/Accounts/ 폴더 구조
  • views/: Default. /sugar/include/MVC/View/views/
  • tpls/: Default. /sugar/include/MVC/View/tpls/
  • metadata/: 메타데이터
  • Dashlets/: 대쉬렛
  • SugarFeeds/: 피드
  • language/: 언어 파일, ko_KR.lang.php

디렉토리 구조

프로세스 구조

index.php를 분석하여 SugarCRM의 프로세스 흐름을 파악한다.

  • require_once('include/entryPoint.php')
  • require_once('config.php') : 환경 설정
  • require_once('config_override.php') : 환경 설정 개인화
  • require_once 'include/SugarObjects/SugarConfig.php' : SugarCRM 환경 설정
  • require_once('include/utils.php')
  • require_once('sugar_version.php');
  • require_once('include/database/PearDatabase.php');
  • require_once('include/database/DBManager.php');
  • require_once('include/database/DBManagerFactory.php');
  • require_once('include/dir_inc.php');
  • require_once('include/Localization/Localization.php');
  • require_once('include/javascript/jsAlerts.php');
  • require_once('include/TimeDate.php');
  • require_once('include/modules.php');
  • require_once('data/SugarBean.php');
  • require_once('include/utils/file_utils.php');
  • require_once('include/utils/mvc_utils.php');
  • require_once('include/SugarEmailAddress/SugarEmailAddress.php');
  • require_once('include/SugarLogger/LoggerManager.php');
  • require_once('modules/Trackers/BreadCrumbStack.php');
  • require_once('modules/Trackers/Tracker.php');
  • require_once('modules/Trackers/TrackerManager.php');
  • require_once('modules/ACL/ACLController.php');
  • require_once('modules/Administration/Administration.php');
  • require_once('modules/Administration/updater_utils.php');
  • require_once('modules/Users/User.php');
  • require_once('modules/Users/authentication/AuthenticationController.php');
  • require_once('include/utils/LogicHook.php');
  • require SUGAR_PATH . '/include/SugarObjects/SugarRegistry.php';
  • require_once('include/MVC/SugarApplication.php')
  • require_once('include/MVC/Controller/ControllerFactory.php')
  • require_once('include/MVC/Controller/SugarController.php') : 디폴터 Controller
  • require_once('include/MVC/View/SugarView.php');
  • require_once('modules/Administration/updater_utils.php');
  • $this->process();
  • $this->processView();
  • $view->process();
  • require_once('custom/modules/'.$module.'/controller.php') : 모듈별 사용자 정의 Controller
  • require_once('modules/'.$module.'/controller.php') : Module별 Controller
  • $controller = new SugarController() : 디폴터 Controller
  • require_once('include/MVC/View/ViewFactory.php')
  • require_once('include/MVC/View/SugarView.php');
  • 'custom/modules/'.$module.'/views/view.'.$type.'.php : 사용자 정의 모듈별 View
  • modules/'.$module.'/views/view.'.$type.'.php' : Module별 View
  • custom/include/MVC/View/views/view.'.$type.'.php : 사용자 정의 디폴트 View
  • include/MVC/View/views/view.'.$type.'.php : 디폴트 View
  • require_once('modules/Users/authentication/AuthenticationController.php')
  • $app->execute()
  • Request parameter : module, action, usertheme, MSID, entryPoint, massupdate
  • $this->controller = ControllerFactory::getController($module);
  • $this->controller->checkEntryPointRequiresAuth($_REQUEST['entryPoint'])
  • $this->loadUser();
  • $this->ACLFilter();
  • $this->preProcess();
  • $this->controller->preProcess();
  • $this->loadLanguages();
  • $this->checkDatabaseVersion();
  • $this->loadDisplaySettings();
  • $this->loadLicense();
  • $this->loadGlobals();
  • $this->setupResourceManagement($module);
  • $this->controller->execute();
  • sugar_cleanup();
  • require_once('include/resource/ResourceManager.php');
  • require_once ('modules/Sync/file_config.php');
  • require_once('modules/Sync/SyncController.php');
  • require_once('themes/'.$GLOBALS['theme'].'/layout_utils.php');

화면 구조

  • include/MVC/View/SugarView.php
  • $this->displayHeader();
  • Theme : header.tpl
_leftFormHiddenLastViewed.tpl
_leftFormHiddenShortcuts.tpl
   _leftFormHide.tpl
  • $this->preDisplay();
  • $this->displayErrors();
  • $this->display();
  • Module과 Action에 해당하는 template이 사용됨
  • $this->displaySubPanels();
  • $subpanel->display();
  • $this->displayFooter();
  • Theme : footer.tpl
  • Default Theme
  • Sugar <- default

Shortcut Menu

  • SugarCRM의 좌측 메뉴에 보여지는 Shortcut Menu (바로가기 메뉴)를 정리 한다.
  • /modules/모듈명/Menu.php 에 권한에 따른 바로 가기 메뉴가 정의 되어 있다.

동적 구조

  • Relate 변수
select name, type, ext2, ext3 
from fields_meta_data 
where custom_module = 'cases' 
 and type = 'relate';

select custom_module, name, type, len, required, ext1, ext2, ext3, ext4 
 from fields_meta_data 
where custom_module = 'Campaigns'
order by name;
  • relationship
desc relationships;

문제 해결

  • Sugar 화면이 깨어지고 Ajax 관련 오류 창이 표시됨
CentOS에 설치된 PHP 라이브러리의 버전이 달라 문제가 발생 합니다. 

- jssource/Minifier.php 파일 수정
//--- 158 line, pnuskgh
// $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 권한으로 생성을 합니다.

Localization

한글팩 작성

  • Localization 범위
  • 한글 번역, 이미지 등 한글화
  • 어순 : 성 이름
  • 날짜, 시간
  • 다중 통화 (Currency)
  • 주소


  • PHP 파일 번역
  • ko_KR.lang.php
  • ~Dashlet.ko_KR.lang.php
  • demoData.ko_KR.php
  • phpmailer.lang-ko.php
  • Template 파일 번역
  • LotusLiveSignup.ko_KR.tpl
  • footer.tpl
  • JavaScript 파일 번역
  • ko.js, ko_dlg.js
  • calendar.js, calendar-min.js
  • HTML 파일 번역
  • ko_KR.notify_template.html
  • ko_KR.Portal.html
  • 이미지 파일을 gimp를 사용하여 새로 작성
  • PDF 파일에서 한글이 깨어짐
  • TCPDF에서 hysmyeongjostdmedium.php 파일을 다운로드
  • include/tcpdf/fonts/ 폴더에 복사
  • "Admin -> Repair -> Quick Repair and Rebuild" 메뉴 실행
  • 개인별 Profile에서 PDF Settings을 다음과 같이 설정
  • Font for Header and Body : MyungJo Medium (Korean)
  • Font for Footer : MyungJo Medium (Korean)
  • vi include/Sugarpdf/sugarpdf_default.php
  • helvetica를 MyungJo Medium (Korean)로 변경 합니다. (미확인 사항)
'PDF_FONT_NAME_MAIN'=>'helvetica',
'PDF_FONT_NAME_DATA'=>'helvetica',
  • TCPDF에 ttf 폰트 추가 (실패)
  • 나눔글꼴을 다운로드 합니다.
  • http://www.xml-convert.com/en/convert-tff-font-to-afm-pfa-fpdf-tcpdf 사이트에서 ttf2ufm.exe 파일을 다운로드 합니다.
  • ttf2ufm.exe ~.ttf 명령을 사용하여 ~.ufm 파일을 생성 합니다.
  • /include/tcpdf/fonts/utils/makefont.php 파일을 수정하여 nanumgothiccoding.php, nanumgothiccoding.z, nanumgothiccoding.ctg.z 파일을 생성 합니다.
  • php -q makefont.php NanumGothicCoding.ttf NanumGothicCoding.ufm
  • 생성된 파일을 /include/tcpdf/fonts/ 폴더에 복사 합니다.

주소

  • Address Localization
  • include/SugarFields/Fields/Address/ko_KR.DetailView.tpl, ko_KR.EditView.tpl

한글로 모듈(거래처) 목록 검색

  • AJAX 목록 화면에서 한글로 검색시 화면이 표시되지 않음
include/ListView/ListViewData.php 파일의 529 라인에서
$queryString = htmlentities($_REQUEST[$field_name]);을 아래와 같이 변경함
$queryString = htmlentities($_REQUEST[$field_name], null, "UTF-8");

메일 발송시 보낸 사람 이름

  • 메일 발송시 보낸 사람 이름이 깨어짐
modules/Emails/Email.php 851 line
From : $this->from_addr_name = $this->from_addr;
To   : $this->from_addr_name = "{$mail->FromName} <{$mail->From}>";
  • 근본적으로 해결을 하려면 $mail->FromName 값이 MIME으로 인코딩 되었을 경우에만 decode를 하도록 수정할 것

Tips

참고 문헌

  • 기타 오픈소스 CRM


지원 업체

SuiteCRM을 사용한 영업관리, 고객관리는 아래 담당자에게 연락하여 주시면, 빠르고 친절하게 전문적인 답변을 드리겠습니다.

영업 문의 sales@obcon.biz 010-4667-1106 영업 대표
기술 문의 tech@obcon.biz 구축/컨설팅 담당
고객 지원 support@obcon.biz 고객 지원 담당

OBCon 홈페이지 바로가기