由於自己並非資訊相關科系畢業,基礎知識與技能相當貧乏,透過此次學習Odoo系統基礎建置與開發,我才初次接觸了如何在Windows系統透過VM來使用Linux系統,以及終端機指令的操作,來一步一步建置Odoo系統,包括所需的Python套件、PostgreSQL資料庫系統、pgAdmin資料庫管理工具、Odoo系統資料夾結構、Odoo系統設定文件、PyCharm整合開發環境、系統更新與維護方式等等,需要了解與學習的技術非常非常的多,自己也僅學習使用了一小部分的工具與技巧而已。
系統開發由於牽涉到許多資料夾結構與不同文件如csv、py、xml等,因此未來使用Git做為示範檔案存放空間的需求或許也將越來越迫切,現階段仍純粹在網誌整理、發布文章;本系列一共六篇學習筆記,為花費大量時間綜合整理Peter Wu老師課堂教學、《Odoo快速入門與實戰》簡體書,以及零散的網路教學文章而得,前五篇的學習筆記完全操作使用Odoo社群版,第六篇的學習筆記則加入「康虎雲報表」的安裝與教學,可至「康虎軟件工作室」官方網站下載相關軟體,配合學習筆記的說明來安裝使用。
自學Odoo系統的建置開發相當不容易:在台灣,Odoo系統的知名度與普及性遠不如SAP、鼎新、Oracle等大廠,資訊廠商與開發人員的數量也相對稀少,就連參考書籍也完全沒有繁體中文的版本,僅有少數英文書與簡體書可以購買(而且這些書都寫得很糟),加上這幾年Odoo系統的快速發展,不同的版本之間有不小的變動,學會的技術可能過幾年就完全不能用了…。綜合上述許多原因,即便本系列學習筆記已經整理很清楚了,對於完全零經驗的開發者而言,相信仍舊難以閱讀、理解。
目前Odoo系統在歐美與中國大陸的資源、社群與討論,都比台灣頻繁、密集得多,想要入門Odoo系統的學習者建議還是需要老師來帶領,才有辦法掌握操作、管理、開發的各項眉眉角角。
l 習慣上,reports資料夾是一個獨立的Package,所有reports相關檔案皆放置於此。
l Step 1安裝康虎雲報表Server工具(有分Odoo版本):
將cfprint資料夾放在custom資料夾,並記得在終端機修改使用者群組,登入Odoo系統安裝後,可在Settings > Technical看到CFPrint。
將cfprint資料夾放在custom資料夾,並記得在終端機修改使用者群組,登入Odoo系統安裝後,可在Settings > Technical看到CFPrint。
l Step 2安裝康虎雲報表Client工具:
在Windows系統將康虎雲報表zip檔解壓縮到選定的位置,點擊cfprint.exe並允許網路存取即可,設定方面建議選擇「預覽」、「開機自啟」、「最小化到系統托盤」等比較方便。
在Windows系統將康虎雲報表zip檔解壓縮到選定的位置,點擊cfprint.exe並允許網路存取即可,設定方面建議選擇「預覽」、「開機自啟」、「最小化到系統托盤」等比較方便。
l Step 3在openacademy資料夾內修改__init__.py:
# 原程式碼增加以下程式碼
from . import reports
# 原程式碼增加以下程式碼
from . import reports
l Step 4在reports資料夾內創建openacademy_studentclass_report.py:
# -*- coding: utf-8 -*-
# Author: Peter Wu
from odoo import models, fields, api
from odoo.exceptions import UserError
# AbstractModel用在離開畫面即清除資料的欄位
class openacademystudentclassreport(models.AbstractModel):
_name = 'report.openacademy.studentclass_report'
@api.model
def _get_report_values(self, docids, data = None):
docs = self.env['openacademy.studentclass'].browse(docids)
res_doc = []
# 蒐集母單資料
for line in docs:
line_doc = []
# 蒐集子單資料
for student_line in line.studentclass_line:
if student_line.student_class == '1':
myclass = '一年級'
elif student_line.student_class == '2':
myclass = '二年級'
elif student_line.student_class == '3':
myclass = '三年級'
if student_line.student_fm == 'M':
myfm = '男'
elif student_line.student_fm == 'F':
myfm = '女'
if student_line.student_memo:
mymemo = student_line.student_memo.replace('\n','\\n')
else:
mymemo = ' '
line_temp = {
'student_no': student_line.student_no,
'student_name': student_line.student_name,
'student_contact': student_line.student_contact,
'student_class': myclass,
'student_fm': myfm,
'student_memo': mymemo}
line_doc.append(line_temp)
temp = {
'studentclass_name': line.studentclass_name,
'studentclass_teacher': line.studentclass_teacher.teacher_name,
'studentclass_line': line_doc}
res_doc.append(temp)
docargs = {
'doc_ids': docids,
'doc_model': 'openacademy.studentclass',
'docs': res_doc}
return docargs
# -*- coding: utf-8 -*-
# Author: Peter Wu
from odoo import models, fields, api
from odoo.exceptions import UserError
# AbstractModel用在離開畫面即清除資料的欄位
class openacademystudentclassreport(models.AbstractModel):
_name = 'report.openacademy.studentclass_report'
@api.model
def _get_report_values(self, docids, data = None):
docs = self.env['openacademy.studentclass'].browse(docids)
res_doc = []
# 蒐集母單資料
for line in docs:
line_doc = []
# 蒐集子單資料
for student_line in line.studentclass_line:
if student_line.student_class == '1':
myclass = '一年級'
elif student_line.student_class == '2':
myclass = '二年級'
elif student_line.student_class == '3':
myclass = '三年級'
if student_line.student_fm == 'M':
myfm = '男'
elif student_line.student_fm == 'F':
myfm = '女'
if student_line.student_memo:
mymemo = student_line.student_memo.replace('\n','\\n')
else:
mymemo = ' '
line_temp = {
'student_no': student_line.student_no,
'student_name': student_line.student_name,
'student_contact': student_line.student_contact,
'student_class': myclass,
'student_fm': myfm,
'student_memo': mymemo}
line_doc.append(line_temp)
temp = {
'studentclass_name': line.studentclass_name,
'studentclass_teacher': line.studentclass_teacher.teacher_name,
'studentclass_line': line_doc}
res_doc.append(temp)
docargs = {
'doc_ids': docids,
'doc_model': 'openacademy.studentclass',
'docs': res_doc}
return docargs
l Step 5在reports資料夾內創建__init__.py:
# -*- coding: utf-8 -*-
# Author: Peter Wu
from . import openacademy_studentclass_report
# -*- coding: utf-8 -*-
# Author: Peter Wu
from . import openacademy_studentclass_report
l Step 6在reports資料夾內創建openacademy_report.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<report id="report_openacademy_studentclass_id"
model="openacademy.studentclass"
string="學員班級報表"
report_type="qweb-html"
name="openacademy.studentclass_report"
file="openacademy.studentclass_report"
/>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<report id="report_openacademy_studentclass_id"
model="openacademy.studentclass"
string="學員班級報表"
report_type="qweb-html"
name="openacademy.studentclass_report"
file="openacademy.studentclass_report"
/>
</data>
</odoo>
l Step 7在reports資料夾內創建openacademy_studentclass_report.xml:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="studentclass_report">
<t t-call="cfprint.html_container">
<h1 class="col-12 text-center">學員班級報表列印中...</h1>
<h3 class="col-12 text-center">列印中...,請等待...</h3>
<script type="text/javascript">
var cfprint_addr = "127.0.0.1"; //列印伺服器監聽地址
var _delay_close = -1; //列印完成後關閉視窗的延時時長(毫秒), -1則表示不關閉
/*定義主表結構*/
var _tablestudentclass = {
"Name": "Studentclass",
"Cols": [
{"type": "str", "size": 20, "name": "studentclass_name", "required": false},
{"type": "str", "size": 50, "name": "studentclass_teacher", "required": false},
],
"Data": [ ]
};
/*定義從表結構*/
var _tablestudentclassLines = {
"Name": "studentclassLines",
"Cols": [
{"type": "str", "size": 20, "name": "student_no", "required": false},
{"type": "str", "size": 20, "name": "student_name", "required": false},
{"type": "str", "size": 20, "name": "student_contact", "required": false},
{"type": "str", "size": 20, "name": "student_class", "required": false},
{"type": "str", "size": 10, "name": "student_fm", "required": false},
{"type": "str", "size": 500, "name": "student_memo", "required": false},
],
"Data": [ ]
};
/*增加主表記錄*/
<t t-foreach="docs" t-as="o">
/*如果t t-if為True,就執行t-esc的部分*/
_tablestudentclass.Data.push({
"studentclass_name":"<t t-if="o['studentclass_name']" t-esc="o['studentclass_name']"/>",
"studentclass_teacher":"<t t-if="o['studentclass_teacher']" t-esc="o['studentclass_teacher']"/>",
});
/*增加從表記錄*/
<t t-foreach="o['studentclass_line']" t-as="lines">
_tablestudentclassLines.Data.push({
"student_no":"<t t-if="lines['student_no']" t-esc="lines['student_no']"/>",
"student_name":"<t t-if="lines['student_name']" t-esc="lines['student_name']"/>",
"student_contact":"<t t-if="lines['student_contact']" t-esc="lines['student_contact']"/>",
"student_class":"<t t-if="lines['student_class']" t-esc="lines['student_class']"/>",
"student_fm":"<t t-if="lines['student_fm']" t-esc="lines['student_fm']"/>",
"student_memo":"<t t-if="lines['student_memo']" t-esc="lines['student_memo']"/>",
});
</t>
</t>
var _data = {"template": "base64:<t t-esc="get_cf_template(user.env, 'studentclass_report')"/>", "ver": 4, "Copies": 1, "Duplex": 0, "Preview": 1, "Tables": []};
_data["Tables"].push(_tablestudentclass);
_data["Tables"].push(_tablestudentclassLines);
var _reportData = JSON.stringify(_data); //轉成json字元串
console.log(_reportData);
//生成資料之後,在cfprint_ext.js中會自動呼叫進行列印
</script>
</t>
</template>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="studentclass_report">
<t t-call="cfprint.html_container">
<h1 class="col-12 text-center">學員班級報表列印中...</h1>
<h3 class="col-12 text-center">列印中...,請等待...</h3>
<script type="text/javascript">
var cfprint_addr = "127.0.0.1"; //列印伺服器監聽地址
var _delay_close = -1; //列印完成後關閉視窗的延時時長(毫秒), -1則表示不關閉
/*定義主表結構*/
var _tablestudentclass = {
"Name": "Studentclass",
"Cols": [
{"type": "str", "size": 20, "name": "studentclass_name", "required": false},
{"type": "str", "size": 50, "name": "studentclass_teacher", "required": false},
],
"Data": [ ]
};
/*定義從表結構*/
var _tablestudentclassLines = {
"Name": "studentclassLines",
"Cols": [
{"type": "str", "size": 20, "name": "student_no", "required": false},
{"type": "str", "size": 20, "name": "student_name", "required": false},
{"type": "str", "size": 20, "name": "student_contact", "required": false},
{"type": "str", "size": 20, "name": "student_class", "required": false},
{"type": "str", "size": 10, "name": "student_fm", "required": false},
{"type": "str", "size": 500, "name": "student_memo", "required": false},
],
"Data": [ ]
};
/*增加主表記錄*/
<t t-foreach="docs" t-as="o">
/*如果t t-if為True,就執行t-esc的部分*/
_tablestudentclass.Data.push({
"studentclass_name":"<t t-if="o['studentclass_name']" t-esc="o['studentclass_name']"/>",
"studentclass_teacher":"<t t-if="o['studentclass_teacher']" t-esc="o['studentclass_teacher']"/>",
});
/*增加從表記錄*/
<t t-foreach="o['studentclass_line']" t-as="lines">
_tablestudentclassLines.Data.push({
"student_no":"<t t-if="lines['student_no']" t-esc="lines['student_no']"/>",
"student_name":"<t t-if="lines['student_name']" t-esc="lines['student_name']"/>",
"student_contact":"<t t-if="lines['student_contact']" t-esc="lines['student_contact']"/>",
"student_class":"<t t-if="lines['student_class']" t-esc="lines['student_class']"/>",
"student_fm":"<t t-if="lines['student_fm']" t-esc="lines['student_fm']"/>",
"student_memo":"<t t-if="lines['student_memo']" t-esc="lines['student_memo']"/>",
});
</t>
</t>
var _data = {"template": "base64:<t t-esc="get_cf_template(user.env, 'studentclass_report')"/>", "ver": 4, "Copies": 1, "Duplex": 0, "Preview": 1, "Tables": []};
_data["Tables"].push(_tablestudentclass);
_data["Tables"].push(_tablestudentclassLines);
var _reportData = JSON.stringify(_data); //轉成json字元串
console.log(_reportData);
//生成資料之後,在cfprint_ext.js中會自動呼叫進行列印
</script>
</t>
</template>
</data>
</odoo>
l Step 8在openacademy資料夾內修改__manifest__.py:
'data': [
'reports/openacademy_report.xml',
'reports/openacademy_studentclass_report.xml',
],
'data': [
'reports/openacademy_report.xml',
'reports/openacademy_studentclass_report.xml',
],
l Step 9設定康虎雲報表模板:
Settings > Activate the developer mode
Settings > Technical > CFPrint Template Management > Create
在Template ID與Name填入報表模型名稱,此例為studentclass_report,並將任一範例fr3檔上傳至Template
Settings > Activate the developer mode
Settings > Technical > CFPrint Template Management > Create
在Template ID與Name填入報表模型名稱,此例為studentclass_report,並將任一範例fr3檔上傳至Template
l Step 10安裝或更新openacademy模組之後,回到Windows系統試著列印報表,此時會發生錯誤,請點選「設計」修改報表。
l Step 11可開啟既有的範例報表來編輯,並點選「報表」 > 「資料」以選取報表資料集,重新編輯完成後請將fr3檔重新上傳至Template。
l Step 12回到Windows系統再次試著列印報表,若一切設定正確,應可看見預覽列印的成果。
Odoo設定
l 排程執行,Number of Calls為-1表示執行次數無限:
Settings > Activate the developer mode
Settings > Technical > Scheduled Actions
Settings > Activate the developer mode
Settings > Technical > Scheduled Actions
l 序號規劃:
Settings > Activate the developer mode
Settings > Technical > Sequences
Settings > Activate the developer mode
Settings > Technical > Sequences
l 備份設定,Odoo 12 Community Version無此功能:
Settings > Activate the developer mode
Settings > Technical > Configure back-ups
Settings > Activate the developer mode
Settings > Technical > Configure back-ups
沒有留言:
張貼留言