運用 Odoo 知識將必要的部分拆解出來,再搭配 GenAI 來新增功能,這次實作去年的 Day11 的功能,詳細的內容可以參考下面連結。
[Day11] 圖書館管理系統 ISBN 驗證跟預設搜尋選項
"""
# books.py
from odoo import models, fields
class Books(models.Model):
    _name = 'library.books'
    _description = 'Library Books'
    name = fields.Char(string='Book Name', required=True)
    isbn = fields.Char(string='ISBN')
    book_type = fields.Selection([
        ('paper', 'Paper'),
        ('ebook', 'E-Book'),
        ('other', 'Other')],
        string='Book Type', default='paper')
    description = fields.Text(string='Description')
    stock = fields.Integer(string='Stock')
    price_twd = fields.Float(string='Price (TWD)')
    average_rating = fields.Float(string='Average Rating', digits=(2, 2))
    publish_date = fields.Date(string='Publish Date')
    last_rent_date = fields.Datetime(string='Last Rent Date')
    rentable = fields.Boolean(string='Rentable', default=True)
    cover_image = fields.Binary(string='Cover Image')
"""
"""
book_views.xml
<odoo>
    <record id="view_book_form" model="ir.ui.view">
        <field name="name">library.books.form</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <form string="Book">
                <sheet>
                    <group>
                        <field name="name"/>
                        <field name="isbn"/>
                        <field name="book_type"/>
                        <field name="description"/>
                        <field name="stock"/>
                        <field name="price_twd"/>
                        <field name="average_rating"/>
                        <field name="publish_date"/>
                        <field name="last_rent_date"/>
                        <field name="rentable"/>
                        <field name="cover_image" widget="image"/>
                    </group>
                </sheet>
            </form>
        </field>
    </record>
    <record id="view_book_tree" model="ir.ui.view">
        <field name="name">library.books.tree</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <tree string="Books">
                <field name="name"/>
                <field name="isbn"/>
                <field name="book_type"/>
                <field name="stock"/>
                <field name="price_twd"/>
                <field name="average_rating"/>
                <field name="publish_date"/>
                <field name="last_rent_date"/>
                <field name="rentable"/>
            </tree>
        </field>
    </record>
</odoo>
"""
上面是使用 Odoo 17 客製化模組的 Model 和 View,我要新增一個功能 Check ISBN validation (檢查 ISBN 是否合理),並且是在新增 books 的 Form View 裡面,用 Button (按鈕) 來觸發,請用繁體中文
你可以在 Odoo 17 模組中新增一個檢查 ISBN 是否合理的功能,並在 Form View 中透過按鈕來觸發這個檢查。以下是具體的步驟和範例程式碼:
修改 Model (books.py):新增一個方法來檢查 ISBN,並透過按鈕來觸發該方法。
更新 View (book_views.xml):在 Form View 中新增一個按鈕來執行 ISBN 檢查。
首先,我們在 Books 模型中新增一個 check_isbn 方法,這個方法會檢查 ISBN 是否有效。
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class Books(models.Model):
    _name = 'library.books'
    _description = 'Library Books'
    name = fields.Char(string='Book Name', required=True)
    isbn = fields.Char(string='ISBN')
    book_type = fields.Selection([
        ('paper', 'Paper'),
        ('ebook', 'E-Book'),
        ('other', 'Other')],
        string='Book Type', default='paper')
    description = fields.Text(string='Description')
    stock = fields.Integer(string='Stock')
    price_twd = fields.Float(string='Price (TWD)')
    average_rating = fields.Float(string='Average Rating', digits=(2, 2))
    publish_date = fields.Date(string='Publish Date')
    last_rent_date = fields.Datetime(string='Last Rent Date')
    rentable = fields.Boolean(string='Rentable', default=True)
    cover_image = fields.Binary(string='Cover Image')
    @api.model
    def is_valid_isbn(self, isbn):
        """簡單的 ISBN 驗證方法,支援 ISBN-10 和 ISBN-13"""
        isbn = isbn.replace('-', '').replace(' ', '')
        if len(isbn) == 10:
            total = sum((10 - i) * int(x) for i, x in enumerate(isbn[:9])) + (10 if isbn[-1] == 'X' else int(isbn[-1]))
            return total % 11 == 0
        elif len(isbn) == 13:
            total = sum(int(x) * (3 if i % 2 else 1) for i, x in enumerate(isbn))
            return total % 10 == 0
        return False
    def check_isbn(self):
        """檢查 ISBN,並在無效時拋出錯誤"""
        if not self.isbn:
            raise ValidationError("ISBN 欄位不能為空。")
        if not self.is_valid_isbn(self.isbn):
            raise ValidationError("輸入的 ISBN 無效,請檢查後再試。")
        return True
