1. 핵심 라이브러리 및 환경 구성
Odoo(과거 OpenERP)의 웹 클라이언트는 강력한 자바스크립트 프레임워크를 기반으로 구축되었습니다. 주요 라이브러리는 다음과 같습니다.
- jQuery: DOM 조작 및 이벤트 처리를 위해 1.8.3 버전을 기본으로 사용합니다.
- Underscore.js: 데이터 컬렉션 처리 및 유틸리티 함수를 제공합니다.
- QWeb: XML 기반의 클라이언트 사이드 템플릿 엔진입니다.
모듈 구성 시 __openerp__.py(또는 최신 버전의 __manifest__.py) 파일에 사용할 리소스를 다음과 같이 정의해야 합니다.
{
'js': ['static/src/js/custom_script.js'],
'css': ['static/src/css/style.css'],
'qweb': ['static/src/xml/templates.xml'],
}
2. 기본 모듈 구조 및 디버깅
Odoo JavaScript 모듈은 인스턴스를 인자로 받는 함수 형태로 정의됩니다. 브라우저에서 스크립트 압축을 해제하고 상세한 로그를 확인하려면 URL 뒤에 ?debug 파라미터를 추가합니다.
openerp.my_custom_module = function(instance) {
var _t = instance.web._t; // 번역 함수
var QWeb = instance.web.qweb; // QWeb 인스턴스
instance.my_custom_module = {}; // 모듈 네임스페이스 정의
instance.my_custom_module.MainView = instance.web.Widget.extend({
start: function() {
console.log("View has been initialized.");
},
});
// 클라이언트 액션 등록
instance.web.client_actions.add('custom_view.main', 'instance.my_custom_module.MainView');
}
3. 클래스 정의 및 상속 시스템
Odoo는 instance.web.Class를 통해 자체적인 클래스 상속 시스템을 제공합니다. init은 생성자 역할을 하며, this._super()를 통해 부모 메서드를 호출할 수 있습니다.
instance.my_custom_module.BaseLogic = instance.web.Class.extend({
init: function(user_name) {
this.user_name = user_name;
},
greet: function() {
console.log("Welcome,", this.user_name);
},
});
instance.my_custom_module.ExtendedLogic = instance.my_custom_module.BaseLogic.extend({
greet: function() {
this._super();
console.log("Additional greeting from extended class.");
},
});
var app = new instance.my_custom_module.ExtendedLogic("Dev");
app.greet();
4. 위젯(Widget) 아키텍처
위젯은 UI를 구성하는 기본 단위입니다. this.$el을 통해 해당 위젯의 jQuery 객체에 접근할 수 있으며, 위젯 간의 부모-자식 관계를 형성할 수 있습니다.
instance.my_custom_module.SubWidget = instance.web.Widget.extend({
start: function() {
this.$el.html("<p>Child Content</p>");
},
});
instance.my_custom_module.ParentWidget = instance.web.Widget.extend({
start: function() {
this.$el.append("<div class='wrapper'>Parent View</div>");
var child = new instance.my_custom_module.SubWidget(this);
child.appendTo(this.$(".wrapper"));
},
});
5. QWeb 템플릿 엔진 활용
QWeb은 XML 내부에서 JavaScript 로직을 수행할 수 있게 해줍니다. 주요 디렉티브는 다음과 같습니다.
t-name: 템플릿 식별자t-esc: 변수 출력 (이스케이프 처리됨)t-raw: HTML 태그를 포함한 원시 출력t-if: 조건문t-foreach/t-as: 반복문t-att-: 속성 바인딩
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="ProductItemTemplate">
<div class="product-card">
<h4><t t-esc="widget.title"/></h4>
<ul>
<t t-foreach="widget.items" t-as="item">
<li t-att-style="'color:' + widget.accentColor">
<t t-esc="item"/>
</li>
</t>
</ul>
</div>
</t>
</templates>
6. 이벤트 핸들링 및 속성 감시
위젯 내에서 DOM 이벤트는 events 객체를 통해 선언적으로 바인딩하거나 jQuery를 사용해 직접 바인딩할 수 있습니다. 위젯 자체 이벤트는 trigger와 on을 사용합니다.
instance.my_custom_module.InteractiveWidget = instance.web.Widget.extend({
events: {
"click .action-btn": "handleAction",
},
handleAction: function(event) {
alert("Button clicked!");
this.trigger("action_complete", {status: "success"});
},
start: function() {
this.on("change:data", this, this.dataChanged);
},
dataChanged: function() {
console.log("Data has been updated to:", this.get("data"));
}
});
7. 서버와의 통신 (RPC)
Odoo는 서버 측 Python 모델과 통신하기 위해 instance.web.Model 클래스를 제공합니다. 비동기 처리를 위해 Deferred 객체를 사용하며 .then()으로 콜백을 관리합니다.
모델 메서드 호출
var myModel = new instance.web.Model("res.users");
myModel.call("search_read", [ [['active', '=', true]], ['name', 'login'] ]).then(function(users) {
_.each(users, function(user) {
console.log("User:", user.name);
});
});
데이터 쿼리 최적화
query() 메서드를 사용하면 필터링, 정렬, 제한 조건을 체인 형태로 구현할 수 있어 가독성이 향상됩니다.
var model = new instance.web.Model("product.template");
model.query(['name', 'list_price'])
.filter([['sale_ok', '=', true]])
.limit(10)
.all().then(function(products) {
// 결과 처리
});
8. 기존 클래스 확장 (include)
이미 정의된 Odoo의 위젯이나 클래스의 기능을 수정해야 할 경우 extend가 아닌 include를 사용합니다. 이는 원본 클래스 자체를 몽키 패치(Monkey Patch)하여 모든 인스턴스에 변경 사항을 적용합니다.
instance.web.Widget.include({
start: function() {
console.log("All widgets now log this message on start.");
return this._super();
},
});