Quick Start
다보리-컴포저블을 처음 사용하는 사용자에게 필요한 정보 안내
- 1장. 설치하기
- Ownerkey 발급하기
- env.dabory의 이해
- 다보리 DB API 와 DB 연결 방법
- 프론트엔드 설치하기 (Docker)
- 웹서버/웹호스팅에 설치하는 방법
- 더미테마(Dummy-Theme)설치 방법
- 운영테마(Production-Theme)설치방법
- Dabory Linux 서버 SSH를 통한 로그인 방법
- xampp를 통한 설치방법
- 2장. Restfull API 구성
- 3장. Frontend 기반 구조
- 4장. Parameter 기반 개발
- 5장. 실행 메뉴와 권한 관리
- 6장. 테마 커스터마이징
- 테마 설치하기
- git 서버와 Standard/theme 폴더 동기화
- theme 폴더 및 .env 변수 동기화
- 프로 테마 커스터마이징하기
- 서버에 테마를 반영하는 방법
- Api23KeyPair를 활용한 통신 가이드
- Theme 개발시 네이밍 규칙
- 7장. 쿼리 커스터마이징
- 8장. 커스텀 테이블 사용방법
- 기타
1장. 설치하기
Ownerkey 발급하기
Ownerkey란?
다보리앱은 main app과 guest app이 존재합니다. ownerKey를 공유하면 host app과 guest app간의 api 공유가 가능합니다.
OwnerKey 사용 예시
main app : 본점 A
guest app : 지점 B
지점 B는 본점 A의 api를 사용할 수 있습니다.
1. 지점 B에서 회원리스트 조회시 본점 A의 회원리스트를 조회합니다.
2. 지점 B에서 신규회원 회원가입시 본점 A의 회원리스트로 추가됩니다. (회원리스트를 본점 A의 DB로만 사용할 경우)
3. 본점 A에서 새로운 상품추가시 본점 B의 삼품리스트에 추가됩니다. (상품리스트를 본점 A의 DB로만 사용할 경우)
OwnerKey 발급방법
Ownerkey를 사용하기 위해서는 guest app을 등록하여 OwnerKey를 발급받아야 합니다.
1. main app을 등록한 dabory 계정으로 로그인합니다.
2. guest app 등록을 위해서 My App 메뉴를 클릭합니다.
3. 좌측 메뉴에서 App Manager를 클릭합니다.
4. 등록한 app중 Owner key를 공유할 app을 클릭합니다.
5. GuestApp 탭을 클릭합니다.
6. a부터 c까지 입력 및 선택합니다.
ⓐ Guest App Name : Owner Key의 이름
ⓑ OwnerCode : Owner Key의 제한방식
- owner : 모든 api 허용
- keypair :
- dbupdate :
- limited : 일부 api만 허용
ⓒ AppType : guest app의 type
7. Download .owner-key 버튼을 클릭하여 Owner key를 download 합니다.
8. MainApp 탭을 누른뒤 save 버튼을눌러 저장합니다.
9. 생성된 .owner-key를 확인하고 frontend 소스코드를 open합니다.
10. .env 파일에 MAIN_API_OWNER_KEY 변수를 추가하고 생성된 owner key의 값을 넣어줍니다.
env.dabory의 이해
env.dabory
env.dabory는 Laravel의 설정파일인 env 파일을 확장하여 API 서버와 db 연동을 위해 추가적으로 사용되는 연동용 설
정파일입니다.
2. 서버와 db 연동과정
Frontend에서 백엔드 서버에 API를 요청할 때 env.dabory 파일을 참조합니다. 여기에서 api url은 요청을 보낼 API 서버를 결정하며, 특정 API를 호출하기 위해서는 해당 API 서버에서 발급한 GateToken이 필요합니다.
GateToken을 발급받기 위해서는 ClientId, ClientSecret, BeforeBase64의 값이 다보리 SSO에 등록된 DB 접속 정보와 일치해야 합니다. 즉, DB와의 연동이 인증되지 않으면 GateToken을 발급받을 수 없습니다. 이러한 변수들을 활용하여 지정된 API 서버에 요청하면, 해당 서버로부터 GateToken을 반환받아 이후 API 호출에 사용할 수 있습니다.
이처럼 GateToken을 중심으로 한 인증 절차를 통해 다보리 앱에서 main app과 guest app 간의 보안성을 유지하면서도 원활한 데이터 연동과 API 호출이 가능합니다.
3. env.dabory의 주요 변수 설명
다보리 DB API 와 DB 연결 방법
해당사항은 먼저 2장 Restfull api의 구성 1번 메뉴얼을 숙지하시고 확인해주시기 바랍니다.
2장 1번 메뉴얼에서 언급한바와 같이 clientId와 beforebase64가 담긴 json type의 데이터를 통해 API 서버를 호출하게되면 api 서버에서 response로 gate token을 생성하여 반환합니다.
이 gate token은 .env.dabory 파일 생성시 입력된 db 접속정보가 암호화되어 있기 때문에 .env.dabory 파일에 설정이 되어 있고 App Manger에 등록되어 있다면 반환받은 gate-token을 통해 연동된 db api에 연결이 가능합니다.
프론트엔드 설치하기 (Docker)
아래 단계에 따라 DC 프론트엔드 설치를 진행하세요:
1. DC 프론트엔드 설치본(Docker)을 다운로드하려면 제공된 다운로드 링크를 클릭하여 dc-demo-frontend-docker.tar.gz
파일을 다운로드합니다.
2. 다운로드가 완료되면 dc-demo-frontend-docker.tar.gz
파일을 DC를 설치할 디렉토리로 이동합니다. 예를 들어, 설치할 디렉토리를 /path/to/install
로 정했다면, 다음 명령어를 사용해 파일을 이동할 수 있습니다.
mv ~/Downloads/dc-demo-frontend-docker.tar.gz /path/to/install
3. 설치 디렉토리로 이동한 후, tar
명령어를 사용해 압축을 해제합니다:
cd /path/to/install
tar -xzvf dc-demo-frontend-docker.tar.gz
압축 해제가 완료되면 demo
디렉토리가 생성됩니다.
4. 생성된 demo
디렉토리로 이동합니다:
cd demo
5. demo
디렉토리에는 다음과 같은 파일과 디렉토리가 포함되어 있습니다:
dbrerp : DC의 표준 ERP 소스 디렉토리입니다. ERP와 관련된 코드 및 리소스가 포함되어 있습니다.
docker-compose.yml : DC의 Docker 컨테이너 설정 파일입니다. 이 파일에는 컨테이너 구성, 포트 매핑, 볼륨 설정 등이 정의되어 있습니다.
php-docker : PHP 버전별 설정 및 Dockerfile이 포함된 디렉토리입니다. 프로젝트에서 사용할 PHP 환경을 설정하는 데 사용됩니다.
5. 설치가 완료되면 docker-compose.yml
파일을 사용해 Docker 컨테이너를 실행하여 DC 프론트엔드를 배포합니다. 실행 명령어는 다음과 같습니다:
docker-compose up -d
6. Docker 컨테이너가 실행되면, docker-compose.yml
에 설정된 포트로 웹 브라우저를 통해 접속할 수 있습니다. 기본적으로 아래 주소를 사용합니다:
-
사용자 페이지 (Pro 페이지):
http://localhost:8028 -
관리자 페이지:
http://localhost:8028/dabory/erp
이제 DC 프론트엔드가 정상적으로 실행되며, 사용자 페이지와 관리자 페이지를 사용할 수 있습니다.
웹서버/웹호스팅에 설치하는 방법
설치전 준비사항
0. dabory git server에 사용자를 등록합니다. (다보리 git server 바로가기)
1. .env 파일
2. .env.dabory 파일
3. php와 mariadb의 설치
참고자료
웹서버/웹호스팅을 통한 설치방법
1. ssh을 통해 웹서버에 접근합니다.
2. 설치할 디렉토리를 생성하고 해당 디렉토리로 이동합니다.
3. 예제에서는 eyemsg 라는 테마폴더를 설치할 것이기 때문에 설치 경로에 아래와 같이 디렉토리를 구성하겠습니다.
- eyemsg.daboryhostcom
- kloxoscript
- public_html
각 디렉토리에 대한 설명은 아래에서 진행하겠습니다
4. 다보리 git 서버에서 mybin 레포지토리로 접속합니다. (mybin 바로가기)
5. HTTP url을 복사합니다.
6. 설치경로에서 git clone을 통해 mybin을 받아옵니다.
git clone http://git.daboryhost.com:10880/dabory/mybin
이제 다음과 같이 디렉토리들이 구성되었습니다.
5. eyemsg.daboryhost.com 디렉토리로 이동합니다.
cd eyemsg.daboryhost.com
6. 다보리 깃서버에 dbrerp 레포지토리로 접속합니다.
7. HTTP url을 복사해줍니다.
8. git clone 명령어를 통해 dbrerp 소스를 가져옵니다.
git clone http://git.daboryhost.com:10880/dabory/dbrerp.git
9. 아래 명령어를 통해 dbrerp의 하위 경로에 있는 모든 파일들을 eyemsg.daboryhost.com의 하위 경로로 이동시킵니다
mv dbrerp/* .
10. 사전에 준비해두었던 .env 파일과 .env.dabory 파일을 생성한뒤 내용을 붙여넣어줍니다.
이 부분이 숙지가 안되었다면 위 참고자료를 통해 env와 env.dabory 파일을 세팅해주세요.
vi .env
vi .env.dabory
11. dabory 디렉토리로 이동합니다.
cd dabory
12. 아래 링크를 클릭하여 theme 폴더를 설치한뒤 13번부터 진행해주시기 바랍니다.
13. 다보리 git 서버의 vendor 레포지토리로 접속합니다.
14. git clone을 통해 vendor 소스를 가져옵니다.
git cloen http://git.daboryhost.com:10880/dabory/vendor.git
15. storage 관련 Update 예정
16. eyemsg.daboryhost.com으로 접근하면 다음과 같이 설치가 완료되었습니다.
참고자료
- 홈페이지 위젯 설정하기
- 홈페이지
더미테마(Dummy-Theme)설치 방법
.env 항목에서 DBR_THEME 변수에 erponly를 넣어줍니다. erponly는 테마는 /pro로 들어오는 경로로 들어오는 모든 트래픽을 user page로 redirection시켜주는 테마입니다.
/dabory/themes 디렉토리로 이동한뒤 git clone erponly url 명령어를 통해 theme 소스코드를 가져옵니다. 반드시 변수의 이름과 테마 폴더 이름을 변수 값으로 동기화해야 합니다. 디렉토리 관련해서는composer 디렉토리에 autoload_psr4 파일에 각 디렉토리들을 namespace로 구성하여 관리되고 있으니 참고하시기 바랍니다.
운영테마(Production-Theme)설치방법
-
운영테마(Production-Theme)설치방법
.env파일에서 ERP_THEME, PRO_THEME 변수를 찾아 확인합니다. 변수의 이름과 테마 폴더 이름을 변수 값으로 동기화해야 합니다. /themes/pro 폴더 임폴트 (수정 예정)
Dabory Linux 서버 SSH를 통한 로그인 방법
사전준비
1. .ussh 파일 (ssh를 통해 편리하게 접근하기 위한 셸 스크립트 파일입니다.)
2. dbr_list.txt 파일 (개발자가 직접 생성합니다.)
2-1. 아래 내용을 입력합니다.
#서버코드 #IP #설치지역
dbr02=13.124.2.254 #erics-and-kloxo
* dbr02서버는 예시입니다. 서버가 다를 수 있기 때문에 미리 확인하시고 진행하시기 바랍니다.
2-2. ussh 파일이 있는 디렉토리에서 dbr_list.txt 라는 이름으로 텍스트 파일을 생성하고 2-1의 내용을 붙여넣어줍니다.
ussh를 통한 서버 접근방법
1. ussh 파일이 준비되었다면 해당위치로 이동합니다.
2. 아래 명령어를 통해 서버에 접근합니다.
./ussh dbr02 eyemsg
# ./ussh 서버이름 계정명
xampp를 통한 설치방법
설치전 준비사항
1. xampp 링크를 통해 xampp를 다운로드합니다.
2. More Downloads 클릭
3. 자신의 OS에 맞는 버전을 선택합니다. 예제는 window 버전으로 설치하겠습니다.
4. 7.3 ~8.0 까지의 php 버전을 호환하는 버전을 설치합니다. 예제는 7.3.33버전을 설치하겠습니다.
5. 포터블 버전이 아닌 일반 버전의 installer.exe를 클릭하여 설치합니다.
6. 다운로드된 설치파일을 클릭하여 설치를 진행합니다.
7. env/env.dabory 파일 세팅
xampp를 통한 설치방법
window 기준으로 설치를 진행한 예제입니다.
1. XAMPP Control Pannel을 관리자권한으로 실행합니다.
2. xampp는 기본 80포트 / 443 포트로 실행됩니다. 포트 충돌이 일어난다면 httpd.conf / httpd-ssl.conf / Config에서 포트를 변경해줍니다.
3. Apache 서버를 실행합니다. 만약 실행이 안된다면 아래와 같이 화살표버튼을 클릭하여 Apache를 재설치합니다.
4. 서버가 실행되었다면 터미널을 열어줍니다.
5. 아래 명령어를 통해 다보리 컴포터블의 dbrerp를 받아옵니다.
cd htdocs
git clone http://git.daboryhost.com:10880/dabory/dbrerp.git
6. 아래 명령어를 통해 필요한 파일들을 받아옵니다.
# vendor
cd dbrerp
git clone http://git.daboryhost.com:10880/dabory/vendor.git
# erponly
cd dabory
mkdir themes
git clone http://git.daboryhost.com:10880/dbrerp-themes/erponly.git
7. 이제 localhost:port번호로 접근합니다.
8. 만약 특정 에러가 발생한다면
- env 혹은 env.dabory 파일 확인
- vendor 혹은 storage 파일 확인
- xampp apache 서버의 설정파일 확인 (public 경로설정)
- 테마폴더의 존재 및 위치 확인
위 사항들을 체크해보시기 바랍니다.
2장. Restfull API 구성
Gate Token 개념
인증 & OAuth 2.0
인증이란 특정 사용자가 본인임을 확인하는 절차를 의미합니다. 일반적으로 아이디와 비밀번호가 일치하면 해당 사용자가 본인이라고 판단할 수 있습니다. 예를 들어, 다보리에 로그인할 때 다보리 계정의 아이디와 비밀번호를 입력하여 본인 여부를 확인하는 방식입니다.
하지만, 다보리 오픈API를 활용하여 개발한 애플리케이션에서 사용자가 다보리 계정의 아이디와 비밀번호를 직접 입력하도록 하면 보안상의 위험이 발생할 수 있습니다. 이를 방지하기 위해, 사용자가 제 삼자가 만든 애플리케이션이 아닌 **공식 인증 서비스(예: 네이버 로그인 페이지)**에서 직접 인증을 진행하고, 그 결과를 애플리케이션에 전달하는 방식이 필요합니다.
이러한 인증 방식을 체계적으로 정리한 표준이 OAuth이며, 다보리 오픈API는 OAuth 2.0 프로토콜을 적용하여 안전한 인증 서비스를 제공하고 있습니다.
Gate Token
dabory sso(OAuth2 기반)을 통해 사용자가 인증되면 이후 GateToken을 사용하여 API 서버와 DB에 연동할 수 있습니다. GateToken 자체는 사용자 인증을 담당하지 않고, 로그인 이후 인증된 사용자의 권한을 기반으로 API 및 DB 접근을 관리하는 역할을 합니다.
다보리 Frontend에서는 로그인 체크 이전에 session에 저장된 gatetoken을 check합니다. 만약 gatetoken이 존재하지 않는다면 main_api server로 부터 gatetoken을 발급받습니다. 즉 gatetoken은 app등록시 입력된 db 접근정보와 api server와의 정상적인 연동 권한을 갖췄는지 체크하기 위해 사용되는 암호화된 토큰입니다.
api 서버로부터 반환받은 GateToken은 프론트엔드 session에 저장됩니다. 이 session은 권한이 필요한 모든 프론트엔드 요청의 header에 포함됩니다.
다보리 API 설계의 기본 지식
HTTP Method 및 보안성:
- 다보리 ERP의 모든 API는 단순성과 보안성을 고려하여 POST method만 사용합니다.
- 이는 데이터 변경 및 전송의 안정성을 보장할 수 있습니다.
DaborySSO 및 환경 변수:
- DaborySSO를 사용하여 API 서버에 인증 및 권한 관리를 권장하지만 필요에 따라 Key Pair를 API 서버의 환경 변수에 저장하여 SSO 서버와 독립적으로 사용할 수 있습니다.
GateToken:
- 모든 API 요청은 API 서버로부터 반환받은 GateToken을 포함해야 합니다. 이를 통해 인증 및 권한 부여가 이루어집니다.
- GateToken은 타켓 DB의 접근 정보를 PKI 암호화한 BeforeBase64 Key로만 발급받을 수 있습니다. 이는 데이터 보안을 강화합니다.
- 모든 Frontend Server는 ClientID 값을 가집니다. 이는 DaborySSO에서 App 레코드를 생성하는 과정에서 생성됩니다.
- Client(Frontend)의 GateToken은 API 서버의 메모리 DB에 저장됩니다. 또한 유효기간 설정이 가능합니다. 이를 통해 인증된 클라이언트만이 API를 사용할 수 있도록 합니다.
이러한 설계 원칙을 준수하여 안전하고 효율적인 API 시스템을 구축할 수 있습니다.
3장. Frontend 기반 구조
.env 의 구조
.env 파일 세팅 예제
참고자료
Lavavel .env 기본 메뉴얼(https://laravel.kr/docs/5.7/configuration)
Lavavel .env Example(https://zetawiki.com/wiki/라라벨_.env,_.env.example)
# [Dabory]
ERP_THEMES=테마명입력 (해당 테마 설치후 입력)
LOCALE_SEQUENCE=다국어 사용 목록
APP_MOBILE_NO=아직 사용X
TAG_LINE=아직 사용X
CDN_TYPE=미디어 CDN (aws-s3 or local)
MEDIA_URL=미디어 base url 지정(미디어가 local or a3)
FAVICON_PATH=파비콘 파일 path
IS_SKIP_DBUPDATE=DBUPDATE 스킵 or 사용
IS_ON_MEMBER_SIGNUP=아직 사용X
## [MetaMask]
CHAIN_ID=0xE67B
CHAIN_NAME='Dang Smart Chain'
RPC_URLS=http://3.38.62.211:8545
NATIVE_CURRENCY_NAME=DGT
NATIVE_CURRENCY_SYMBOL=DGT
NATIVE_CURRENCY_DECIMALS=18
BLOCK_EXPLORER_URLS=https://explorer-staging.dangnn.co.kr
### [asset & cache]
BROWSER_CACHE=브라우저 캐시사용 (개발단계에서 false)
CSSJS_URL=local or asset url 입력 (개발단계에서 local)
### [Printer]
REPORT_SERVER_URL=프린터 서버 base url
### [Laravel]
APP_NAME=앱 이름
APP_ENV=.env 기본 메뉴얼 참고
APP_KEY=base64:.env 기본 메뉴얼 참고
APP_DEBUG=.env 기본 메뉴얼 참고
APP_URL=앱 url
LOG_CHANNEL=stack
LOG_LEVEL=debug
DB_CONNECTION=사용x
DB_HOST=사용x
DB_PORT=사용x
DB_DATABASE=사용x
DB_USERNAME=사용x
DB_PASSWORD=사용x
BROADCAST_DRIVER=사용x
CACHE_DRIVER=사용x
FILESYSTEM_DRIVER=사용x
QUEUE_CONNECTION=사용x
SESSION_DRIVER=사용x
SESSION_LIFETIME=사용x
MEMCACHED_HOST=사용x
REDIS_HOST=사용x
REDIS_PASSWORD=사용x
REDIS_PORT=사용x
MAIL_MAILER=.env 기본 메뉴얼 참고
MAIL_HOST=.env 기본 메뉴얼 참고
MAIL_PORT=.env 기본 메뉴얼 참고
MAIL_USERNAME=.env 기본 메뉴얼 참고
MAIL_PASSWORD=.env 기본 메뉴얼 참고
MAIL_ENCRYPTION=.env 기본 메뉴얼 참고
MAIL_FROM_ADDRESS=.env 기본 메뉴얼 참고
MAIL_FROM_NAME=.env 기본 메뉴얼 참고
AWS_ACCESS_KEY_ID=.env 기본 메뉴얼 참고
AWS_SECRET_ACCESS_KEY=.env 기본 메뉴얼 참고
AWS_DEFAULT_REGION=.env 기본 메뉴얼 참고
AWS_BUCKET=.env 기본 메뉴얼 참고
AWS_USE_PATH_STYLE_ENDPOINT=.env 기본 메뉴얼 참고
PUSHER_APP_ID=사용x
PUSHER_APP_KEY=사용x
PUSHER_APP_SECRET=사용x
PUSHER_APP_CLUSTER=사용x
MIX_PUSHER_APP_KEY=사용x
MIX_PUSHER_APP_CLUSTER=사용x
ANALYTICS_UA_ID=
ANALYTICS_VIEW_ID=
ANALYTICS_G_ID=
ANALYTICS_PROPERTY_ID=
.env.dabory 와 Gate Token
제 2장 Rest Api의 구성(https://manual.dabory.com/books/frontend-tutorial/chapter/restfull-api)에서 Gate Token에 대한 내용을 다뤘으니 참조하시고 해당 장을 숙지하시면 이해하는데 도움이 됩니다.
참고사항
- [ KeyPair/PublicKey 등을 를 생성하는 일반적인 PHP Code
]- [Sodium 사용 Ajax 제공 (260~262 Lines)]
- [ DB 정보 암호화 how to use it in PHP (254~263 Lines)]
(http://git.daboryhost.com:10880/dabory/dbrerp/src/master/resources/views/front/dabory/pro/my-app/popup/popup-form1/form-a/client-app-form.blade.php).dabory Gate Token(DGT)
- 로그인한 유저가 유저페이지에 접근합니다.
- 백엔드 서버에서
secret_key
와key_pair
를 통해서 해당 업체의 db를 생성합니다. (erp_center_db, erp_memory_db, erp_individual_dbs) - 프론트엔드서버에 생성된 db를 제공합니다.(driver, host, username, database, passwd, public_key) -> client config
- 유저가 메뉴나 링크를 클릭합니다.
[DGT 생성과정 시작]
- 백엔드 api 서버에 DGT를 요청합니다.
- api 서버에서 프론트엔드에서 보낸 사용자의 client config를 통해 랜덤한 20자의 문자열을 생성하고 Sodium을 통해 암호화합니다.
- 백엔드에서 DGT를 생성하여 저장하고 status 200, DGT를 반환합니다.
- 프론트엔드에서 반환받은 DGT를 세션에 저장합니다.
- 만약 DGT가 존재하지 않는다면 DGT를 받아오는 과정이 생략됩니다.
[Main Request]
- 이제 프론트엔드에서 보낸 모든 요청에 DGT가 포함되어 요청합니다.
[DCS 생성과정 시작]
- 백엔드에서는 DGT를 통해 DCS를 생성하여 반환합니다.
- 만약 memory_db에 저장된 DGT가 존재하지 않는다면 DCS를 받아오는 과정이 생략됩니다.
- 검증된 DCS를 통해 사용자 DB(erp databases)의 모델에 접근합니다.
- 사용자 db로부터 요청한 data를 얻고 반환합니다.
[요청 끝]
다보리 Frontend 폴더 구조
Frontend 구조(표준)
주요 디렉토리 설명
dabory
디렉토리는 다보리의 중요한 구성 요소로, 관리자 및 ERP 사용자 메뉴를 커스터마이징 할 수 있도록 설정하는 디렉토리입니다.
para
: 이 디렉토리에는 관리자가 설정할 수 있는 다양한 ERP 사용자 메뉴와 시스템 설정 파일들이 JSON 형식으로 저장됩니다. 이러한 파일들을 통해 ERP 시스템의 메뉴 구성, 권한 관리, 기타 관리 설정 등을 유동적으로 수정이 가능합니다.
themes
: 다보리의 프론트엔드 테마를 커스터마이징 할 수 있는 디렉토리입니다. 각 사이트별로 제공되는 테마를 개별적으로 수정하거나 새로 구축할 수 있습니다. 각 테마의 템플릿, 스타일, JavaScript, 리소스 등을 이곳에서 관리하며, 이를 통해 각 업체나 고객에 맞춤화된 프론트엔드 페이지를 구현할 수 있습니다.
public
: public 폴더는 웹 애플리케이션의 진입점이자 외부에서 접근 가능한 모든 파일들이 위치하는 폴더입니다. 다보리 프론트엔드에서 테마 요소에 실제로 접근할 수 있는 디렉토리입니다. para- -/dabory 폴더와 themes 폴더는 위 dabory 폴더와 동일한 구조로 이루어져 있습니다. dabory 폴더에서는 이미지나 리소스에 접근이 불가능하기 때문에 public 폴더에서 심볼릭 링크(symbolic link)를 생성하여 사용합니다.
*심볼릭 링크 (Symbolic Link)dabory
폴더 안에서는 이미지나 리소스에 직접 접근할 수 없기 때문에, public
폴더에 심볼릭 링크(symbolic link)를 생성하여 dabory
내부의 이미지 및 리소스를 외부에서 접근 가능하도록 연결합니다. 이를 통해 public
폴더를 경유하여 dabory
폴더 내의 리소스를 웹 애플리케이션에서 사용할 수 있습니다.
추가설명
다보리의 프론트엔드 구조는 매우 유연하고 확장 가능하도록 설계되어 있으며, dabory
폴더를 통해 관리자는 ERP 시스템과 테마를 자유롭게 커스터마이징할 수 있습니다. 또한 public
폴더는 웹 애플리케이션의 외부 리소스를 제공하는 중심 역할을 하며, 필요한 경우 심볼릭 링크를 통해 리소스를 접근할 수 있습니다.
다보리 Theme 폴더의 구조
Theme 폴더의 구조
pro (Service Page)
pro 디렉토리는 기업이나 조직 외부에 있는 게스트 및 고객을 대상으로 하는 프론트 오피스 페이지입니다. 표준 ERP와는 별도로 pro디렉토리에서만 사용되는 독립적인 클래스와 로직이 app
, resources
, routes
등의 디렉토리에 구분되어 존재하며, 표준 erp와는 독립적으로 작동합니다.
- pro 디렉토리 예시
app
이 디렉토리에는 각 기능별로 정의된 Controller가 있으며, 기능에 따라 명명 규칙을 따릅니다. Controller는 외부 API 호출과 반환된 값들을 view 페이지에 전송하는 역할을 합니다.
para
pro 디렉토리에서 사용되는 view 페이지의 구성요소, api에 대한 명시 등등 pro 페이지를 구성하는 전반적인 요소들이 파라메터로 구성되어 있습니다.
resources
pro 디렉토리에서 작동하는 정적인 요소들이 포함된 디렉토리입니다. 보통 Controller와 동일한 네이밍 규칙을 따르며, Controller에서 받아온 데이터를 활용해 view 페이지가 구성됩니다. 스크립트 코드와 css, image 등이 포함되어 있습니다.
erp (Back Office)
ERP 디렉토리는 기업이나 조직 내 직원 및 관리자를 위한 백오피스 페이지입니다. 보통 erp의 표준 erp로 작동하지만 pro 페이지 없이 erp만 사용할 수 있는 erponly
테마의 경우 pro에 설정된 route 경로로 들어오는 모든 route를 erp 경로로 redirect하여 표준 erp에서만 작동하는 구조로 간결하게 구성되어 있습니다.
- erp 디렉토리 예시
4장. Parameter 기반 개발
다보리 파라메터의 개념
다보리 파라메터
다보리 컴포저블에서는 모든 구성요소들을 파라메터를 통해 관리, 구성하고 있습니다. 다보리 파라메터를 통해 다음과 같이 구현이 가능합니다. 몇가지 예시를 소개합니다.
고객입력창 구현을 위한 파라메터
{
"General": {
"Title": "고객입력",
"PickApi": "slip-form-book",
"ActApi": "company-act"
},
"QueryVars": {
"QueryName": "pos/customer"
},
"SelectButtonOptions": [
{
"Value": "new",
"Caption": "새 레코드"
},
{
"Value": "del",
"Caption": "레코드 삭제"
},
{
"Value": "copy",
"Caption": "레코드 복사"
},
{
"Value": "rpt-print-pdf",
"Caption": "연말정산(pdf)"
},
{
"Value": "rpt-print-paper",
"Caption": "연말정산(종이)"
}
],
"//FormVars": "ListVars[0]-Caption",
"FormVars": [
{
"SaveButton": "저장",
"CompanyName": "고객번호(자동채번)*",
"MainContact": "고객명* / 성별",
"MobileNo": "휴대전화*",
"TelNo": "유선전화",
"BirthDate": "생년월일*",
"Email": "이메일*",
"CgroupId": "고객분류*",
"ZipCode": "우편번호*",
"Addr1": "주소*",
"Addr2": "주소상세",
"IsOkText": "문자발송",
"IsOkEmail": "이메일발송",
"IsOkDm": "디엠발송",
"Remarks": "관리자메모",
"UserCredit": "적립금",
"CurrUserCredit": "현재 적립금",
"AvailUserCredit": "가용 적립금(적용-버튼)"
},
{
"SaveButton": "",
"CompanyName": "left",
"MainContact": "left",
"MobileNo": "left",
"TelNo": "left",
"BirthDate": "left",
"Email": "left",
"CgroupId": "left",
"ZipCode": "left",
"Addr1": "left",
"Addr2": "left",
"IsOkText": "left",
"IsOkEmail": "left",
"IsOkDm": "left",
"Remarks": "left",
"UserCredit": "left",
"CurrUserCredit": "left",
"AvailUserCredit": "left"
},
{
"SaveButton": "0",
"CompanyName": "20",
"MainContact": "20",
"MobileNo": "20",
"TelNo": "20",
"BirthDate": "20",
"Email": "20",
"CgroupId": "20",
"ZipCode": "20",
"Addr1": "20",
"Addr2": "100",
"IsOkText": "20",
"IsOkEmail": "20",
"IsOkDm": "20",
"Remarks": "",
"UserCredit": "20",
"CurrUserCredit": "20",
"AvailUserCredit": "20"
},
{
"SaveButton": "",
"CompanyName": "required",
"MainContact": "required",
"MobileNo": "required",
"TelNo": "",
"BirthDate": "required",
"Email": "required",
"CgroupId": "required",
"ZipCode": "required",
"Addr1": "required",
"Addr2": "",
"IsOkText": "",
"IsOkEmail": "",
"IsOkDm": "",
"Remarks": "",
"UserCredit": "",
"CurrUserCredit": "",
"AvailUserCredit": ""
}
]
}
let response = await call_slip_form_book(formA['General']['PickApi'], formA['QueryVars']['QueryName'],
customer_name, {!! json_encode($menuCode) !!});
$('.customer-eyetest-act').on('click', function () {
// console.log($(this).data('value'))
switch( $(this).data('value') ) {
case 'save': customer_eyetest_btn_act_save(); break;
case 'new': atype_custom_btn_act_new(); break;
case 'copy': customer_eyetest_btn_act_copy(); break;
case 'del': customer_eyetest_btn_act_del(); break;
case 'rpt-print-pdf': Stype.rpt_print('#customer-eyetest .frm'); break;
case 'rpt-print-paper': print_test(); break;
}
});
<ul class="dropdown-menu dropdown-menu-right" role="menu">
@foreach ($formA['SelectButtonOptions'] as $key => $btn)
<li class="dropdown-item">`{{ $btn['Caption'] }}`</li>
@endforeach
</ul>
['FormVars'][2] : label, input등의 필수요소 설정
<div class="form-group w-100 d-flex flex-column" style="width: 143px">
<label class="m-0 overflow-hidden text-nowrap">{{ $formA['FormVars']['Title']['CompanyName'] }}</label>
<div class="col-12 d-flex p-0">
<input type="text" class="auto-slip-no-txt rounded w-100 radius-l0" autocomplete="off" disabled
maxlength="{{ $formA['FormVars']['MaxLength']['CompanyName'] }}"
{{ $formA['FormVars']['Required']['CompanyName'] }}>
</div>
</div>
품목찾기 모달창 구현을 위한 파라메터
{
"General": {
"Title": "품목 찾기",
"PageApi": "item-search-page"
},
"QueryVars": {
"QueryName": "master/item",
"FilterName": "is_material",
"FilterValue": "0"
},
"//FormVars": "ListVars[0]-Caption, ListVars[0]-format",
"FormVars": [
{
"SelectButton": "",
"ItemCode": "품목코드",
"ItemName": "품명",
"SubName": "서브명",
"CountUnit": "수량단위",
"CurrStockQty": "현재고",
"PurchPrc": "표준매입가",
"SalesPrc": "표준매출가",
"ItemDesc": "품목설명",
"FilterOption": "검색조건",
"SimpleOption": "상태별 검색"
},
{
"SelectButton": "left",
"ItemCode": "left",
"ItemName": "left",
"SubName": "left",
"CountUnit": "left",
"CurrStockQty": "decimal('stock_qty')",
"PurchPrc": "decimal('purch_prc')",
"SalesPrc": "decimal('sales_prc')",
"ItemDesc": "left",
"FilterOption": "left",
"SimpleOption": "left"
}
],
"// OrderByOptions": "OrderBy Options//첫번째 Value가 Default, 필수(Required)",
"OrderByOptions": [
{
"Value": "item_code asc",
"Caption": "품목코드 정렬"
},
{
"Value": "item_name asc",
"Caption": "품명 정렬"
},
{
"Value": "sub_name asc",
"Caption": "서브명 정렬"
}
],
"FilterSelectOptions": [
{
"Value": "",
"Caption": "=검색 조건="
},
{
"Value": "mx.item_code",
"Caption": "품목코드"
},
{
"Value": "mx.item_name",
"Caption": "품명"
},
{
"Value": "mx.sub_name",
"Caption": "서브명"
}
],
"SimpleSelectOptions": [
{
"Value": "mx.expose_type='0'",
"Caption": "온라인 게시"
},
{
"Value": "mx.expose_type='1'",
"Caption": "온라인 누락"
},
{
"Value": "mx.expose_type='2'",
"Caption": "쿠폰신청 상품"
},
{
"Value": "",
"Caption": "전체"
}
],
"// ListVars": "ListVars[0]-caption, ListVars[1]-size(%), ListVars[2]-align",
"// Price": "Prices show with comma and truncate numbers under decimal !!",
"ListVars": [
{
"$Radio": "$Radio",
"$Check": "",
"No": "번호",
"ItemCode": "품목 코드",
"ItemName": "품명",
"SubName": "서브명",
"IgroupName": "품목구분",
"SalesPrc": "매출가",
"PurchPrc": "매입가",
"MoreInfo": "추가정보"
},
{
"$Radio": "3",
"$Check": "3",
"No": "10",
"ItemCode": "15",
"ItemName": "12",
"SubName": "12",
"IgroupName": "13",
"SalesPrc": "10",
"PurchPrc": "10",
"MoreInfo": "10"
},
{
"$Radio": "center",
"$Check": "center",
"No": "center",
"ItemCode": "left",
"ItemName": "left",
"SubName": "left",
"IgroupName": "left",
"SalesPrc": "decimal('sales_qty')",
"PurchPrc": "decimal('purch_prc')",
"MoreInfo": "left"
}
]
}
ListType1 파라메터의 이해와 사용법
ListType1
ListType1은 다보리 파라메터 중 가장 많이 사용되는 파라메터입니다. 주로 필터링을 통해 데이터를 List 형식으로 출력합니다.
ListType1 예시
1. view page
상단 필터링을 통해 데이터가 걸러지고 하단 박스에 결과 데이터들을 출력합니다.
2. para
{
"//list-type-1": "simple and plain list by query of table join",
"General": {
"Title": "상품 리스트",
"PageApi": "list-type1-page",
"ActApi": "list-type1-upload"
},
"QueryVars": {
"QueryName": "master/item-fngoods-input",
"FilterName": "",
"FilterValue": "",
"FilterDate": ""
},
"PrintVars": {
"QueryName": "federated/crystal/master/item-fngoods-input",
"ReportPath": "standard/master/item-fngoods-input.rpt",
"ExportFmt": "PDF",
"ServerPrinter": "",
"CustomCode": "item-fngoods-input"
},
"HeadSelectOptions": [
{
"Value": "clear-all-filter",
"Caption": "초기화"
},
{
"Value": "barcode-print",
"Caption": "바코드 인쇄"
},
{
"Value": "rpt-print",
"Caption": "빠른 표준 보고서"
},
{
"Value": "rpt-custom",
"Caption": "커스텀 보고서"
}
],
"//FormVars": "FormVars[0]-caption, FormVars[1]-searchPopup",
"FormVars": [
{
"ListButton": "조회",
"DateRange": "",
"DateNavi": "일자방향(오늘)",
"Date": "",
"From": "부터",
"To": "까지",
"FirstRange": "",
"SecondRange": "",
"ThirdRange": "",
"FourthRange": "",
"AddTotalLine": "",
"SelectPopup": "",
"MultiPopup": "",
"ChartPopup": "",
"DownloadList": "",
"ShowOnlyClosed": "",
"Balance": "",
"OrderBy": "표시 순서",
"FilterOption": "검색조건",
"SimpleOption": "상태별 검색"
}
],
"FilterSelectOptions": [
{
"Value": "",
"Caption": "=검색 조건="
},
{
"Value": "mx.item_code",
"Caption": "품목코드"
},
{
"Value": "mx.item_name",
"Caption": "품명"
},
{
"Value": "mx.sub_name",
"Caption": "서브명"
}
],
"SimpleSelectOptions": [
{
"Value": "mx.expose_type='0'",
"Caption": "온라인 게시"
},
{
"Value": "mx.expose_type='1'",
"Caption": "온라인 누락"
},
{
"Value": "",
"Caption": "전체"
}
],
"//ListType1RangeVars": "[0]-filter, [1]-component, [2]-parameter",
"ListType1RangeVars": [
{
"FirstRange": "",
"SecondRange": "",
"ThirdRange": "",
"FourthRange": ""
},
{
"FirstRange": "",
"SecondRange": "",
"ThirdRange": "",
"FourthRange": ""
},
{
"FirstRange": "",
"SecondRange": "",
"ThirdRange": "",
"FourthRange": ""
}
],
"// DateRangeOptions": "월:현재월의 1~30, 분기: 현재분기의 첫째월 1일 ~ 마지막월의 말일, 반기/년 동일한 컨셉,전체:1990~3000",
"DateRangeOptions": [
],
"DateNaviOptions": [
{
"Value": "day",
"Caption": "일"
},
{
"Value": "week",
"Caption": "주"
},
{
"Value": "month",
"Caption": "월"
},
{
"Value": "quarterly",
"Caption": "분기"
},
{
"Value": "year",
"Caption": "년"
},
{
"Value": "all",
"Caption": "전체"
}
],
"SelectPopupOptions": [
{
"Caption": "상품 입력/수정/삭제",
"Component": "popup-form1.form-a.item-form",
"Parameter": "/popup/popup-form1/form-a/item"
}
],
"SelectLinkedPopupOptions":[
{
"Caption": "상품 입력/수정/삭제",
"Linked":"/dabory/erp/master-data/item-tabbed?bpa=eyJtZW51X25hbWUiOiJ0ZXN0LWl0ZW0tdGFiYmVkIiwibWVudV9jb2RlIjoiOTMwMDAwIiwiZGlzYWJsZV9sX21lbnUiOiIwIiwiZW5hYmxlX3JfbWVudSI6IjAiLCJwZXJtaXNzaW9uIjp7ImlzX215bWVudSI6IjAiLCJpc19saXN0IjoiMSIsImlzX3JlYWQiOiIxIiwiaXNfY3JlYXRlIjoiMSIsImlzX3VwZGF0ZSI6IjEiLCJpc19kZWxldGUiOiIxIiwiaXNfbmV3dGFiIjoiMCJ9LCJwYWdlX3VyaSI6IlwvZGFib3J5XC9lcnBcL21hc3Rlci1kYXRhXC9pdGVtLXRhYmJlZCIsInBhcmFfbmFtZSI6IlwvZm9ybVwvZm9ybS1hXC9pdGVtLXRhYmJlZCIsInRoZW1lX2RpciI6IiIsIm1haW5fYXBwX2lkIjowLCJndWVzdF9hcHBfaWQiOjAsImN1c3RvbV92YXIiOiIifQ=="
}
],
"// OrderByOptions": "OrderBy Options//첫번째 Value가 Default",
"OrderByOptions": [
{
"Value": "mx.item_code asc",
"Caption": "상품 코드 순서"
},
{
"Value": "mx.item_code desc",
"Caption": "상품 코드 역순"
}
],
"//BalanceOptions": "Show OnlyBalaceRemained or All",
"BalanceOptions": [
{
"Value": "",
"Caption": "전체 보기"
},
{
"Value": "c10 > 0",
"Caption": "잔량있는 것만"
}
],
"DisplayVars": {
"IsListFirst" : true,
"IsExcelColumn" : false,
"InitLines" : 15,
"HeadHeight": "130",
"IsC1Popup": "1",
"BodyHeight": "680"
},
"// ListVars": "ListVars[0]-caption, ListVars[1]-size(px), ListVars[2]-align->right(number) left(left)",
"ListVars": [
{
"$Radio": "$Radio",
"$Check": "$Check",
"No": "번호",
"C1": "품목코드",
"C2": "품명",
"C3": "서브명",
"C4": "품목구분",
"C5": "매출가",
"C6": "매입가",
"C7": "단위",
"C8": "공급사(입점사)",
"C9": "온라인누락"
},
{
"$Radio": "3",
"$Check": "3",
"No": "5",
"C1": "12",
"C2": "25",
"C3": "12",
"C4": "8",
"C5": "6",
"C6": "6",
"C7": "4",
"C8": "8",
"C9": "8"
},
{
"$Radio": "center",
"$Check": "center",
"No": "center",
"C1": "left",
"C2": "left",
"C3": "left",
"C4": "left",
"C5": "decimal('sales_prc')",
"C6": "decimal('purch_prc')",
"C7": "center",
"C8": "center",
"C9": "check"
}
]
}
ListType1 추가방법
새로운 ListType1을 추가하는 방법입니다.
1. 웹상에서 /dabory/erp 경로로 이동합니다.
3. 위 메뉴들은 모두 ListType1을 통해 구현된 메뉴들을 불러오는 리스트메뉴입니다. 사용자 메뉴 불러오기를 예시로 새로운 ListType1을 추가하겠습니다.
4. 사용자 메뉴 불러오기 메뉴 진입시 아래와 같이 리스트가 출력됩니다. C5:파라메터명을 확인합니다.
5. 예제에서는 회원 앱 권한 메뉴를 복사하여 새로운 ListType1을 생성하겠습니다. 회원 앱 권한의 파라메터명은 /form/form-b/member-menu-perm입니다.
6. dbrerp 소스상에서 para 파일들이 들어있는 dabory/para 디렉토리에서 /list/list-type1/downupload/ 경로에서
해당 페이지 메뉴에서 보여주고 싶은 데이터, 엑셀 다운로드 데이터를 C1~C20까지 순서대로 넣습니다.
쿼리 작성이 끝났다면 방금 만들어줬던 쿼리와 동일하게 새로 만들어준 json 파일의 파라메터도 수정해줍니다.
마지막으로 쿼리를 실행하기 위래 QueryName을 입력해줍니다.
이제 다시 웹으로 가서 바둑판 메뉴 불러오기를 하면 새로 추가한 list를 확인할 수 있습니다.
파라메터를 이용한 head/body 복사
head 복사 구현하기
파라메터를 이용하여 sorder의 head와 body를 복사하는 방법을 명시합니다.
예제에서는 sorder(수주)로 테스트를 진행하겠습니다.
필요한 사항
1. 파라메터에 대한 전반적인 이해도
2. JavaScript에 대한 기초적인 이해도
3. API에 대한 이해도
1. 수주리스트의 파라메터인 sorder.json을 살펴보겠습니다.
{
"General": {
"Title": "수주등록",
"PickApi": "slip-form-book",
"ActApi": "sorder-act"
},
"QueryVars": {
"QueryName": "sales/sorder"
},
"HeadSelectOptions": [
{
"Value": "new",
"Caption": "추가",
"Parameter": ""
},
{
"Value": "save-and-new",
"Caption": "저장 후 추가",
"Parameter": ""
},
{
"Value": "copy-to-another",
"Caption": "수주에서 수주로 복사(-)",
"Parameter": "sales/sorder-sorder"
},
{
"Value": "copy-to-another",
"Caption": "매입 가격표에서 수주로 복사(-)",
"Parameter": "purch/pquote-sorder"
},
{
"Value": "copy-to-another",
"Caption": "견적에서 수주로 복사",
"Parameter": "sales/squote-sorder"
},
{
"Value": "delete",
"Caption": "삭제",
"Parameter": ""
}
],
"StatusOptions": [
{
"Value": "확정",
"Caption": "확정"
},
{
"Value": "취소",
"Caption": "취소"
}
],
"BodySelectOptions": [
{
"Value": "body-copy",
"Caption": "수주에서 수주로 품목 복사(-)",
"Parameter": "sales/sorder-sorder"
},
{
"Value": "body-copy",
"Caption": "견적에서 수주로 품목 복사(-)",
"Parameter": "sales/squote-sorder"
},
{
"Value": "multi-delete",
"Caption": "품목 일괄 삭제",
"Parameter": ""
},
{
"Value": "multi-update",
"Caption": "품목 일괄 수정",
"Parameter": ""
}
],
"//FormVars": "ListVars[0]-Caption",
"FormVars": [
{
"SaveButton": "저장",
"AddNewBdButton": "품목 추가",
"AutoSlipNo": "수주번호(자동채번)*",
"Date": "수주일자*",
"Buyer": "매출업체*",
"BuyerContact": "업체담당자",
"DealType": "거래구분*",
"VatType": "부가세*",
"VatTypeRate": "부가세율",
"Status": "상황",
"Delivery": "납품기한",
"PayTerms": "지불조건",
"Destination": "납품장소",
"IsClosed": "종결",
"SgroupName": "영업부서*",
"UserName": "입력사용자*",
"Remarks": "비고"
},
{
"SaveButton": "left",
"AddNewBdButton": "left",
"AutoSlipNo": "left",
"Date": "left",
"Buyer": "left",
"BuyerContact": "left",
"DealType": "left",
"VatType": "left",
"VatTypeRate": "left",
"Status": "left",
"Delivery": "left",
"PayTerms": "left",
"Destination": "left",
"IsClosed": "left",
"SgroupName": "left",
"UserName": "left",
"Remarks": "left"
},
{
"SaveButton": "0",
"AddNewBdButton": "20",
"AutoSlipNo": "20",
"Date": "20",
"Buyer": "20",
"BuyerContact": "20",
"DealType": "20",
"VatType": "20",
"VatTypeRate": "20",
"Status": "20",
"Delivery": "20",
"PayTerms": "20",
"Destination": "20",
"IsClosed": "0",
"SgroupName": "20",
"UserName": "20",
"Remarks": "0"
},
{
"SaveButton": "",
"AddNewBdButton": "",
"AutoSlipNo": "required",
"Date": "required",
"Buyer": "required",
"BuyerContact": "",
"DealType": "required",
"VatType": "required",
"VatTypeRate": "",
"Status": "",
"Delivery": "",
"PayTerms": "",
"Destination": "",
"IsClosed": "",
"SgroupName": "required",
"UserName": "required",
"Remarks": ""
}
],
"// ListVars": "ListVars[0]-Caption, ListVars[1]-Size(%), ListVars[2]-align",
"ListVars": [
{
"$Radio": "",
"$Check": "$Check",
"ItemCode": "품목코드*",
"ItemName": "품명*",
"SubName": "서브명#",
"CountUnit": "단위#",
"SorderQty": "수주수량*",
"SorderPrc": "수주단가*",
"SupplyAmt": "공급가액*",
"VatAmt": "세액*",
"SumAmt": "합계금액*",
"CurrSalesPrc": "매출가#",
"ConfirmDate": "요청납기일",
"DeliDate": "확정납기일*",
"Ref1": "참고1",
"Ref2": "참고2",
"SorderMemo": "품목설명(M)"
},
{
"$Radio": "",
"$Check": "3",
"ItemCode": "10",
"ItemName": "30",
"SubName": "10",
"CountUnit": "5",
"SorderQty": "10",
"SorderPrc": "10",
"SupplyAmt": "10",
"VatAmt": "10",
"SumAmt": "10",
"CurrSalesPrc": "10",
"DeliDate": "12",
"ConfirmDate": "12",
"Ref1": "15",
"Ref2": "15",
"SorderMemo": "10"
},
{
"$Radio": "",
"$Check": "center",
"ItemCode": "left",
"ItemName": "left",
"SubName": "left",
"CountUnit": "center",
"SorderQty": "decimal('sales_qty')",
"SorderPrc": "decimal('sales_prc')",
"SupplyAmt": "decimal('sales_amt')",
"VatAmt": "decimal('sales_amt')",
"SumAmt": "decimal('sales_amt')",
"CurrSalesPrc": "decimal('sales_prc')",
"DeliDate": "right",
"ConfirmDate": "right",
"Ref1": "right",
"Ref2": "right",
"SorderMemo": "right"
}
],
"FooterVars": [
{
"StorageName": "창고",
"BranchName": "점포명",
"QtyTotal": "수량 합계",
"SupplyTotal": "공급가액 소계",
"VatTotal": "부가세액 소계",
"SumTotal": "합계액 소계"
}
]
}
5장. 실행 메뉴와 권한 관리
실행 메뉴의 확장
다보리 컴포저블에서 사용자 메뉴를 확장하고 수정할 수 있습니다.
사용자 메뉴리스트
erp 페이지 좌측에 사용자 메뉴리스트입니다. 로그인한 사용자의 권한에 따라, 설정에 따라 사용가능한 모든 메뉴가 노출됩니다.
모든 메뉴는 고유식별 코드인 메뉴코드가 존재하며 부모메뉴 - 자식메뉴와 같이 계층형으로 구성되어 있습니다.
좌측메뉴를 제어하기 위해서 '메뉴 확장과 API 관리' - '사용자 메뉴'로 가면
해당 앱에서 생성된 모든 메뉴 레코드가 출력됩니다.
여기서 메뉴정보들은 bpa 변수 안에 암호화되어 반환되고 테마폴더의 경로 + bpa를 통해 해당 메뉴에 접근할 수 있습니다.
우측 상단에 보이는 조회 버튼 옆에 화살표 버튼 클릭시 메뉴 레코드의 데이터를 제어할 수 있습니다.
Component : /views/components/nav-side-bar-component
Parameter : /dabory/para/erp/ko_KR/list/list-typ1/user-menu-input
Query_name : user-menu-input
사용자 메뉴의 수정 / 추가 / 삭제
user-menu-input 파라미터를 통해 사용자메뉴를 추가하고 삭제하고 수정할 수 있습니다
* 사용자메뉴를 추가할 경우
1. 메뉴코드 확인
사용자 메뉴리스트에서 메뉴코드를 확인하고 추가할 메뉴의 메뉴코드가 들어갈 위치를 확인합니다.
사용자 메뉴는 parent(최상위 메뉴) - child(하위메뉴) - second chlid(두번째 하위메뉴) - third child(세번째 하위메뉴) ...
위와 같은 계층형 구조로 이루어져 있습니다. parent 의 메뉴코드가 010000이라면 child의 메뉴코드는 01로 시작합니다.
또 child의 메뉴코드가 011000이라면 second chlid의 메뉴코드는 011로 시작합니다.
이런식으로 반복하며 사용자 메뉴가 출력되기 때문에 메뉴코드를 확인하고 생성해야 합니다.
2. 테마폴더 / sort_type 지정
현재 사용하고 있는 테마의 디렉토리와 sort_type을 확인하여 input에 입력해야 합니다.
sort_type은 해당 업체의 db마다 다르기 때문에 dbr_sort_menu에서 확인이 가능합니다.
3. saveBtn을 통해 db에 저장됐다면 erp header에 캐시삭제를 통해 캐시를 삭제해주어야 웹상에 반영이 됩니다.
만약 좌측메뉴에 노출이 안된다면 아래와 같은 원인이 있을 수 있습니다.
- 캐시가 남아있을 경우
- 테마경로를 잘못 입력
- is_use, is_skipp 등의 컬럼값이 잘못 체크
Component : views/front/dabory/erp/list-type/type1
Parameter : /dabory/para/erp/ko_KR_list/popup/popup-form1/form-a/user-menu-input
Query_name : menu-perm/user
사용자 메뉴의 검색
Component : views/front/dabory/erp/list-type/type1
Parameter : /dabory/para/erp/ko_KR_list/popup/popup-form1/form-a/user-menu-input
실행메뉴의 권한관리
사용자 메뉴별 유저의 권한을 설정할 수 있습니다.
녹색 바탕의 흰색 폴더 버튼을 클릭하게 되면 사용자 메뉴조회 popup이 나타납니다.
사용자의 권한별 권한 정보를 확인할 수 있으며 특정 권한번호를 클릭하게 되면 해당 사용권한에서 사용할 수 있는 사용자메뉴가 출력됩니다.
Component : /views/front/dabory/erp/perm/user-perm
Parameter : /dabory/para/erp/ko_KR/form/form-b/user-menu-perm
Query_name : user-menu-perm
이 Component에서 사용자별 메뉴의 상태값들을 수정할 수 있고 사용자메뉴에서 추가한 새로운 메뉴를 적용할 수 있습니다.
6장. 테마 커스터마이징
테마 설치하기
테마 설치하기
1. 설치할 테마를 확인한뒤 다보리 깃서버에서 해당 테마 레포지토리로 이동하여 HTTP url을 복사합니다.
2. dbrerp 소스에서 dabory 디렉토리로 이동합니다.
cd dabory
3. themes 디렉토리를 생성합니다.
mkdir themes
4. 생성한 themes 디렉토리로 이동합니다.
cd themes
5. 복사했던 깃레포지토리의 HTTP url를 git clone 합니다.
git clone http://git.daboryhost.com:10880/dbrerp-themes/eyemsg.git
6. dbrerp 소스의 루트 디렉토리에 위치한 public 경로로 이동합니다.
cd ../../public
7. /themes/eyemsg/pro 디렉토리를 생성합니다.
mkdir -p /themes/point2u/pro
8. 생성해준 /themes/point2u/pro 경로로 이동합니다.
cd themes/eyemsg/pro
9. public/themes/eyemsg/pro 경로 안에 dabory/themes/eyemsg/pro 경로의 resources의 심볼릭 링크를 걸어줘야 합니다.
ln -s [타겟경로] [심볼릭 링크 경로] 명령어를 통해 심볼릭 링크를 걸 수 있습니다.
아래 명령어를 입력하여 심볼릭 링크를 걸어줍니다.
ln -s ../../../../dabory/themes/eyemsg/pro/resources resources
만약 이 심볼릭 링크가 정상적으로 걸리지 않았다면 css 등 정적인 요소들이 깨져서 나타날 수 있습니다.
git 서버와 Standard/theme 폴더 동기화
깃서버 : 테마폴더 동기화
로컬 PC에서의 스크립트 (cd php
):
-
cd $HOME/docker-works/php/
: 홈 디렉토리 아래에 있는docker-works/php/
경로로 이동합니다. -
all-gitpp {website-alias}
:all-gitpp
는 사전 정의된 쉘 함수로, 웹사이트 별로 Git 저장소에서 변경 사항을 가져오고 특정 폴더로 이동하여 업데이트를 수행합니다.{website-alias}
는 웹사이트의 별칭을 나타내며, 해당 웹사이트의 폴더로 이동하고 Git 동기화를 실행합니다.
서버에서의 스크립트 (cdz
):
-
cd /home
: 서버의/home
디렉토리로 이동합니다. -
all-gitpp-host {website-alias}
:all-gitpp-host
는 로컬 PC의all-gitpp
와 비슷한 역할을 합니다. 이 명령은 특정 웹사이트에 대한 Git 저장소 동기화 및 업데이트를 실행합니다. 이전과 마찬가지로{website-alias}
는 웹사이트의 별칭을 나타내며, 해당 웹사이트의 폴더로 이동하고 Git 동기화를 실행합니다.
이러한 스크립트들은 특정 작업을 자동화하여 개발자가 코드 변경 사항을 효율적으로 동기화하고 관리할 수 있도록 도와줍니다. 로컬 PC에서는 개발 환경을 관리하고, 서버에서는 실제 배포된 웹사이트를 관리하는 데 사용될 수 있습니다.
theme 폴더 및 .env 변수 동기화
Theme 폴더 : .env 변수 동기화
프로젝트 루트 경로에서 .env파일로 이동합니다.
(변수 이름과 테마 폴더 이름을 변수 값으로 동기화해야 합니다.)
현재는 DBR_THEME로 통합되어 DBR_THEME 변수로만 운영되고 있습니다.
프로 테마 커스터마이징하기
테마 개발시 pro 커스터마이징하기
다보리 컴포저블의 기본 쇼핑몰 테마인 dcdemo의 pro 페이지를 커스터마이징하는 예제입니다.
dcdemo가 설치되어 있지 않다면 프론트엔드 설치하기 예제를 통해 설치를 완료해주세요.
pro의 구조
pro 디렉토리는 다음과 같이 구성되어있습니다. 커스터마이징시 app, para, resources, routes에서 모든 커스터마이징이 이뤄집니다.
예제1
위 이미지처럼 item-details 페이지에서 상품구분, 상품명, 상품 가격, 옵션 등의 데이터들을 출력하고 있습니다.
예제1에서는 item-details 페이지에서 출력하고 있는 데이터를 변경하여 원하는 데이터로 바꿔서 출력하겠습니다.
서버에 테마를 반영하는 방법
수정사항 서버에 배포하기
1. 수정사항을 git repo에 piush합니다.
2. 서버 로그인
3. 아래와 같이 명령어를 입력합니다.
cd /home
all-gitpp-dbrerp 서버계정명
Api23KeyPair를 활용한 통신 가이드
API23JS란?
API23JS는 GUEST 사이트의 JavaScript에서 HOST 사이트의 API를 사용하기 위한 권한 키입니다. 여기서 HOST는 데이터를 요청받아 처리하고 반환하는 부모 사이트이며,
GUEST는 데이터를 요청하는 자식 사이트라고 하겠습니다.
예를 들어 예시에서는 아래와 같이 정해놓고 진행하겠습니다.
-
HOST:
opticalpos
-
GUEST:
eyemsg
HOST 설정방법
1. HOST가 될 사이트의 통합설정으로 이동합니다.
* 사이트별로 메뉴명이 상이할 수 있습니다.
2. Api23 KeyPair Encrypted 메뉴를 클릭합니다.
3. ①, ②를 순서대로 클릭하여 Api23eKeyPair를 생성합니다.
4. 편집기를 실행하여 HOST(예시에서는 opticalpos)의 .env파일로 이동합니다.
4-1. 혹은 command에서 vi 편집기를 통해 .env 파일을 열어줍니다.
5. env파일에 API23E_KEY_PAIR 변수안에 Api23 KeyPair Encrypted 메뉴에서 생성한 Api23eKeyPair 값을 추가해줍니다.
6. 링크를 클릭하여 myapp API23-Apps로 이동합니다.
7. 아래와 같이 차례대로 버튼을 클릭합니다.
8. 아래와 같이 SSO App의 Api23 Keys를 생성할 수 있는 모달창이 열립니다.
App Type : App의 타입을 지정합니다. js를 통해 함수를 사용하여 통신할 것 이기 때문에 js로 하겠습니다.
Sort : 앱의 종료에 대해서 선택합니다. CRM을 기준하로 하기 때문에 표준 CRM인 KingkongCrm을 선택하겠습니다.
OriginUrl : geust로 사용할 url을 입력합니다.
9. Generate New Api23 Keys 버튼을 클릭하여 Api23Key를 생성후 값을 복사하여 메모장에 붙여넣습니다. (추후 HOST Api를 사용하기 위해서 필요합니다.)
10. Save 버튼을 통하여 입력한 값들을 반드시 저장합니다.
GUEST 설정방법
1. HOST 생성방법 3번에서 생성해준 API23eKeyPair 값을 HOST와 동일하게 GUEST의 프로젝트 .env 파일에도 동일하게 넣어주겠습니다.
* 'api23key'키가 아니라 'API23eKeyPair'키를 넣어야합니다.
2. 편집기를 열고 GUEST 사이트의 FrontEnd(dbrerp)에서 HOST의 API를 사용하려는 view 페이지로 이동합니다.
예시에서는 eyemsg의 right.blade.php 파일에 아래와 같이 script를 추가하겠습니다.
<script src="/js/dabory.data-linker.js?serverUrl=https://opticalpos.daboryhost.com&api23Key=Nx4QebHKTssjDuP0AKude0IMZWnak0O0hb1SJ5C3PCUuPK0oRxAVAclS5/I6Zs4cO1Czr8DDrR2LNw/uJpwmzibLTYvsH54ThO5lVLs8ifHllF0fenDeHGL1R6Tuv+KJMQGQGt//HhRLrNKRyrXsx2wN1ZSUtPrpkvEQLC+DE/O0xPxYqBXqM80EaRJ+K1qrTQFkVKMwcTEv"></script>
dabory.data-linker.js 사용방법
<script src="/js/dabory.data-linker.js?serverUrl=https://opticalpos.daboryhost.com&api23Key=Nx4QebHKTssjDuP0AKude0IMZWnak0O0hb1SJ5C3PCUuPK0oRxAVAclS5/I6Zs4cO1Czr8DDrR2LNw/uJpwmzibLTYvsH54ThO5lVLs8ifHllF0fenDeHGL1R6Tuv+KJMQGQGt//HhRLrNKRyrXsx2wN1ZSUtPrpkvEQLC+DE/O0xPxYqBXqM80EaRJ+K1qrTQFkVKMwcTEv"></script>
<script>
$('#open-signup-popup').on('click', function () {
if (! window.passwdPolicy) {
$.fn.dataLinker.api23Js('setup-get', {
'SetupCode': 'passwd-policy',
'BrandCode': 'member'
}, function (response) {
window.passwdPolicy = response
$('#policy-desc-em').text(window.passwdPolicy['PolicyDesc'])
// console.log(window.passwdPolicy)
$('#join').modal('show');
})
} else {
$('#join').modal('show');
}
});
</script>
dabory.data-linker.js
스크립트를 로드합니다. 이 스크립트는 serverUrl
과 api23Key
파라미터를 통해 API 호출을 처리할 서버와 인증 키를 설정합니다.5번줄 :
- window.passwdPolicy가 존재하는지 확인후 없을 경우
dabory.data-linker.js
에서 제공하는api23Js
메서드를 사용해setup-get
HOST의 API를 호출합니다. - 호출 시, 요청 데이터(
SetupCode
와BrandCode
)를 GUEST로 전송하여 API에서 필요한 비밀번호 정책 정보를 가져옵니다.
이렇게 API23JS는 HOST와 GUEST간의 안전한 데이터 통신을 가능하게 합니다.
- HOST는 API23E_KEY_PAIR를 생성하고 API23_KEY를 발급하여 GUEST에게 제공합니다.
- GUEST는 API23_KEY를 사용해 HOST API를 호출하여 필요한 데이터를 가져옵니다.
이를 통해 HOST의 API 데이터를 GUEST 사이트에서 효율적으로 사용할 수 있습니다.
Theme 개발시 네이밍 규칙
테마/계정/DB 복사 시 중복 단어로 인한 오류 방지를 위한 네이밍 규칙
🔎문제사항
테마나 DB를 복사할 때, 폴더명과 내부 콘텐츠의 텍스트가 함께 일괄 변경되면서 예상치 못한 문제가 발생할 수 있습니다.
예를들어
- 예를 들어, 기존
composable
테마를 복사해 **새로운 테마인myaccount
**로 변경하는 경우,
편집기에서composable
이라는 단어를 전체 검색 후 변경하게 되면 폴더명뿐 아니라 내부 콘텐츠의 모든composable
텍스트가 **myaccount
**로 바뀌어버립니다. - 이와 비슷한 문제가 DB 복사 시에도 발생할 수 있습니다. DB 사용자 이름(
composable_db
)이 포함된 특정 값들이 일괄 변경되면서 Definer나 테이블 내 데이터까지 변경되어 원치 않는 데이터 수정이 일어날 수 있습니다. - 따라서 이러한 문제를 방지하고, 다른 테마나 DB로 복사 작업을 보다 편리하게 수행하기 위해 아래와 같은 네이밍 규칙을 제안합니다.
🛠 해결방안
1️⃣테마명, 계정명, DB명에 언더바(_) 사용하기
기존방식 |
✅변경방식 |
분류 |
composable | ✅ compos_able | theme |
myaccount | ✅ my_account | theme |
composable_db | ✅ compos_able_db | db |
myaccount_db | ✅ my_account_db | db |
2️⃣도메인(URL) 생성 시 하이픈(-) 사용하기
기존방식 |
✅ 변경방식 |
분류 |
composable.com | ✅ compos_able.com | domain |
myaccount.com | ✅ my_account.com | domain |
7장. 쿼리 커스터마이징
쿼리 커스터마이징 개념
다보리 컴포저블에서는 weberp_queries
에 표준화된 쿼리 구조가 적용되어 있습니다. 표준 쿼리는 다양한 ERP 및 PRO 기능을 체계적으로 지원하며, 각 분류별로 구조화되어 있습니다. 테마별로 쿼리를 커스터마이징하여 사용할 수도 있지만, 기본적인 표준 쿼리의 구조와 위치를 유지하는 것이 중요합니다.
표준 쿼리 구조
weberp_queries
는 표준화된 쿼리들이 구축되어 있으며, 각 쿼리는 특정 기능과 연관된 디렉토리 구조를 따릅니다. 예를 들어, erp/list/list-type1/download/post
디렉토리에는 pro_post
테이블의 다운로드 기능을 구현하는 쿼리 파일이 포함되어 있습니다.
커스터마이징 지침
- 디렉토리 구조 유지: 테마 디렉토리의
qry
안에 쿼리를 커스터마이징할 때는weberp_queries
의 구조와 위치를 동일하게 유지해야 합니다. - 표준 쿼리 참조: 필요한 쿼리의 구조와 위치를
weberp_queries
에서 확인한 후, 테마 디렉토리의qry
에 동일한 구조로 구현합니다. - 쿼리 커스터마이징:
select
절,조건
절,from
절 등 쿼리의 세부 내용을 필요에 따라 다양하게 커스터마이징할 수 있습니다.
예시
weberp_queries
의 디렉토리 구조 예시:
weberp_queries/erp/list/list-type1/download/post
테마 디렉토리의 커스터마이징된 쿼리 구조 예시:
themes/your_theme/qry/erp/list/list-type1/download/post
커스터마이징 쿼리를 구축할 때는 반드시 weberp_queries
를 참조하여 필요한 쿼리의 구조와 위치를 확인하고, 동일한 디렉토리 구조로 구현해야 합니다. 이를 통해 표준 쿼리의 체계를 유지하면서도 필요한 부분을 커스터마이징할 수 있습니다.
커스터마이징 예제
pro 테마중 kbgolf에 적용된 쿼리 커스터마이징 예제를 살펴보겠습니다.
디렉토리 구조 설정
먼저 kbgolf
테마의 qry
디렉토리로 이동합니다. 예제에서 kbgolf/qry
디렉토리 구조는 다음과 같습니다.
표준 쿼리 디렉토리와 일치
백엔드 서버에서 SQL 파일을 인식하기 위해서는 main_api
서버의 디렉토리 구조와 동일하게 만들어야 합니다.
weberp_queries
의 디렉토리를 참고하여 동일한 디렉토리를 구축합니다.
weberp_queries
디렉토리 구조 예시:
커스터마이징 쿼리의 디렉토리 구조 예시
QueryVars 작성
프론트엔드에서 쿼리를 호출하기 위한 파라미터를 작성합니다. QueryVars
에 테마명을 포함하여 작성합니다:
"QueryVars": {
"QueryName": "kbgolf::post/sise",
"FilterName": "",
"FilterValue": "",
"FilterDate": "",
"SimpleFilter": ""
},
QueryName
: kbgolf::post/sise
와 같이 테마명을 포함시켜줍니다. 테마명이 포함되지 않으면 서버에서 표준 쿼리를 찾게 되어 에러가 발생할 수 있습니다.서버 반영
참고사항
8장. 커스텀 테이블 사용방법
strong api를 활용한 STRONG 커스터마이징
Strong 커스터마이징이란?
다보리 컴포저블의 표준화된 테이블 구조는 통합 관리, 데이터의 일관성, 유지보수 효율성 등 여러 가지 면에서 큰 장점을 제공합니다. 만약 특정 애플리케이션에서 구조 변경이 발생했을 때 db-update 실행시 메인 API 서버에서 돌고 있는 모든 애플리케이션의 테이블 구조를 동기화할 수 있습니다.
하지만 모든 애플리케이션이 동일한 데이터 구조를 사용함에 따라 유연성의 제한이 생길 수 있습니다. 이러한 부분들은 Strong 커스터마이징을 통해 표준 테이블 구조에서 벗어나 다양하게 커스터마이징할 수 있습니다. 커스터마이징 테이블에는 테이블명에 특정 prefix를 붙여 기존 표준 테이블과 구분합니다.
예를 들어, dbr_item이라는 표준으로 사용하고 있는 db table을 strong api를 사용하여 커스터마이징 하려면 zzz_dbr_item 같이 테이블명에 특정한 prefix를 붙여 변경하여 표준테이블과는 다르게 db 테이블을 사용할 수 있습니다. 이렇게 테이블을 커스터마이징하여 각 애플리케이션 별로 개성 있는 데이터 구조를 구축할 수 있습니다.
또한 Strong 커스터마이징은 Java, Python, Golang 등 다양한 언어로 백엔드 API 서버 구축이 가능합니다. 이 API 서버를 통해 해당 어플리케이션의 개발 언어와 무관하게 다보리 컴포저블의 게이트웨이 서버를 이용할 수 있습니다. 이를 통해 각 애플리케이션은 고유한 요구사항을반영한 맞춤형 데이터 구조를 가질 수 있으면서도, 다보리 컴포저블의 통합 관리 및 일관성 유지의 장점을 활용할 수 있습니다.
Strong api를 활용한 프론트엔드 예제
참고사항
- 예제에 앞서 dc 프론트엔드가 설치되어 있지 않다면 프론트엔드 설치하기를 통해 프론트엔드 설치를 완료해주세요.
- strong의 backend는 main api 서버와 별도로 작동하는 api 서버입니다.
- main api를 호출하지 않고 strong api를 통해 별도의 api를 구성하여 frontend와 backend에서 표준을 수정하지 않고도 다양하게 커스터마이징이 가능합니다.
- strong 디렉토리는 public에서 심볼릭링크를 사용하지 않습니다. 필요하다면 themes/dcdemo/erp 경로에 js, css, blade 파일 등을 넣고 사용합니다.
프론트엔드 세팅
1. env파일에 API_URL변수 추가
- 자바 api서버 개발시 STRJAVA_API_URL
- GO api서버 개발시 STRGPO_API_URL
- Python api서버 개발시 STRPYTHON_API_URL
해당 API 서버의 URL을 입력해줍니다.
2. dabory/themes/dcdemo/ 경로 안에 strong 디렉토리 추가
3. strong 디렉토리에 frontend/erp 디렉토리 추가
4. app, resources 디렉토리를 각각 추가
기타
바코드 프린트 사용방법
바코드 라이브러리 적용방법
1. 라라벨 패키지 정보
- name: milon/barcode
- version: v10.0.1
- php: ^7.3 ~ ^8.0
- 바코드 print 사용방법
controller : db에서 데이터 불러옴 ->
view : 불러온 데이터를 가져와서 DNS1D 클래스를 통해 바코드와 연동
padding, margin 등을 적용하여 바코드의 출력위치를 지정
크리스탈 레포트 사용방법
MacOS에서 크리스탈 레포트 사용 및 윈도우 서버 접근 방법
1. 크리스탈 레포트 개요
크리스탈 레포트(Crystal Reports)는 데이터를 자동으로 가져와 PDF, Excel, Word 등의 보고서를 생성 및 배포하는 역할을 합니다 일반적으로 기업용 ERP, 회계 시스템, CRM 등과 연동하여 사용되며, 이러한 이유로 윈도우 서버 환경에서 운영됩니다
2. MacOS에서 윈도우 서버 접근 방법
MacOS에서 윈도우 서버에서 실행 중인 크리스탈 레포트에 접근하려면 원격 데스크톱 연결을 사용해야 합니다
2.1 Microsoft 원격 데스크톱 앱 설치
MacOS에서는 RDP(Remote Desktop Protocol) 파일을 실행하여 원격 서버에 접속할 수 있으며, 이를 위해 Microsoft의 원격 데스크톱 앱이 필요합니다
-
앱 다운로드 경로:
Microsoft Remote Desktop (App Store)
2.2 원격 데스크톱 연결 방법
-
Microsoft Remote Desktop 앱을 실행합니다.
-
'Import from RDP File' 또는 **'새 연결 추가'**를 선택합니다.
-
제공받은 RDP 파일을 불러오거나 수동으로 서버 정보를 입력합니다.
-
Username(사용자명)과 Password(비밀번호)를 입력하여 로그인합니다.
-
원격 데스크톱을 통해 윈도우 서버에 접속하면 크리스탈 레포트를 사용할 수 있습니다.
3. 크리스탈 레포트 실행
다음은 윈도우 서버 접속 후 .rpt
파일을 열어 크리스탈 리포트에서 보고서를 편집할 때, 자주 사용하는 기능들 입니다
🔹 1. 텍스트 상자 (Text Box)
📌 역할:
- 고정된 텍스트(라벨)를 추가할 때 사용합니다
- 예:
"사업자등록번호"
,"전화번호"
,"고객명"
같은 문구
🔹 2. 라인(Line) 생성 도구
📌 역할:
- 보고서에서 표(테이블)와 같은 구조를 만들 때 가로, 세로 선(Line)을 추가하는 기능입니다
- 예: 표의 구분선을 추가하여 가독성을 높일 때 사용합니다
🔹 3. DB 필드 (Database Fields) - 동적 데이터 바인딩
📌 역할:
- DB에서 가져온 데이터를 자동으로 보고서에 반영하는 역할입니다
- 예:
{c1}
→"사업자등록번호"
,{c2}
→"전화번호"
등의 값을 동적으로 불러옴
4. 크리스탈 리포트에서 합계 자동 정렬 방법
📌 목표: ex) 연말정산에서 데이터 한줄 한줄 추가 될때 합계가 맨 아래에 위치하는 방법
- DB에서 불러온 데이터(Details)가 동적으로 추가될 때, 맨 아래의 "합계"가 자동으로 내려가도록 설정
- Header, Details, Footer에서 같은 변수 이름을 사용할 때,
position
값을 이용해 구분 Section Expert
의Suppress
기능을 활용하여 필요한 섹션만 표시되도록 설정
1. 동적 로우 추가 시 Footer(합계) 자동 위치 조정
📌 원리:
- Details(바디)에서 데이터가 많아질수록 Report Footer(합계) 섹션이 자동으로 아래로 내려감
- Report Footer를 사용
📌 설정 방법:
1️⃣ "Section Expert"에서 Report Footer 설정 조정
2️⃣ Suppress 조건 추가하여 Report Footer가 마지막에만 나오도록 설정
📌 예상 결과:
No | 방문일 | 현금 | 카드 | 외상금액 | 합계 |
---|---|---|---|---|---|
1 | 2024-11-10 | 10,000 | 50,000 | 0 | 60,000 |
2 | 2024-11-11 | 5,000 | 40,000 | 0 | 45,000 |
3 | 2024-11-12 | 8,000 | 35,000 | 0 | 43,000 |
합계 | 23,000 | 125,000 | 0 | 148,000 |
✔ 데이터가 많아질수록 합계가 자동으로 맨 아래로 정렬됨
5. 크리스탈 리포트에서 Database Fields를 연동하여 데이터 치환하는 방법
📌 목표:
➡ 오른쪽 Database Fields
에서 불러온 데이터를 원하는 위치에 배치하여 동적으로 치환하기
1. Database Fields
에서 필요한 데이터 가져오기
📌 설정 방법:
1️⃣ 오른쪽 Field Explorer
창에서 "Database Fields"
선택
2️⃣ 필요한 데이터 필드를 찾음 (예: {c1}
, {c2}
, {c3}
등)
3️⃣ 각 필드를 드래그하여 보고서(Report) 디자인의 적절한 위치에 배치
2. 데이터 필드를 Header, Details, Footer에 적절히 배치하기
📌 배치 방법:
✔ Header(헤더) 섹션:
{position} = "head-foot"
데이터를 사용하여 회사명, 고객정보 등 배치
✔ Details(바디) 섹션:{position} = "body"
데이터를 사용하여 반복되는 상세 데이터 배치
✔ Footer(합계) 섹션:{position} = "head-foot"
데이터를 사용하여 총합 표시
3. 예제: Database Fields 배치하기
📝 Report 디자인에서 데이터 배치 예시
위치 | Database Fields (예제) | 설명 |
---|---|---|
Header | {c1} (사업자번호) |
보고서 상단에 고정 |
Header | {c2} (전화번호) |
보고서 상단에 고정 |
Details | {c3} (방문일) |
데이터가 동적으로 반복됨 |
Details | {c4} (현금) |
데이터가 동적으로 반복됨 |
Details | {c5} (카드) |
데이터가 동적으로 반복됨 |
Details | {c6} (합계) |
데이터가 동적으로 반복됨 |
Footer | {c7} (총합계) |
마지막 행 아래에 위치 |
✔ 이제 데이터가 동적으로 추가될 때, 각 위치에 맞는 값이 자동으로 채워짐
✔ 합계도 마지막 행 아래에 자동으로 정렬됨
프론트에서 크리스탈레포트 연동방법
Crystal Report + Front 연동방법
1. 아래와 같이 이미 작업된 양식의 rpt파일이 존재한다면 해당 rpt파일에서 필요한 필드들을 확인합니다.
1-1 위와 같이 작성된 rpt 파일이 존재하지 않는다면 C:\ReCrystallizeServer\Reports\standard 경로로 이동후 필요한 양식과 가장 흡사한 양식을 찾아 복사해줍니다.
2. 확인한 필드를 토대로 쿼리를 작성합니다.
-- opticalpos::federated/crystal/adjustment/subqry/insert1.sql
SELECT
UNIX_TIMESTAMP() as created_on,
2 as list_token,
'head-foot' as position,
-- 발행매장
tax_no as c1, -- 사업자등록번호
tel_no as c2, -- 전화번호
branch_name as c3, -- 상호명
branch_manager as c4, -- 대표자
-- 고객정보
company_no as c5, -- 고객번호
company_name as c6, -- 고객명
0 as d1, -- dummy
0 as d2, -- dummy
0 as d3, -- dummy
0 as d4, -- dummy
0 as d5, -- dummy
0 as d6, -- dummy
0 as d7, -- dummy
0 as d8, -- dummy
0 as d9, -- dummy
0 as d10 -- dummy
from dbr_company as mx
inner join dbr_sorder on mx.id = dbr_sorder.buyer_id
inner join dbr_branch on dbr_sorder.branch_id = dbr_branch.id
-- @where
group by mx.id
-- @order
-- opticalpos::federated/crystal/adjustment/subqry/insert2.sql
SELECT
UNIX_TIMESTAMP() as created_on,
2 as list_token,
'body' as position,
sorder_date as c1, -- 주문일자
ccard_amt as c2, -- 카드 사용금액
cash_amt as c3, -- 현금 사용금액
coupon_amt as c4, -- 쿠폰 사용금액
reward_use_amt as c5, -- 적립금 사용금액
discount_amt as c6, -- 할인금 사용금액
sum(sorder_sum) - ccard_amt - cash_amt - coupon_amt - reward_use_amt as c7, -- 외상 금액
sum(ccard_amt) as c8, -- 해당일의 총 카드 사용금액
sum(cash_amt) as c9, -- 해당일의 총 현금 사용금액
sum(sorder_sum) as c10, -- 해당일의 총 사용금액
sum(sum(sorder_sum)) OVER () as c11, -- 해당고객의 토탈 사용금액
0 as d1, -- dummy
0 as d2, -- dummy
0 as d3, -- dummy
0 as d4, -- dummy
0 as d5, -- dummy
0 as d6, -- dummy
0 as d7, -- dummy
0 as d8, -- dummy
0 as d9, -- dummy
0 as d10 -- dummy
from
dbr_sorder
inner join
( select
buyer_id, dbr_company.id as id
from
dbr_company
inner join dbr_sorder on dbr_company.id = dbr_sorder.buyer_id
group by buyer_id
) as mx
on mx.buyer_id = dbr_sorder.buyer_id
inner join dbr_sorder_bd on dbr_sorder.id = dbr_sorder_bd.sorder_id
-- @where
group by sorder_no
-- HAVING SUM(sorder_sum) - ccard_amt - cash_amt - coupon_amt - reward_use_amt <> SUM(sorder_sum)
-- @order
"PrintVars": {
"QueryName": "opticalpos::federated/crystal/adjustment",
"ReportPath": "standard/adjustment/adjustment.rpt",
"ExportFmt": "PDF",
"ServerPrinter": "",
"CustomCode": "adjustment"
},
QueryName : 위에서 작성했던 query를 입력해줍니다.
ReportPath : winodw server에서 rpt 파일을 저장했던 위치입니다.
ExportFmt : 레포트 출력시 파일의 형식입니다.
ServerPrinter : ""
CustomCode : 해당 커스텀을 구분할 수 있는 code입니다.
4. env(설정파일)에 REPORT_SERVER_URL 변수를 확인합니다.