在這裡,我們新增了 is_valid_isbn 方法來進行 ISBN 驗證。此方法會檢查 ISBN 是符合 ISBN-10 或 ISBN-13 規範。如果驗證失敗,check_isbn 會丟出 ValidationError。
接下來,我們在 Form View 裡新增一個按鈕來觸發 ISBN 檢查。
<odoo>
    <record id="view_book_form" model="ir.ui.view">
        <field name="name">library.books.form</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <form string="Book">
                <sheet>
                    <group>
                        <field name="name"/>
                        <field name="isbn"/>
                        <field name="book_type"/>
                        <field name="description"/>
                        <field name="stock"/>
                        <field name="price_twd"/>
                        <field name="average_rating"/>
                        <field name="publish_date"/>
                        <field name="last_rent_date"/>
                        <field name="rentable"/>
                        <field name="cover_image" widget="image"/>
                    </group>
                    <footer>
                        <button name="check_isbn" string="檢查 ISBN" type="object" class="btn-primary"/>
                    </footer>
                </sheet>
            </form>
        </field>
    </record>
</odoo>
當你在書本的 Form View 中點擊「檢查 ISBN」按鈕時,系統會自動驗證輸入的 ISBN 是否有效,並在無效時顯示錯誤訊息。
這樣的設計能幫助用戶確保輸入的 ISBN 是有效的,也提升了資料的準確性。
請再新增 View 裡新增 search view
在 Odoo 中,你可以透過 search view 來讓使用者搜尋特定欄位的資料。你可以在 book_views.xml 中新增一個 search view,讓使用者能夠根據書本名稱、ISBN 或其他欄位進行搜尋。
下面是如何修改 book_views.xml,以新增 search view:
<odoo>
    <record id="view_book_form" model="ir.ui.view">
        <field name="name">library.books.form</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <form string="Book">
                <sheet>
                    <group>
                        <field name="name"/>
                        <field name="isbn"/>
                        <field name="book_type"/>
                        <field name="description"/>
                        <field name="stock"/>
                        <field name="price_twd"/>
                        <field name="average_rating"/>
                        <field name="publish_date"/>
                        <field name="last_rent_date"/>
                        <field name="rentable"/>
                        <field name="cover_image" widget="image"/>
                    </group>
                    <footer>
                        <button name="check_isbn" string="檢查 ISBN" type="object" class="btn-primary"/>
                    </footer>
                </sheet>
            </form>
        </field>
    </record>
    <record id="view_book_tree" model="ir.ui.view">
        <field name="name">library.books.tree</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <tree string="Books">
                <field name="name"/>
                <field name="isbn"/>
                <field name="book_type"/>
                <field name="stock"/>
                <field name="price_twd"/>
                <field name="average_rating"/>
                <field name="publish_date"/>
                <field name="last_rent_date"/>
                <field name="rentable"/>
            </tree>
        </field>
    </record>
    <!-- 新增 search view -->
    <record id="view_book_search" model="ir.ui.view">
        <field name="name">library.books.search</field>
        <field name="model">library.books</field>
        <field name="arch" type="xml">
            <search string="Search Books">
                <field name="name" string="Book Name"/>
                <field name="isbn" string="ISBN"/>
                <field name="book_type" string="Book Type"/>
                <field name="stock" string="Stock"/>
                <filter name="filter_rentable" string="Rentable" domain="[('rentable', '=', True)]"/>
                <filter name="filter_not_rentable" string="Not Rentable" domain="[('rentable', '=', False)]"/>
                <group expand="0" string="Group By">
                    <filter string="Book Type" group_by="book_type"/>
                    <filter string="Rentable" group_by="rentable"/>
                </group>
            </search>
        </field>
    </record>
</odoo>
當你進入書本的 tree view 或 list view 時,會看到上方的搜尋欄位,使用者可以依照書本名稱、ISBN 進行篩選,也可以透過過濾器篩選出可租借或不可租借的書籍,並且可以根據書本類型或租借狀態來群組顯示。
這樣可以大幅提升使用者的搜尋和篩選體驗,方便快速找到所需的書籍資料。