因为这种搜索使用太频繁,所以花了点时间从10升级到了11,12,13。
odoo13版本新插件的地址,https://apps.odoo.com/apps/modules/13.0/app_search_range_date_number/
odoo12版本新插件的地址,https://apps.odoo.com/apps/modules/12.0/app_search_range_date_number/
odoo11版本新插件的地址,https://apps.odoo.com/apps/modules/11.0/app_search_range_date_number/
10版本可以免费下载的,是在别人基础上改的。 https://github.com/guohuadeng/app-odoo/tree/master/app_search_range
odoo11和12的前端进行了极大的改动,架构和Api什么的全改了,涉及前端的插件,如果要升级成本一下子高了很多。半桶水折腾了一天,记录下涨个经验。
1.官网文档,这篇一定要看下,少很多坑
https://www.sunpop.cn/documentation/13.0/reference/javascript_cheatsheet.html
https://www.odoo.com/documentation/11.0/reference/javascript_cheatsheet.html
First of all, remember that the first rule of customizing odoo with JS is: try to do it in python. This may seem strange, but the python framework is quite extensible, and many behaviours can be done simply with a touch of xml or python. This has usually a lower cost of maintenance than working with JS:
- the JS framework tends to change more, so JS code needs to be more frequently updated
- it is often more difficult to implement a customized behaviour if it needs to communicate with the server and properly integrate with the javascript framework. There are many small details taken care by the framework that customized code needs to replicate. For example, responsiveness, or updating the url, or displaying data without flickering.
意思是能用python就python,用._rpc方法调用后台python的代码。前端还在不断改,不急的话等稳定再动手。
2.还是官网文档,了解架构
https://www.odoo.com/documentation/11.0/reference/javascript_reference.html
主要的view的类型原来1个js给拆分成了4个: view, controller, renderer, model,逻辑更清晰,但门槛也高了不少。很多原来的api没了,四处分散......笨办法是F12断点调试来找新办法。
3. 开始代码
11的教程要看下,有10的基础会过得很快。
https://www.odoo.com/documentation/11.0/howtos/web.html#widget-helpers
基本上还是
- 3.1 多继承,不管是qweb还是js,都多利用现有的
- 3.2 规划好在哪个布局和js上改。本例主要是在searchView
- 3.3 写qweb做好组件的布局
- 3.4 写js处理事件
- 3.5 写好翻译po和插件描述
3.3 写qweb做好组件的布局
viewstemplate_view.xml,将样式和js放入项目
<template id="assets_backend" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> <link rel="stylesheet" type="text/css" href="/app_search_range_date_number/static/src/css/app_search_range_date_number.css"/> <script type="text/javascript" src="/app_search_range_date_number/static/src/js/search_view.js"></script> </xpath> </template>
staticsrcxmlbase.xml,放dom,以日期为例
<!--日期类型搜索--> <t t-name="odooApp.SearchDate"> <span class="app-search-range-date pull-left ml4 mr4"> <select class="app_select_field_date o_input o_field_widget mt4" > <option t-foreach="date_fields" t-as="field" t-att-value="field[0]" t-att-type="field[2]"> <t t-esc="field[1]"/> </option> </select> </span> <span class="pull-left o_datepicker o_field_date o_field_widget ml4 mt4"> <input class="app_start_date o_datepicker_input o_input" size="14" placeholder="Start date" type="text" title="Press Enter to search"/> </span> <span class="pull-left o_datepicker o_field_date o_field_widget ml4 mt4"> <input class="app_end_date o_datepicker_input o_input" size="14" placeholder="End date" type="text" title="Press Enter to search" /> </span> </t>
3.4 写js处理事件
staticsrcjssearch_view.js,继承扩展SearchView,以核心扩展domain为例。注意时区的处理,odoo的时区永远是个坑,多测试
//扩展domain加上日期时间范围 build_search_data: function () { data = this._super.apply(this, arguments); var appDomain = this.app_search(); data.domains.push(appDomain); return data; }, //返回范围数组 app_search: function() { var self = this; var domain = []; // 注意,date和datetime型的处理是不同的,已处理完 if ($(document).find('.app_select_field_date')) { var start_date = $(document).find('.app_start_date').val(), end_date = $(document).find('.app_end_date').val(), field = $(document).find('.app_select_field_date').val(), field_type = 'datetime'; var tz = session.user_context.tz, start_utc, end_utc; _.each(self.fields, function (value, key, list) { if (value.name == field) { field_type = value.type; return false; } }); moment.locale(tz); var l10n = _t.database.parameters; if (start_date) { if (field_type === 'date') { //日期类型,无须utc处理 start_date = moment(moment(start_date, time.strftime_to_moment_format(l10n.date_format))).format('YYYY-MM-DD'); domain.push([field, '>=', start_date]); } else { //日期时间,处理utc start_date = moment(moment(start_date, time.strftime_to_moment_format(l10n.date_format))).format('YYYY-MM-DD 00:00:00'); start_utc = moment(start_date) domain.push([field, '>=', start_utc]); } } if (end_date) { if (field_type === 'date') { end_date = moment(moment(end_date, time.strftime_to_moment_format(l10n.date_format))).format('YYYY-MM-DD'); domain.push([field, '<=', end_date]); } else { end_date = moment(moment(end_date, time.strftime_to_moment_format(l10n.date_format))).format('YYYY-MM-DD 00:00:00'); end_utc = moment(end_date) domain.push([field, '<=', end_utc]); } } } if ($(document).find('.app_select_field_number')) { var start_range = $(document).find('.app_start_number').val(), end_range = $(document).find('.app_end_number').val(), range_field = $(document).find('.app_select_field_number').val(); if (start_range) { domain.push([range_field, '>=', parseInt(start_range)]); } if (end_range) { domain.push([range_field, '<=', parseInt(end_range)]); } } return domain; },
3.5 写好翻译po和插件描述
这个很重要,至少中英双语才对得起odoo这么好的框架。程序是拿来用的,好东西要靠细节打磨出来的。