Merge lp:~therp-nl/web-addons/7.0-web_relativedelta into lp:~webaddons-core-editors/web-addons/7.0

Proposed by Holger Brunn (Therp)
Status: Rejected
Rejected by: Holger Brunn (Therp)
Proposed branch: lp:~therp-nl/web-addons/7.0-web_relativedelta
Merge into: lp:~webaddons-core-editors/web-addons/7.0
Prerequisite: lp:~therp-nl/web-addons/7.0-web_relativedelta_momentjs
Diff against target: 377 lines (+352/-0)
4 files modified
web_relativedelta/__init__.py (+20/-0)
web_relativedelta/__openerp__.py (+77/-0)
web_relativedelta/static/src/js/web_relativedelta.js (+179/-0)
web_relativedelta/static/test/web_relativedelta.js (+76/-0)
To merge this branch: bzr merge lp:~therp-nl/web-addons/7.0-web_relativedelta
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) Needs Resubmitting
Stefan Rijnhart (Opener) Needs Information
Review via email: mp+217653@code.launchpad.net

Description of the change

Reimplementation of relativedelta for use in client side domains in the hope that it sucks less than the one provided in upstream.

This uses http://momentjs.com which was committed separately to simplify the review.

To post a comment you must log in.
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks! Code looks clean enough. But I was wondering about the rationale. Can you give an example how to use this in a custom module (I assume)? Why do you 'hope' it sucks less, I mean, what is bad about the standard implementation in the OpenERP web client? Why not propose this into upstream OpenERP web client trunk then?

review: Needs Information
Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

The hope part is modesty and the fact that I'm not sure that the day= parameter is handled correctly.

What is bad about the standard implementation:
- no weekday, so there's no chance to have filters for the current (calendar) week, next week, etc
- no datetimes, only date
- no hours, minute, second
- negative days are not properly implemented

For an example:
Just use relativedelta as usual, but without the drawbacks as described above

36. By Holger Brunn (Therp)

