
1. Odoo 18二次开发入门为什么选择模块化开发第一次接触Odoo二次开发时很多人会问为什么不直接修改源码这个问题我也纠结过。直到有次升级系统发现自己改过的核心代码全被覆盖才真正理解模块化开发的价值。Odoo的模块化设计就像乐高积木每个业务功能都是独立的模块既能灵活组合又互不干扰。最近给一家电商客户做库存预警系统时我们完全通过新建模块实现功能。当客户临时需要增加供应商管理功能时只需再开发一个供应商模块两个模块通过依赖关系完美配合。这种开发方式让系统维护成本降低了60%升级时再也不用提心吊胆。2. 从零搭建库存预警模块2.1 创建模块脚手架先确保你已经配置好Odoo 18开发环境。打开终端进入自定义模块目录通常放在addons文件夹执行这个神奇的命令python ../odoo-bin scaffold stock_alert my_addons这个命令会在my_addons目录下生成stock_alert模块的初始结构。我习惯用业务功能命名模块比如这里的stock_alert就明确表示了库存预警功能。生成的文件结构中最需要关注的是__manifest__.py模块的身份证models/数据模型的家views/用户界面的工作室security/权限控制中心2.2 配置manifest文件打开__manifest__.py这是模块的配置中心。最近做项目时发现几个容易踩的坑{ name: 库存预警系统, # 用中文名方便终端用户识别 version: 1.0, summary: 实时监控库存水位自动触发补货预警, description: 本模块提供 - 多级库存阈值设置 - 预警规则自定义 - 自动通知采购负责人 - 可视化预警仪表盘 , # 详细描述会显示在应用商店 author: 你的名字, website: https://yourdomain.com, category: Inventory, # 必须使用Odoo标准分类 depends: [stock], # 依赖的模块库存功能基于stock模块 data: [ security/ir.model.access.csv, views/stock_warehouse_views.xml, ], demo: [], # 演示数据 installable: True, application: True, license: LGPL-3, }特别注意depends配置有次我忘记添加mail模块依赖导致消息通知功能报错排查了半天才发现是这个原因。3. 构建库存预警数据模型3.1 设计预警规则模型在models/stock_alert.py中定义核心模型from odoo import models, fields, api class StockAlertRule(models.Model): _name stock.alert.rule _description 库存预警规则 name fields.Char(规则名称, requiredTrue) active fields.Boolean(启用, defaultTrue) warehouse_id fields.Many2one( stock.warehouse, 仓库, help应用该规则的仓库 ) product_category_id fields.Many2one( product.category, 产品分类, help应用该规则的产品分类 ) threshold_type fields.Selection([ (quantity, 数量), (value, 金额), (day, 天数)], 阈值类型, defaultquantity ) warning_threshold fields.Float(预警阈值) critical_threshold fields.Float(严重阈值) action_ids fields.One2many( stock.alert.action, rule_id, 触发动作 ) _sql_constraints [ (threshold_check, CHECK(warning_threshold critical_threshold), 预警阈值必须小于严重阈值) ]这个模型设计有几个实用技巧使用active字段实现软删除通过help参数添加字段说明使用SQL约束保证业务逻辑正确性采用标准的_name命名规范模块名.模型名3.2 添加关联模型继续在同一个文件中添加动作模型class StockAlertAction(models.Model): _name stock.alert.action _description 预警触发动作 rule_id fields.Many2one(stock.alert.rule, 所属规则) action_type fields.Selection([ (email, 发送邮件), (task, 创建任务), (order, 生成采购订单)], 动作类型, requiredTrue ) recipient_ids fields.Many2many( res.users, string接收人 ) template_id fields.Many2one( mail.template, 邮件模板, domain[(model_id.model, , stock.alert.rule)] ) api.onchange(action_type) def _onchange_action_type(self): if self.action_type email: return {domain: {template_id: [ (model_id.model, , stock.alert.rule) ]}}这里展示了Odoo强大的动态域功能当动作类型选择email时模板选择框只显示适用于库存预警规则的邮件模板。4. 实现业务逻辑4.1 添加定时检查方法在StockAlertRule类中添加核心业务逻辑def _check_stock_levels(self): 核心方法检查库存水平并触发预警 ProductProduct self.env[product.product] StockQuant self.env[stock.quant] for rule in self: domain [] if rule.warehouse_id: domain.append((location_id.warehouse_id, , rule.warehouse_id.id)) if rule.product_category_id: domain.append((product_id.categ_id, , rule.product_category_id.id)) quants StockQuant.search(domain) for quant in quants: if rule.threshold_type quantity: value quant.quantity elif rule.threshold_type value: value quant.inventory_value else: # days value (fields.Date.today() - quant.in_date.date()).days if value rule.critical_threshold: self._trigger_actions(quant, critical) elif value rule.warning_threshold: self._trigger_actions(quant, warning) def _trigger_actions(self, quant, level): 触发配置的动作 for action in self.action_ids: if action.action_type email: self._send_alert_email(action, quant, level) elif action.action_type task: self._create_alert_task(action, quant, level) elif action.action_type order: self._generate_purchase_order(action, quant, level)这段代码实现了根据规则条件构建查询域获取库存数据并计算比较值根据阈值触发不同级别的预警执行配置的各类动作4.2 实现邮件通知功能继续添加邮件发送方法def _send_alert_email(self, action, quant, level): 发送预警邮件 if not action.recipient_ids or not action.template_id: return template action.template_id.with_context( default_modelstock.alert.rule, default_res_idself.id, quantquant, levellevel, ruleself ) for recipient in action.recipient_ids: template.send_mail(recipient.id, force_sendTrue)这里使用了Odoo的邮件模板系统通过上下文传递动态数据。建议提前在后台配置好邮件模板包含类似这样的内容主题库存预警 - ${level critical and 严重 or 警告}级别 内容 产品 ${quant.product_id.name} 在 ${quant.location_id.complete_name} 的库存${rule.threshold_type}已触发${level critical and 严重 or 警告}预警 当前值${value} 阈值${level critical and rule.critical_threshold or rule.warning_threshold}5. 设计用户界面5.1 表单视图设计在views/stock_warehouse_views.xml中添加record idview_stock_alert_rule_form modelir.ui.view field namenamestock.alert.rule.form/field field namemodelstock.alert.rule/field field namearch typexml form header button name_check_stock_levels string立即检查 typeobject classoe_highlight/ field nameactive widgetboolean_button/ /header sheet group group field namename/ field namewarehouse_id/ field nameproduct_category_id/ /group group field namethreshold_type/ field namewarning_threshold/ field namecritical_threshold/ /group /group notebook page string触发动作 field nameaction_ids tree editablebottom field nameaction_type/ field namerecipient_ids widgetmany2many_tags/ field nametemplate_id/ /tree /field /page page string高级设置 !-- 可以添加更多高级选项 -- /page /notebook /sheet /form /field /record这个表单视图包含了顶部按钮手动触发库存检查基本信息区域规则名称、适用范围阈值设置区域预警参数配置标签页动作配置和高级设置5.2 列表视图设计继续添加列表视图record idview_stock_alert_rule_tree modelir.ui.view field namenamestock.alert.rule.tree/field field namemodelstock.alert.rule/field field namearch typexml tree field namename/ field namewarehouse_id/ field nameproduct_category_id/ field namethreshold_type/ field namewarning_threshold/ field namecritical_threshold/ field nameactive/ /tree /field /record5.3 添加菜单和动作最后配置菜单入口!-- 动作定义 -- record idaction_stock_alert_rule modelir.actions.act_window field namename库存预警规则/field field nameres_modelstock.alert.rule/field field nameview_modetree,form/field /record !-- 菜单定义 -- menuitem idmenu_stock_alert_root name库存预警 parentstock.menu_stock_root/ menuitem idmenu_stock_alert_rules name预警规则 parentmenu_stock_alert_root actionaction_stock_alert_rule/这里将新模块的菜单挂载到了库存管理的根菜单下保持了系统的整体性。6. 配置权限和安全规则6.1 定义访问权限在security/ir.model.access.csv中添加id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_stock_alert_rule,stock.alert.rule,model_stock_alert_rule,base.group_user,1,1,1,1 access_stock_alert_action,stock.alert.action,model_stock_alert_action,base.group_user,1,1,1,1这个配置给普通用户(base.group_user)赋予了完整的CRUD权限。如果需要对不同角色设置不同权限可以创建更多记录。6.2 添加记录规则有时候需要更细粒度的权限控制可以在security/stock_alert_security.xml中添加记录规则record idstock_alert_rule_user_rule modelir.rule field namename库存预警规则用户权限/field field namemodel_id refmodel_stock_alert_rule/ field namedomain_force[|, (warehouse_id, , False), (warehouse_id.manager_id, , user.id)]/field field namegroups eval[(4, ref(stock.group_stock_user))]/ /record这条规则限制普通库存用户只能看到自己管理的仓库的预警规则。7. 测试与部署7.1 开发环境测试安装模块前建议先运行Odoo的测试模式python odoo-bin -i stock_alert --test-enable这会自动执行模块中的测试用例。我们可以在tests/目录下添加测试类from odoo.tests.common import TransactionCase class TestStockAlert(TransactionCase): def setUp(self): super().setUp() self.Warehouse self.env[stock.warehouse] self.Product self.env[product.product] self.AlertRule self.env[stock.alert.rule] self.warehouse self.Warehouse.create({ name: 测试仓库, code: TEST }) self.product self.Product.create({ name: 测试产品, type: product, categ_id: self.env.ref(product.product_category_all).id }) def test_alert_trigger(self): rule self.AlertRule.create({ name: 测试规则, warehouse_id: self.warehouse.id, threshold_type: quantity, warning_threshold: 50, critical_threshold: 20 }) # 模拟库存变化 self.env[stock.quant].create({ product_id: self.product.id, location_id: self.warehouse.lot_stock_id.id, quantity: 10 }) # 执行检查 rule._check_stock_levels() # 验证是否触发了严重预警 # 这里可以添加更多断言7.2 生产环境部署当测试通过后在生产环境安装模块时建议先在测试环境完整验证备份生产数据库使用--stop-after-init参数先检查依赖python odoo-bin -i stock_alert --stop-after-init确认无误后再正式安装8. 扩展与优化8.1 添加仪表盘视图为了让预警信息更直观可以添加看板视图record idview_stock_alert_kanban modelir.ui.view field namenamestock.alert.kanban/field field namemodelstock.alert.rule/field field namearch typexml kanban default_group_bywarehouse_id templates t t-namekanban-box div classoe_kanban_card div classoe_kanban_content strongfield namename//strong div仓库: field namewarehouse_id//div div产品分类: field nameproduct_category_id//div div classprogress div classprogress-bar roleprogressbar t-att-stylewidth: (100 * (warning_threshold - critical_threshold) / warning_threshold) % /div /div /div /div /t /templates /kanban /field /record8.2 实现自动定时检查为了让系统自动运行库存检查可以添加定时任务from odoo import api, models class IrCron(models.Model): _inherit ir.cron api.model def _setup_stock_alert_cron(self): 创建或更新定时任务 cron self.env.ref(stock_alert.cron_stock_alert, raise_if_not_foundFalse) if not cron: cron self.env[ir.cron].create({ name: 库存预警检查, model_id: self.env.ref(stock_alert.model_stock_alert_rule).id, state: code, code: model._check_stock_levels(), interval_number: 1, interval_type: hours, numbercall: -1, doall: False, active: True, }) return cron然后在__manifest__.py的data列表中添加data: [ security/ir.model.access.csv, views/stock_warehouse_views.xml, data/ir_cron.xml, ],8.3 性能优化建议当产品数量很多时库存检查可能会比较耗时。可以考虑以下优化分批处理将检查任务分成多个小任务添加索引在频繁查询的字段上添加数据库索引缓存结果对不常变动的数据使用缓存异步执行将耗时操作放到后台任务队列def _check_stock_levels_batch(self, batch_size100): 分批检查库存 for i in range(0, len(self), batch_size): batch self[i:ibatch_size] batch._check_stock_levels() self.env.cr.commit() # 定期提交事务