tryton-sao 7.8.9 → 7.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ Version 7.8.11 - 2026-06-02
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.8.10 - 2026-05-20
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.8.9 - 2026-05-02
3
13
  --------------------------
4
14
  * Bug fixes (see mercurial logs for details)
@@ -10098,6 +10098,10 @@ img.icon {
10098
10098
  height: 1.42857143em;
10099
10099
  display: block;
10100
10100
  }
10101
+ [dir="rtl"] .treeview > table.tree img.column-affix,
10102
+ [dir="rtl"] .treeview > table.tree a.column-affix > img {
10103
+ transform: scaleX(-1);
10104
+ }
10101
10105
  .treeview > table.tree tr.more-row {
10102
10106
  text-align: center;
10103
10107
  }
@@ -10217,6 +10221,7 @@ img.icon {
10217
10221
  }
10218
10222
  [dir="rtl"] .treeview .expander > img {
10219
10223
  float: right;
10224
+ transform: scaleX(-1);
10220
10225
  }
10221
10226
  .treeview label {
10222
10227
  font-weight: normal;
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.8.9',
6
+ __version__: '7.8.11',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -1450,11 +1450,6 @@ var Sao = {
1450
1450
  };
1451
1451
 
1452
1452
  var ajax_error = function(query, status_, error) {
1453
- if (!process_exception) {
1454
- console.debug(`RPC error calling ${args}: ${status_}: ${error}.`);
1455
- dfd.reject();
1456
- return;
1457
- }
1458
1453
  if (query.status == 503) {
1459
1454
  this.retries++;
1460
1455
  if (this.retries < 5) {
@@ -1480,8 +1475,7 @@ var Sao = {
1480
1475
  }
1481
1476
  return;
1482
1477
  }
1483
- }
1484
- if (query.status == 401) {
1478
+ } else if (query.status == 401) {
1485
1479
  //Try to relog
1486
1480
  Sao.Session.renew(session).then(function() {
1487
1481
  if (async) {
@@ -1491,6 +1485,10 @@ var Sao = {
1491
1485
  dfd.resolve();
1492
1486
  }
1493
1487
  }, dfd.reject);
1488
+ } else if (!process_exception) {
1489
+ console.debug(`RPC error calling ${args}: ${status_}: ${error}.`);
1490
+ dfd.reject();
1491
+ return;
1494
1492
  } else {
1495
1493
  var err_msg = `[${query.status}] ${error}`;
1496
1494
  Sao.common.message.run(
@@ -4942,7 +4940,9 @@ var Sao = {
4942
4940
  };
4943
4941
 
4944
4942
  var complete_datetime = function() {
4945
- return [Sao.Date(), Sao.DateTime().utc()];
4943
+ return [Sao.Date(), Sao.DateTime(
4944
+ undefined, undefined, undefined,
4945
+ 0, 0, 0, 0, true)];
4946
4946
  };
4947
4947
 
4948
4948
  var complete_date = function() {
@@ -5249,6 +5249,32 @@ var Sao = {
5249
5249
  ]);
5250
5250
  return;
5251
5251
  }
5252
+ if ((typeof value == 'string') &&
5253
+ ['datetime', 'timestamp'].includes(field.type) &&
5254
+ (operator == '=')) {
5255
+ let ctx, format_, parsed_date;
5256
+ if (this.context && Object.keys(this.context).length) {
5257
+ ctx = this.context;
5258
+ } else {
5259
+ ctx = {};
5260
+ }
5261
+ format_ = Sao.common.date_format(ctx.date_format);
5262
+ parsed_date = Sao.common.parse_date(format_, value);
5263
+ if (parsed_date &&
5264
+ (Sao.common.format_date(format_, parsed_date) == value)) {
5265
+ let date = Sao.DateTime.combine(parsed_date, Sao.Time());
5266
+ let next_day = Sao.DateTime(
5267
+ date.year(), date.month(), date.date(),
5268
+ date.hour(), date.minute(), date.second(),
5269
+ date.millisecond())
5270
+ next_day.add(1, 'day');
5271
+ result.push(this._clausify([
5272
+ [field_name, '>=', date],
5273
+ [field_name, '<', next_day]
5274
+ ]));
5275
+ return;
5276
+ }
5277
+ }
5252
5278
  }
5253
5279
  if (['many2one', 'one2many', 'many2many', 'one2one',
5254
5280
  'many2many', 'one2one'].includes(field.type) && value) {
@@ -19123,9 +19149,8 @@ function eval_pyson(value){
19123
19149
  if (record) {
19124
19150
  var fields = this.screen.current_view.get_fields();
19125
19151
  if (!record.validate(fields)) {
19126
- this.screen.display(true);
19127
- prm.reject();
19128
- return;
19152
+ this.screen.display(true).always(() => prm.reject());
19153
+ return prm;
19129
19154
  }
19130
19155
  if (this.screen.pre_validate) {
19131
19156
  return record.pre_validate().then(
@@ -23850,7 +23875,7 @@ function eval_pyson(value){
23850
23875
  fields, false, false)) {
23851
23876
  var value = cell.prop('checked');
23852
23877
  this.field.set_client(record, value);
23853
- if (record !== current_record) {
23878
+ if ((!this.group.parent) & (record !== current_record)) {
23854
23879
  // we can not rely on editable tree handler to save the row
23855
23880
  record.save();
23856
23881
  }
@@ -25401,6 +25426,7 @@ function eval_pyson(value){
25401
25426
  },
25402
25427
  button_clicked: function(event) {
25403
25428
  if (Sao.common.compare(this.screen.selected_records, [this.record])) {
25429
+ event.stopPropagation();
25404
25430
  Sao.View.ListGroupViewForm._super.button_clicked.call(this, event);
25405
25431
  }
25406
25432
  }
@@ -28775,6 +28801,7 @@ function eval_pyson(value){
28775
28801
  if (this.__processing || this.__waiting_response) {
28776
28802
  return jQuery.when();
28777
28803
  }
28804
+ this.__processing = true;
28778
28805
  var process = function() {
28779
28806
  if (this.state == this.end_state) {
28780
28807
  return this.end();
@@ -28833,8 +28860,8 @@ function eval_pyson(value){
28833
28860
  } else {
28834
28861
  prms.push(execute_actions());
28835
28862
  }
28836
- this.__processing = false;
28837
- return jQuery.when.apply(jQuery, prms);
28863
+ return jQuery.when.apply(jQuery, prms).then(
28864
+ () => this.__processing = false);
28838
28865
  }, result => {
28839
28866
  if (!result || !this.screen) {
28840
28867
  this.state = this.end_state;
@@ -28957,11 +28984,14 @@ function eval_pyson(value){
28957
28984
  this.footer.empty();
28958
28985
  },
28959
28986
  _get_button: function(definition) {
28987
+ let state = this.state;
28960
28988
  var button = Sao.Wizard.Form._super._get_button.call(this,
28961
28989
  definition);
28962
28990
  this.footer.append(button.el);
28963
28991
  button.el.click(() => {
28964
- this.response(definition);
28992
+ if (this.state === state) {
28993
+ this.response(definition);
28994
+ }
28965
28995
  });
28966
28996
  return button;
28967
28997
  },
@@ -29009,19 +29039,24 @@ function eval_pyson(value){
29009
29039
  this.footer.empty();
29010
29040
  },
29011
29041
  _get_button: function(definition) {
29042
+ let state = this.state;
29012
29043
  var button = Sao.Wizard.Dialog._super._get_button.call(this,
29013
29044
  definition);
29014
29045
  this.footer.append(button.el);
29015
29046
  if (definition['default']) {
29016
29047
  this.content.unbind('submit');
29017
29048
  this.content.submit(e => {
29018
- this.response(definition);
29019
29049
  e.preventDefault();
29050
+ if (this.state === state) {
29051
+ this.response(definition);
29052
+ }
29020
29053
  });
29021
29054
  button.el.attr('type', 'submit');
29022
29055
  } else {
29023
29056
  button.el.click(() => {
29024
- this.response(definition);
29057
+ if (this.state === state) {
29058
+ this.response(definition);
29059
+ }
29025
29060
  });
29026
29061
  }
29027
29062
  return button;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tryton-sao",
3
3
  "title": "sao",
4
4
  "description": "Tryton webclient",
5
- "version": "7.8.9",
5
+ "version": "7.8.11",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/common.js CHANGED
@@ -1635,7 +1635,9 @@
1635
1635
  };
1636
1636
 
1637
1637
  var complete_datetime = function() {
1638
- return [Sao.Date(), Sao.DateTime().utc()];
1638
+ return [Sao.Date(), Sao.DateTime(
1639
+ undefined, undefined, undefined,
1640
+ 0, 0, 0, 0, true)];
1639
1641
  };
1640
1642
 
1641
1643
  var complete_date = function() {
@@ -1942,6 +1944,32 @@
1942
1944
  ]);
1943
1945
  return;
1944
1946
  }
1947
+ if ((typeof value == 'string') &&
1948
+ ['datetime', 'timestamp'].includes(field.type) &&
1949
+ (operator == '=')) {
1950
+ let ctx, format_, parsed_date;
1951
+ if (this.context && Object.keys(this.context).length) {
1952
+ ctx = this.context;
1953
+ } else {
1954
+ ctx = {};
1955
+ }
1956
+ format_ = Sao.common.date_format(ctx.date_format);
1957
+ parsed_date = Sao.common.parse_date(format_, value);
1958
+ if (parsed_date &&
1959
+ (Sao.common.format_date(format_, parsed_date) == value)) {
1960
+ let date = Sao.DateTime.combine(parsed_date, Sao.Time());
1961
+ let next_day = Sao.DateTime(
1962
+ date.year(), date.month(), date.date(),
1963
+ date.hour(), date.minute(), date.second(),
1964
+ date.millisecond())
1965
+ next_day.add(1, 'day');
1966
+ result.push(this._clausify([
1967
+ [field_name, '>=', date],
1968
+ [field_name, '<', next_day]
1969
+ ]));
1970
+ return;
1971
+ }
1972
+ }
1945
1973
  }
1946
1974
  if (['many2one', 'one2many', 'many2many', 'one2one',
1947
1975
  'many2many', 'one2one'].includes(field.type) && value) {
package/src/rpc.js CHANGED
@@ -119,11 +119,6 @@
119
119
  };
120
120
 
121
121
  var ajax_error = function(query, status_, error) {
122
- if (!process_exception) {
123
- console.debug(`RPC error calling ${args}: ${status_}: ${error}.`);
124
- dfd.reject();
125
- return;
126
- }
127
122
  if (query.status == 503) {
128
123
  this.retries++;
129
124
  if (this.retries < 5) {
@@ -149,8 +144,7 @@
149
144
  }
150
145
  return;
151
146
  }
152
- }
153
- if (query.status == 401) {
147
+ } else if (query.status == 401) {
154
148
  //Try to relog
155
149
  Sao.Session.renew(session).then(function() {
156
150
  if (async) {
@@ -160,6 +154,10 @@
160
154
  dfd.resolve();
161
155
  }
162
156
  }, dfd.reject);
157
+ } else if (!process_exception) {
158
+ console.debug(`RPC error calling ${args}: ${status_}: ${error}.`);
159
+ dfd.reject();
160
+ return;
163
161
  } else {
164
162
  var err_msg = `[${query.status}] ${error}`;
165
163
  Sao.common.message.run(
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.8.9',
6
+ __version__: '7.8.11',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/sao.less CHANGED
@@ -982,6 +982,10 @@ img.icon {
982
982
  width: unit(@line-height-base, em);
983
983
  height: unit(@line-height-base, em);
984
984
  display: block;
985
+
986
+ [dir="rtl"] & {
987
+ transform: scaleX(-1);
988
+ }
985
989
  }
986
990
 
987
991
  tr.more-row {
@@ -1075,6 +1079,7 @@ img.icon {
1075
1079
  float: left;
1076
1080
  [dir="rtl"] & {
1077
1081
  float: right;
1082
+ transform: scaleX(-1);
1078
1083
  }
1079
1084
  width: unit(@line-height-base, em);
1080
1085
  height: unit(@line-height-base, em);
package/src/view/form.js CHANGED
@@ -3962,9 +3962,8 @@ function eval_pyson(value){
3962
3962
  if (record) {
3963
3963
  var fields = this.screen.current_view.get_fields();
3964
3964
  if (!record.validate(fields)) {
3965
- this.screen.display(true);
3966
- prm.reject();
3967
- return;
3965
+ this.screen.display(true).always(() => prm.reject());
3966
+ return prm;
3968
3967
  }
3969
3968
  if (this.screen.pre_validate) {
3970
3969
  return record.pre_validate().then(
@@ -12,6 +12,7 @@
12
12
  },
13
13
  button_clicked: function(event) {
14
14
  if (Sao.common.compare(this.screen.selected_records, [this.record])) {
15
+ event.stopPropagation();
15
16
  Sao.View.ListGroupViewForm._super.button_clicked.call(this, event);
16
17
  }
17
18
  }
package/src/view/tree.js CHANGED
@@ -2762,7 +2762,7 @@
2762
2762
  fields, false, false)) {
2763
2763
  var value = cell.prop('checked');
2764
2764
  this.field.set_client(record, value);
2765
- if (record !== current_record) {
2765
+ if ((!this.group.parent) & (record !== current_record)) {
2766
2766
  // we can not rely on editable tree handler to save the row
2767
2767
  record.save();
2768
2768
  }
package/src/wizard.js CHANGED
@@ -55,6 +55,7 @@
55
55
  if (this.__processing || this.__waiting_response) {
56
56
  return jQuery.when();
57
57
  }
58
+ this.__processing = true;
58
59
  var process = function() {
59
60
  if (this.state == this.end_state) {
60
61
  return this.end();
@@ -113,8 +114,8 @@
113
114
  } else {
114
115
  prms.push(execute_actions());
115
116
  }
116
- this.__processing = false;
117
- return jQuery.when.apply(jQuery, prms);
117
+ return jQuery.when.apply(jQuery, prms).then(
118
+ () => this.__processing = false);
118
119
  }, result => {
119
120
  if (!result || !this.screen) {
120
121
  this.state = this.end_state;
@@ -237,11 +238,14 @@
237
238
  this.footer.empty();
238
239
  },
239
240
  _get_button: function(definition) {
241
+ let state = this.state;
240
242
  var button = Sao.Wizard.Form._super._get_button.call(this,
241
243
  definition);
242
244
  this.footer.append(button.el);
243
245
  button.el.click(() => {
244
- this.response(definition);
246
+ if (this.state === state) {
247
+ this.response(definition);
248
+ }
245
249
  });
246
250
  return button;
247
251
  },
@@ -289,19 +293,24 @@
289
293
  this.footer.empty();
290
294
  },
291
295
  _get_button: function(definition) {
296
+ let state = this.state;
292
297
  var button = Sao.Wizard.Dialog._super._get_button.call(this,
293
298
  definition);
294
299
  this.footer.append(button.el);
295
300
  if (definition['default']) {
296
301
  this.content.unbind('submit');
297
302
  this.content.submit(e => {
298
- this.response(definition);
299
303
  e.preventDefault();
304
+ if (this.state === state) {
305
+ this.response(definition);
306
+ }
300
307
  });
301
308
  button.el.attr('type', 'submit');
302
309
  } else {
303
310
  button.el.click(() => {
304
- this.response(definition);
311
+ if (this.state === state) {
312
+ this.response(definition);
313
+ }
305
314
  });
306
315
  }
307
316
  return button;
package/tests/sao.js CHANGED
@@ -1933,6 +1933,12 @@
1933
1933
  'name': 'integer',
1934
1934
  'type': 'integer'
1935
1935
  },
1936
+ 'timestamp': {
1937
+ 'name': 'timestamp',
1938
+ 'string': 'Timestamp',
1939
+ 'type': 'timestamp',
1940
+ 'format': '"%H:%M:%S"',
1941
+ },
1936
1942
  'selection': {
1937
1943
  'string': 'Selection',
1938
1944
  'name': 'selection',
@@ -2033,6 +2039,7 @@
2033
2039
  c(['integer', '>=', 3]),
2034
2040
  c(['integer', '<=', 5])
2035
2041
  ]]],
2042
+ [[c(['Timestamp', null, null])], [c(['timestamp', '=', null])]],
2036
2043
  [[c(['Reference', null, 'foo'])],
2037
2044
  [c(['reference', 'ilike', '%foo%'])]],
2038
2045
  [[c(['Reference', null, 'Spam'])],
@@ -2073,6 +2080,33 @@
2073
2080
  QUnit.assert.deepEqual(parser.parse_clause(value), result,
2074
2081
  'parse_clause(' + JSON.stringify(value) + ')');
2075
2082
  });
2083
+
2084
+ let clause = parser.parse_clause([c(
2085
+ ['Timestamp', '=', Sao.common.format_date('%x', Sao.Date(2002, 12, 4))])]);
2086
+ QUnit.assert.strictEqual(clause[0].length, 2);
2087
+ let [ , operator, value] = clause[0][0];
2088
+ QUnit.assert.strictEqual(operator, '>=');
2089
+ QUnit.assert.ok(value.isSame(Sao.Date(2002, 12, 4)));
2090
+ [ , operator, value] = clause[0][1];
2091
+ QUnit.assert.strictEqual(operator, '<');
2092
+ QUnit.assert.ok(value.isSame(Sao.Date(2002, 12, 5)));
2093
+
2094
+ clause = parser.parse_clause([c(
2095
+ ['Timestamp', '=',
2096
+ Sao.common.format_datetime('%x %X', Sao.DateTime(2002, 12, 4, 12, 30))])]);
2097
+ [ , operator, value] = clause[0];
2098
+ QUnit.assert.strictEqual(operator, '=');
2099
+ QUnit.assert.ok(value.isSame(Sao.DateTime(2002, 12, 4, 12, 30)));
2100
+
2101
+ clause = parser.parse_clause([c(
2102
+ ['Timestamp', null, [
2103
+ `${Sao.common.format_date('%x', Sao.Date(2002, 12, 4))}`,
2104
+ `${Sao.common.format_date('%x', Sao.Date(2002, 12, 5))}`,
2105
+ ]])]);
2106
+ [ , operator, value] = clause[0];
2107
+ QUnit.assert.strictEqual(operator, 'in');
2108
+ QUnit.assert.ok(value[0].isSame(Sao.DateTime(2002, 12, 4)));
2109
+ QUnit.assert.ok(value[1].isSame(Sao.DateTime(2002, 12, 5)));
2076
2110
  });
2077
2111
 
2078
2112
  QUnit.test('DomainParser.format_value', function() {