[IMP] sanitize input for absolute values
[IMP] handle day parameter correctly (don't cross month boundaries)

Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :
37. By Holger Brunn (Therp)

[FIX] actually use relativedelta's semantics for weekdays

38. By Holger Brunn (Therp)

[ADD] tests
[ADD] more detail in manifest

39. By Holger Brunn (Therp)

[ADD] actually add tests

Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

This project is now hosted on https://github.com/OCA/web. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

review: Needs Resubmitting
Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

Unmerged revisions

39. By Holger Brunn (Therp)

[ADD] actually add tests

38. By Holger Brunn (Therp)

[ADD] tests
[ADD] more detail in manifest

37. By Holger Brunn (Therp)

[FIX] actually use relativedelta's semantics for weekdays

36. By Holger Brunn (Therp)

[IMP] sanitize input for absolute values
[IMP] handle day parameter correctly (don't cross month boundaries)

35. By Holger Brunn (Therp)

[ADD] web_relativedelta

34. By Holger Brunn (Therp)

[ADD] moment.js

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'web_relativedelta/__init__.py'
2--- web_relativedelta/__init__.py 1970-01-01 00:00:00 +0000
3+++ web_relativedelta/__init__.py 2014-07-01 06:33:47 +0000
4@@ -0,0 +1,20 @@
5+# -*- coding: utf-8 -*-
6+##############################################################################
7+#
8+# OpenERP, Open Source Management Solution
9+# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
10+#
11+# This program is free software: you can redistribute it and/or modify
12+# it under the terms of the GNU Affero General Public License as
13+# published by the Free Software Foundation, either version 3 of the
14+# License, or (at your option) any later version.
15+#
16+# This program is distributed in the hope that it will be useful,
17+# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+# GNU Affero General Public License for more details.
20+#
21+# You should have received a copy of the GNU Affero General Public License
22+# along with this program. If not, see <http://www.gnu.org/licenses/>.
23+#
24+##############################################################################
25
26=== added file 'web_relativedelta/__openerp__.py'
27--- web_relativedelta/__openerp__.py 1970-01-01 00:00:00 +0000
28+++ web_relativedelta/__openerp__.py 2014-07-01 06:33:47 +0000
29@@ -0,0 +1,77 @@
30+# -*- coding: utf-8 -*-
31+##############################################################################
32+#
33+# OpenERP, Open Source Management Solution
34+# This module copyright (C) 2014 Therp BV (<http://therp.nl>).
35+#
36+# This program is free software: you can redistribute it and/or modify
37+# it under the terms of the GNU Affero General Public License as
38+# published by the Free Software Foundation, either version 3 of the
39+# License, or (at your option) any later version.
40+#
41+# This program is distributed in the hope that it will be useful,
42+# but WITHOUT ANY WARRANTY; without even the implied warranty of
43+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44+# GNU Affero General Public License for more details.
45+#
46+# You should have received a copy of the GNU Affero General Public License
47+# along with this program. If not, see <http://www.gnu.org/licenses/>.
48+#
49+##############################################################################
50+{
51+ "name": "More pythonic relativedelta",
52+ "version": "1.0",
53+ "author": "Therp BV",
54+ "license": "AGPL-3",
55+ "complexity": "normal",
56+ "description": """
57+Introduction
58+============
59+
60+This addon provides a reimplementation of OpenERP's pyjs relativedelta class
61+using Moment.js (http://momentjs.com).
62+
63+On top of what you can do with the original, you can use
64+
65+- datetime objects
66+- relativedelta(hour=0-23, hours=0-23)
67+- relativedelta(minute=0-59, minutes=0-59)
68+- relativedelta(seconds=0-59, seconds=0-59)
69+- relativedelta(weekday=0) [MO] ... weekday=6 [SU]
70+
71+ - there's no MO(+n) syntax, but that can be simulated by
72+ relativedelta(weeks=+(n-1), days=1, weekday=0), this week's monday would
73+ be relativedelta(weeks=-1, days=1, weekday=0) etc.
74+
75+- all of them together in a predictable manner as detailed in https://labix.org/python-dateutil#head-72c4689ec5608067d118b9143cef6bdffb6dad4e
76+
77+Usage
78+=====
79+
80+Simply depend on web_relativedelta and enjoy most of python's relativedelta
81+functionality
82+ """,
83+ "category": "Dependency",
84+ "depends": [
85+ 'web',
86+ ],
87+ "data": [
88+ ],
89+ "js": [
90+ 'static/lib/moment.js',
91+ 'static/src/js/web_relativedelta.js'
92+ ],
93+ "css": [
94+ ],
95+ "qweb": [
96+ ],
97+ "test": [
98+ 'static/test/web_relativedelta.js',
99+ ],
100+ "auto_install": False,
101+ "installable": True,
102+ "application": False,
103+ "external_dependencies": {
104+ 'python': [],
105+ },
106+}
107
108=== added directory 'web_relativedelta/static/src'
109=== added directory 'web_relativedelta/static/src/img'
110=== added file 'web_relativedelta/static/src/img/icon.png'
111Binary files web_relativedelta/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and web_relativedelta/static/src/img/icon.png 2014-07-01 06:33:47 +0000 differ
112=== added directory 'web_relativedelta/static/src/js'
113=== added file 'web_relativedelta/static/src/js/web_relativedelta.js'
114--- web_relativedelta/static/src/js/web_relativedelta.js 1970-01-01 00:00:00 +0000
115+++ web_relativedelta/static/src/js/web_relativedelta.js 2014-07-01 06:33:47 +0000
116@@ -0,0 +1,179 @@
117+//-*- coding: utf-8 -*-
118+//############################################################################
119+//
120+// OpenERP, Open Source Management Solution
121+// This module copyright (C) 2014 Therp BV (<http://therp.nl>).
122+//
123+// This program is free software: you can redistribute it and/or modify
124+// it under the terms of the GNU Affero General Public License as
125+// published by the Free Software Foundation, either version 3 of the
126+// License, or (at your option) any later version.
127+//
128+// This program is distributed in the hope that it will be useful,
129+// but WITHOUT ANY WARRANTY; without even the implied warranty of
130+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
131+// GNU Affero General Public License for more details.
132+//
133+// You should have received a copy of the GNU Affero General Public License
134+// along with this program. If not, see <http://www.gnu.org/licenses/>.
135+//
136+//############################################################################
137+
138+openerp.web_relativedelta = function(openerp)
139+{
140+ var relativedelta = py.type('relativedelta', null,
141+ {
142+ __init__: function()
143+ {
144+ this.ops = py.PY_parseArgs(
145+ arguments,
146+ [
147+ ['year', null],
148+ ['years', null],
149+ ['month', null],
150+ ['months', null],
151+ ['day', null],
152+ ['days', null],
153+ ['hour', null],
154+ ['hours', null],
155+ ['minute', null],
156+ ['minutes', null],
157+ ['second', null],
158+ ['seconds', null],
159+ ['weeks', null],
160+ ['weekday', null],
161+ ]);
162+ },
163+ __add__: function(other)
164+ {
165+ if(other.__name__ != 'date' && other.__name__ != 'datetime')
166+ {
167+ return py.NotImplemented;
168+ }
169+
170+ var result = moment({
171+ year: other.year,
172+ //january==0 in moment.js
173+ month: other.month - 1,
174+ day: other.day,
175+ hour: other.hour,
176+ minute: other.minute,
177+ second: other.second});
178+
179+ if(this.ops.year)
180+ {
181+ result.year(Math.abs(this.ops.year._value));
182+ }
183+ if(this.ops.years)
184+ {
185+ result.add('years', this.ops.years._value);
186+ }
187+ if(this.ops.month)
188+ {
189+ //january==0 in moment.js
190+ result.month(Math.abs(this.ops.month._value % 13) - 1);
191+ }
192+ if(this.ops.months)
193+ {
194+ result.add('months', this.ops.months._value);
195+ }
196+ if(this.ops.day)
197+ {
198+ result = result.clone()
199+ .endOf('month')
200+ .hours(result.hours())
201+ .minutes(result.minutes())
202+ .seconds(result.seconds())
203+ .max(result.clone()
204+ .date(Math.abs(this.ops.day._value)));
205+ }
206+ if(this.ops.days)
207+ {
208+ result.add('days', this.ops.days._value)
209+ }
210+ if(this.ops.weeks)
211+ {
212+ result.add('days', this.ops.weeks._value * 7);
213+ }
214+ if(this.ops.hour)
215+ {
216+ result.hour(Math.abs(this.ops.hour._value % 24));
217+ }
218+ if(this.ops.hours)
219+ {
220+ result.add('hours', this.ops.hours._value);
221+ }
222+ if(this.ops.minute)
223+ {
224+ result.minute(Math.abs(this.ops.minute._value % 60));
225+ }
226+ if(this.ops.minutes)
227+ {
228+ result.add('minutes', this.ops.minutes._value);
229+ }
230+ if(this.ops.second)
231+ {
232+ result.second(Math.abs(this.ops.second._value % 60));
233+ }
234+ if(this.ops.seconds)
235+ {
236+ result.add('seconds', this.ops.seconds._value);
237+ }
238+ if(this.ops.weekday)
239+ {
240+ //in relativedelta, 0=MO, but in iso, 1=MO
241+ var isoWeekday = Math.abs(this.ops.weekday._value || 1) /
242+ (this.ops.weekday._value || 1) *
243+ (Math.abs(this.ops.weekday._value) + 1),
244+ originalIsoWeekday = result.isoWeekday();
245+ result.isoWeekday(isoWeekday).add(
246+ 'weeks', isoWeekday < originalIsoWeekday ? 1 : 0);
247+ }
248+
249+ var args = [
250+ result.year(),
251+ //january==0 in moment.js
252+ result.month() + 1,
253+ result.date(),
254+ ];
255+ if(other.__name__ == 'datetime')
256+ {
257+ args.push(result.hour());
258+ args.push(result.minute());
259+ args.push(result.second());
260+ }
261+
262+ return py.PY_call(Object.getPrototypeOf(other), args);
263+ },
264+ __radd__: function(other)
265+ {
266+ return this.__add__(other);
267+ },
268+ __sub__: function(other)
269+ {
270+ _.each(this.ops, function(op, name)
271+ {
272+ if(!op || name == 'weekday')
273+ {
274+ return;
275+ }
276+ op._value = -op._value;
277+ });
278+ return this.__add__(other);
279+ },
280+ __rsub__: function(other)
281+ {
282+ return this.__sub__(other);
283+ },
284+ });
285+ var original_pyeval_context = openerp.web.pyeval.context;
286+ openerp.web.pyeval.context = function ()
287+ {
288+ var ctx = original_pyeval_context();
289+ return _.extend(
290+ ctx,
291+ {
292+ relativedelta: relativedelta,
293+ });
294+ }
295+}
296
297=== added directory 'web_relativedelta/static/test'
298=== added file 'web_relativedelta/static/test/web_relativedelta.js'
299--- web_relativedelta/static/test/web_relativedelta.js 1970-01-01 00:00:00 +0000
300+++ web_relativedelta/static/test/web_relativedelta.js 2014-07-01 06:33:47 +0000
301@@ -0,0 +1,76 @@
302+//-*- coding: utf-8 -*-
303+//############################################################################
304+//
305+// OpenERP, Open Source Management Solution
306+// This module copyright (C) 2014 Therp BV (<http://therp.nl>).
307+//
308+// This program is free software: you can redistribute it and/or modify
309+// it under the terms of the GNU Affero General Public License as
310+// published by the Free Software Foundation, either version 3 of the
311+// License, or (at your option) any later version.
312+//
313+// This program is distributed in the hope that it will be useful,
314+// but WITHOUT ANY WARRANTY; without even the implied warranty of
315+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
316+// GNU Affero General Public License for more details.
317+//
318+// You should have received a copy of the GNU Affero General Public License
319+// along with this program. If not, see <http://www.gnu.org/licenses/>.
320+//
321+//############################################################################
322+
323+openerp.testing.section(
324+ 'python_compatibility',
325+ {dependencies: ['web.coresetup', 'web.pyeval']},
326+ function(test)
327+ {
328+ test('basic deltas', function(instance)
329+ {
330+ openerp.web_relativedelta(instance);
331+ var eval = function(expression)
332+ {
333+ var result_domain = instance.web.pyeval.eval(
334+ 'domain', "[['a', '=', " + expression + "]]", {}, {});
335+ return result_domain[0][2];
336+ }
337+
338+ var result;
339+
340+ result = eval(
341+ "(datetime.date(2012, 12, 25) + relativedelta(days=7)).strftime('%Y-%m-%d')");
342+ ok(result == '2013-01-01', "cross year");
343+
344+ result = eval(
345+ //2012 is a leap year
346+ "(datetime.date(2012, 01, 01) + relativedelta(days=366)).strftime('%Y-%m-%d')");
347+ ok(result == '2013-01-01', "cross leap year");
348+
349+ result = eval(
350+ "(datetime.date(2012, 02, 01) + relativedelta(day=366)).strftime('%Y-%m-%d')");
351+ ok(result == '2012-02-29', "absolute day");
352+
353+ result = eval(
354+ "(datetime.date(2012, 02, 01) + relativedelta(hours=-1)).strftime('%Y-%m-%d')");
355+ ok(result == '2012-01-31', "negative hour");
356+
357+ result = eval(
358+ "(datetime.date(2012, 01, 30) + relativedelta(weekday=0)).strftime('%Y-%m-%d')");
359+ ok(result == '2012-01-30', "weekday=MO (on monday)");
360+
361+ result = eval(
362+ "(datetime.date(2012, 01, 31) + relativedelta(weekday=0)).strftime('%Y-%m-%d')");
363+ ok(result == '2012-02-06', "weekday=MO (on tuesday)");
364+
365+ result = eval(
366+ "(datetime.date(2012, 01, 30) + relativedelta(weeks=-1, days=1, weekday=0)).strftime('%Y-%m-%d')");
367+ ok(result == '2012-01-30', "last monday (on monday)");
368+
369+ result = eval(
370+ "(datetime.date(2012, 01, 31) + relativedelta(weeks=-1, days=1, weekday=0)).strftime('%Y-%m-%d')");
371+ ok(result == '2012-01-30', "last monday (on tuesday)");
372+
373+ result = eval(
374+ "(datetime.date(2012, 02, 01) + relativedelta(weeks=-1, days=1, weekday=0)).strftime('%Y-%m-%d')");
375+ ok(result == '2012-01-30', "last monday (on wednesday)");
376+ });
377+ });

Subscribers

People subscribed via source and target branches