tryton-sao 7.2.9 → 7.2.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.2.11 - 2024-12-01
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.2.10 - 2024-11-06
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.2.9 - 2024-10-18
3
13
  --------------------------
4
14
  * Bug fixes (see mercurial logs for details)
@@ -9557,6 +9557,7 @@ html.accesskey select[accesskey] ~ span[data-accesskey] {
9557
9557
  .tab-board .tab-domain > .nav-tabs {
9558
9558
  display: inline-flex;
9559
9559
  white-space: nowrap;
9560
+ width: 1px;
9560
9561
  }
9561
9562
  .tab-form .tab-domain .badge,
9562
9563
  .tab-board .tab-domain .badge {
@@ -9644,7 +9645,8 @@ img.icon {
9644
9645
  [dir="rtl"] img.icon {
9645
9646
  transform: scaleX(-1);
9646
9647
  }
9647
- .screen-container {
9648
+ .screen-container,
9649
+ .board {
9648
9650
  display: flex;
9649
9651
  flex-direction: column;
9650
9652
  flex: 1;
@@ -9918,251 +9920,361 @@ img.icon {
9918
9920
  padding-top: 0;
9919
9921
  padding-bottom: 0;
9920
9922
  }
9921
- .form {
9923
+ .form,
9924
+ .board {
9922
9925
  width: 100%;
9923
9926
  height: 100%;
9924
9927
  }
9925
9928
  .form .form-container,
9929
+ .board .form-container,
9926
9930
  .form .form-hcontainer,
9927
- .form .form-vcontainer {
9931
+ .board .form-hcontainer,
9932
+ .form .form-vcontainer,
9933
+ .board .form-vcontainer {
9928
9934
  display: grid;
9929
9935
  width: 100%;
9930
9936
  height: 100%;
9931
9937
  }
9932
- .form .form-item {
9938
+ .form .form-item,
9939
+ .board .form-item {
9933
9940
  display: flex;
9934
9941
  padding: 2px;
9935
9942
  }
9936
- .form .form-item.form-empty {
9943
+ .form .form-item.form-empty,
9944
+ .board .form-item.form-empty {
9937
9945
  padding: 0px;
9938
9946
  }
9939
- .form .form-label {
9947
+ .form .form-label,
9948
+ .board .form-label {
9940
9949
  white-space: pre-wrap;
9941
9950
  width: max-content;
9942
9951
  max-width: 80ch;
9943
9952
  }
9944
9953
  .form .form-char input,
9954
+ .board .form-char input,
9945
9955
  .form .form-password input,
9956
+ .board .form-password input,
9946
9957
  .form .form-integer input,
9958
+ .board .form-integer input,
9947
9959
  .form .form-float input,
9960
+ .board .form-float input,
9948
9961
  .form .form-timedelta input,
9962
+ .board .form-timedelta input,
9949
9963
  .form .form-selection input,
9964
+ .board .form-selection input,
9950
9965
  .form .form-multiselection input,
9966
+ .board .form-multiselection input,
9951
9967
  .form .form-url input,
9968
+ .board .form-url input,
9952
9969
  .form .form-email input,
9970
+ .board .form-email input,
9953
9971
  .form .form-callto input,
9972
+ .board .form-callto input,
9954
9973
  .form .form-sip input,
9974
+ .board .form-sip input,
9955
9975
  .form .form-pyson input,
9976
+ .board .form-pyson input,
9956
9977
  .form .form-char select,
9978
+ .board .form-char select,
9957
9979
  .form .form-password select,
9980
+ .board .form-password select,
9958
9981
  .form .form-integer select,
9982
+ .board .form-integer select,
9959
9983
  .form .form-float select,
9984
+ .board .form-float select,
9960
9985
  .form .form-timedelta select,
9986
+ .board .form-timedelta select,
9961
9987
  .form .form-selection select,
9988
+ .board .form-selection select,
9962
9989
  .form .form-multiselection select,
9990
+ .board .form-multiselection select,
9963
9991
  .form .form-url select,
9992
+ .board .form-url select,
9964
9993
  .form .form-email select,
9994
+ .board .form-email select,
9965
9995
  .form .form-callto select,
9996
+ .board .form-callto select,
9966
9997
  .form .form-sip select,
9967
- .form .form-pyson select {
9998
+ .board .form-sip select,
9999
+ .form .form-pyson select,
10000
+ .board .form-pyson select {
9968
10001
  min-width: 8ch;
9969
10002
  }
9970
- .form .form-date input {
10003
+ .form .form-date input,
10004
+ .board .form-date input {
9971
10005
  width: calc(10ch + 34px);
9972
10006
  }
9973
- .form .form-time input {
10007
+ .form .form-time input,
10008
+ .board .form-time input {
9974
10009
  width: calc(8ch + 34px);
9975
10010
  }
9976
- .form .form-datetime input {
10011
+ .form .form-datetime input,
10012
+ .board .form-datetime input {
9977
10013
  width: calc(19ch + 34px);
9978
10014
  }
9979
10015
  .form .form-many2one select,
10016
+ .board .form-many2one select,
9980
10017
  .form .form-one2one select,
10018
+ .board .form-one2one select,
9981
10019
  .form .form-reference select,
9982
- .form form-binary select {
10020
+ .board .form-reference select,
10021
+ .form form-binary select,
10022
+ .board form-binary select {
9983
10023
  min-width: 8ch;
9984
10024
  }
9985
10025
  .form .form-many2one input,
10026
+ .board .form-many2one input,
9986
10027
  .form .form-one2one input,
10028
+ .board .form-one2one input,
9987
10029
  .form .form-reference input,
9988
- .form form-binary input {
10030
+ .board .form-reference input,
10031
+ .form form-binary input,
10032
+ .board form-binary input {
9989
10033
  min-width: 12ch;
9990
10034
  }
9991
10035
  @media screen and (min-width: 768px) {
9992
10036
  .form .form-reference > .input-sm,
9993
- .form .form-reference > .input-group {
10037
+ .board .form-reference > .input-sm,
10038
+ .form .form-reference > .input-group,
10039
+ .board .form-reference > .input-group {
9994
10040
  width: 50%;
9995
10041
  }
9996
10042
  }
9997
10043
  @media screen and (max-width: 767px) {
9998
10044
  .form .form-reference > .input-sm,
9999
- .form .form-reference > .input-group {
10045
+ .board .form-reference > .input-sm,
10046
+ .form .form-reference > .input-group,
10047
+ .board .form-reference > .input-group {
10000
10048
  width: 100%;
10001
10049
  }
10002
10050
  }
10003
10051
  .form .form-url a > img,
10052
+ .board .form-url a > img,
10004
10053
  .form .form-email a > img,
10054
+ .board .form-email a > img,
10005
10055
  .form .form-callto a > img,
10006
- .form .form-sip a > img {
10056
+ .board .form-callto a > img,
10057
+ .form .form-sip a > img,
10058
+ .board .form-sip a > img {
10007
10059
  width: 1em;
10008
10060
  height: 1em;
10009
10061
  }
10010
- .form .form-many2one > .input-group {
10062
+ .form .form-many2one > .input-group,
10063
+ .board .form-many2one > .input-group {
10011
10064
  width: 100%;
10012
10065
  }
10013
10066
  .form .form-one2many-menu::after,
10014
- .form .form-many2many-menu::after {
10067
+ .board .form-one2many-menu::after,
10068
+ .form .form-many2many-menu::after,
10069
+ .board .form-many2many-menu::after {
10015
10070
  content: "";
10016
10071
  display: table;
10017
10072
  clear: both;
10018
10073
  }
10019
10074
  .form .form-one2many-menu .form-one2many-string,
10075
+ .board .form-one2many-menu .form-one2many-string,
10020
10076
  .form .form-many2many-menu .form-one2many-string,
10077
+ .board .form-many2many-menu .form-one2many-string,
10021
10078
  .form .form-one2many-menu .form-many2many-string,
10022
- .form .form-many2many-menu .form-many2many-string {
10079
+ .board .form-one2many-menu .form-many2many-string,
10080
+ .form .form-many2many-menu .form-many2many-string,
10081
+ .board .form-many2many-menu .form-many2many-string {
10023
10082
  display: inline-table;
10024
10083
  float: left;
10025
10084
  margin: 5px;
10026
10085
  }
10027
10086
  [dir="rtl"] .form .form-one2many-menu .form-one2many-string,
10087
+ [dir="rtl"] .board .form-one2many-menu .form-one2many-string,
10028
10088
  [dir="rtl"] .form .form-many2many-menu .form-one2many-string,
10089
+ [dir="rtl"] .board .form-many2many-menu .form-one2many-string,
10029
10090
  [dir="rtl"] .form .form-one2many-menu .form-many2many-string,
10030
- [dir="rtl"] .form .form-many2many-menu .form-many2many-string {
10091
+ [dir="rtl"] .board .form-one2many-menu .form-many2many-string,
10092
+ [dir="rtl"] .form .form-many2many-menu .form-many2many-string,
10093
+ [dir="rtl"] .board .form-many2many-menu .form-many2many-string {
10031
10094
  float: right;
10032
10095
  }
10033
10096
  .form .form-one2many-menu .form-one2many-toolbar,
10097
+ .board .form-one2many-menu .form-one2many-toolbar,
10034
10098
  .form .form-many2many-menu .form-one2many-toolbar,
10099
+ .board .form-many2many-menu .form-one2many-toolbar,
10035
10100
  .form .form-one2many-menu .form-many2many-toolbar,
10036
- .form .form-many2many-menu .form-many2many-toolbar {
10101
+ .board .form-one2many-menu .form-many2many-toolbar,
10102
+ .form .form-many2many-menu .form-many2many-toolbar,
10103
+ .board .form-many2many-menu .form-many2many-toolbar {
10037
10104
  display: inline-table;
10038
10105
  float: right;
10039
10106
  }
10040
10107
  [dir="rtl"] .form .form-one2many-menu .form-one2many-toolbar,
10108
+ [dir="rtl"] .board .form-one2many-menu .form-one2many-toolbar,
10041
10109
  [dir="rtl"] .form .form-many2many-menu .form-one2many-toolbar,
10110
+ [dir="rtl"] .board .form-many2many-menu .form-one2many-toolbar,
10042
10111
  [dir="rtl"] .form .form-one2many-menu .form-many2many-toolbar,
10043
- [dir="rtl"] .form .form-many2many-menu .form-many2many-toolbar {
10112
+ [dir="rtl"] .board .form-one2many-menu .form-many2many-toolbar,
10113
+ [dir="rtl"] .form .form-many2many-menu .form-many2many-toolbar,
10114
+ [dir="rtl"] .board .form-many2many-menu .form-many2many-toolbar {
10044
10115
  float: left;
10045
10116
  }
10046
10117
  .form .form-one2many-menu .form-one2many-toolbar .badge,
10118
+ .board .form-one2many-menu .form-one2many-toolbar .badge,
10047
10119
  .form .form-many2many-menu .form-one2many-toolbar .badge,
10120
+ .board .form-many2many-menu .form-one2many-toolbar .badge,
10048
10121
  .form .form-one2many-menu .form-many2many-toolbar .badge,
10049
- .form .form-many2many-menu .form-many2many-toolbar .badge {
10122
+ .board .form-one2many-menu .form-many2many-toolbar .badge,
10123
+ .form .form-many2many-menu .form-many2many-toolbar .badge,
10124
+ .board .form-many2many-menu .form-many2many-toolbar .badge {
10050
10125
  max-width: 5em;
10051
10126
  min-width: 5em;
10052
10127
  overflow: hidden;
10053
10128
  text-overflow: ellipsis;
10054
10129
  }
10055
10130
  .form .form-one2many-content .treeview,
10131
+ .board .form-one2many-content .treeview,
10056
10132
  .form .form-many2many-content .treeview,
10133
+ .board .form-many2many-content .treeview,
10057
10134
  .form .form-one2many-content .list-form,
10058
- .form .form-many2many-content .list-form {
10135
+ .board .form-one2many-content .list-form,
10136
+ .form .form-many2many-content .list-form,
10137
+ .board .form-many2many-content .list-form {
10059
10138
  height: auto;
10060
10139
  min-height: 150px;
10061
10140
  max-height: 300px;
10062
10141
  }
10063
10142
  .form .form-text .input-group,
10064
- .form .form-richtext .input-group {
10143
+ .board .form-text .input-group,
10144
+ .form .form-richtext .input-group,
10145
+ .board .form-richtext .input-group {
10065
10146
  width: 100%;
10066
10147
  }
10067
10148
  .form .form-text .input-group textarea,
10149
+ .board .form-text .input-group textarea,
10068
10150
  .form .form-richtext .input-group textarea,
10151
+ .board .form-richtext .input-group textarea,
10069
10152
  .form .form-text .input-group .richtext,
10070
- .form .form-richtext .input-group .richtext {
10153
+ .board .form-text .input-group .richtext,
10154
+ .form .form-richtext .input-group .richtext,
10155
+ .board .form-richtext .input-group .richtext {
10071
10156
  height: 100%;
10072
10157
  line-height: 2.5ex;
10073
10158
  min-height: 12.5ex;
10074
10159
  overflow: auto;
10075
10160
  resize: vertical;
10076
10161
  }
10077
- .form .form-richtext > .btn-toolbar {
10162
+ .form .form-richtext > .btn-toolbar,
10163
+ .board .form-richtext > .btn-toolbar {
10078
10164
  min-width: 450px;
10079
10165
  }
10080
- .form .form-separator label {
10166
+ .form .form-separator label,
10167
+ .board .form-separator label {
10081
10168
  margin-top: 10px;
10082
10169
  }
10083
- .form .form-separator hr {
10170
+ .form .form-separator hr,
10171
+ .board .form-separator hr {
10084
10172
  margin-top: 0;
10085
10173
  margin-bottom: 5px;
10086
10174
  }
10087
- .form .form-image .caption {
10175
+ .form .form-image .caption,
10176
+ .board .form-image .caption {
10088
10177
  min-width: 120px;
10089
10178
  }
10090
- .form .form-document object {
10179
+ .form .form-document object,
10180
+ .board .form-document object {
10091
10181
  object-fit: scale-down;
10092
10182
  object-position: center top;
10093
10183
  width: 100%;
10094
10184
  height: 75vh;
10095
10185
  }
10096
10186
  @media screen and (max-width: 991px) {
10097
- .form .form-document object {
10187
+ .form .form-document object,
10188
+ .board .form-document object {
10098
10189
  height: 50vh;
10099
10190
  }
10100
10191
  }
10101
10192
  @media screen and (max-width: 767px) {
10102
- .form .form-document object {
10193
+ .form .form-document object,
10194
+ .board .form-document object {
10103
10195
  height: 25vh;
10104
10196
  }
10105
10197
  }
10106
- .form label {
10198
+ .form label,
10199
+ .board label {
10107
10200
  font-weight: normal;
10108
10201
  display: inline;
10109
10202
  padding: 0 5px;
10110
10203
  }
10111
- .form label.required {
10204
+ .form label.required,
10205
+ .board label.required {
10112
10206
  font-weight: bold;
10113
10207
  }
10114
- .form label.editable {
10208
+ .form label.editable,
10209
+ .board label.editable {
10115
10210
  font-style: italic;
10116
10211
  }
10117
- .form .nav-tabs {
10212
+ .form .nav-tabs,
10213
+ .board .nav-tabs {
10118
10214
  margin-bottom: 15px;
10119
10215
  }
10120
- .form .panel-heading {
10216
+ .form .panel-heading,
10217
+ .board .panel-heading {
10121
10218
  padding: 2px 2px;
10122
10219
  }
10123
- .form fieldset.form-group_ {
10220
+ .form fieldset.form-group_,
10221
+ .board fieldset.form-group_ {
10124
10222
  overflow: auto;
10125
10223
  }
10126
- .form fieldset.form-group_ > legend {
10224
+ .form fieldset.form-group_ > legend,
10225
+ .board fieldset.form-group_ > legend {
10127
10226
  font-size: 14px;
10128
10227
  margin-bottom: 5px;
10129
10228
  }
10130
10229
  .form fieldset.form-group_ .form-container,
10230
+ .board fieldset.form-group_ .form-container,
10131
10231
  .form fieldset.form-group_ .form-hcontainer,
10132
- .form fieldset.form-group_ .form-vcontainer {
10232
+ .board fieldset.form-group_ .form-hcontainer,
10233
+ .form fieldset.form-group_ .form-vcontainer,
10234
+ .board fieldset.form-group_ .form-vcontainer {
10133
10235
  vertical-align: middle;
10134
10236
  }
10135
- .form .xexpand {
10237
+ .form .xexpand,
10238
+ .board .xexpand {
10136
10239
  width: 100%;
10137
10240
  }
10138
- .form .xfill {
10241
+ .form .xfill,
10242
+ .board .xfill {
10139
10243
  justify-content: stretch;
10140
10244
  }
10141
- .form .yexpand {
10245
+ .form .yexpand,
10246
+ .board .yexpand {
10142
10247
  height: 100%;
10143
10248
  }
10144
- .form .xalign-start {
10249
+ .form .xalign-start,
10250
+ .board .xalign-start {
10145
10251
  justify-self: start;
10146
10252
  justify-content: start;
10147
10253
  }
10148
- .form .xalign-center {
10254
+ .form .xalign-center,
10255
+ .board .xalign-center {
10149
10256
  justify-self: center;
10150
10257
  justify-content: center;
10151
10258
  }
10152
- .form .xalign-end {
10259
+ .form .xalign-end,
10260
+ .board .xalign-end {
10153
10261
  justify-self: end;
10154
10262
  justify-content: end;
10155
10263
  }
10156
- .form .yalign-start {
10264
+ .form .yalign-start,
10265
+ .board .yalign-start {
10157
10266
  align-items: start;
10158
10267
  }
10159
- .form .yalign-center {
10268
+ .form .yalign-center,
10269
+ .board .yalign-center {
10160
10270
  align-items: center;
10161
10271
  }
10162
- .form .yalign-end {
10272
+ .form .yalign-end,
10273
+ .board .yalign-end {
10163
10274
  align-items: end;
10164
10275
  }
10165
- .form .yfill {
10276
+ .form .yfill,
10277
+ .board .yfill {
10166
10278
  align-self: stretch;
10167
10279
  }
10168
10280
  .form-binary,
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.2.9',
6
+ __version__: '7.2.11',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -2083,7 +2083,8 @@ var Sao = {
2083
2083
  if ( (!(statement instanceof Sao.PYSON.DateTime ||
2084
2084
  statement instanceof Sao.PYSON.Date ||
2085
2085
  statement instanceof Sao.PYSON.TimeDelta)) &&
2086
- (jQuery(statement.types()).not(['number']).length) ) {
2086
+ (jQuery(statement.types()).not(
2087
+ ['number', 'object']).length) ) {
2087
2088
  throw 'statement must be an integer, float, ' +
2088
2089
  'date, datetime or timedelta';
2089
2090
  }
@@ -4588,10 +4589,18 @@ var Sao = {
4588
4589
  .replace('not', '!').trim();
4589
4590
  }
4590
4591
  if (operator.endsWith('in')) {
4591
- if (operator == 'not in') {
4592
- operator = '!';
4592
+ if (value instanceof Array && value.length == 1) {
4593
+ if (operator == 'not in') {
4594
+ operator = '!=';
4595
+ } else {
4596
+ operator = '=';
4597
+ }
4593
4598
  } else {
4594
- operator = '';
4599
+ if (operator == 'not in') {
4600
+ operator = '!';
4601
+ } else {
4602
+ operator = '';
4603
+ }
4595
4604
  }
4596
4605
  }
4597
4606
  var formatted_value = this.format_value(field, value, target);
@@ -5229,10 +5238,13 @@ var Sao = {
5229
5238
  .replace(escape + '%', '%')
5230
5239
  .replace(escape + '_', '_');
5231
5240
  },
5232
- quote: function(value) {
5241
+ quote: function(value, empty=false) {
5233
5242
  if (typeof value != 'string') {
5234
5243
  return value;
5235
5244
  }
5245
+ if (empty && value === '') {
5246
+ return '""';
5247
+ }
5236
5248
  if (value.contains('\\')) {
5237
5249
  value = value.replace(new RegExp('\\\\', 'g'), '\\\\');
5238
5250
  }
@@ -5391,7 +5403,8 @@ var Sao = {
5391
5403
  return value;
5392
5404
  }
5393
5405
  },
5394
- format_value: function(field, value, target=null, context={}) {
5406
+ format_value: function(
5407
+ field, value, target=null, context={}, _quote_empty=false) {
5395
5408
  var format_float = function() {
5396
5409
  if (!value && value !== 0 && value !== new Sao.Decimal(0)) {
5397
5410
  return '';
@@ -5502,7 +5515,9 @@ var Sao = {
5502
5515
  };
5503
5516
  converts.timestamp = converts.datetime;
5504
5517
  if (value instanceof Array) {
5505
- return value.map(v => this.format_value(field, v)).join(';');
5518
+ return value.map(
5519
+ v => this.format_value(field, v, null, context, true))
5520
+ .join(';');
5506
5521
  } else {
5507
5522
  var func = converts[field.type];
5508
5523
  if (func) {
@@ -5510,7 +5525,7 @@ var Sao = {
5510
5525
  } else if (value === null) {
5511
5526
  return '';
5512
5527
  } else {
5513
- return this.quote(value);
5528
+ return this.quote(value, _quote_empty);
5514
5529
  }
5515
5530
  }
5516
5531
  },
@@ -6061,7 +6076,9 @@ var Sao = {
6061
6076
  (single_value && operator == 'in' && value.length == 1)) &&
6062
6077
  (!count ||
6063
6078
  ((count === 1) && model.length && name.endsWith('.id')))) {
6064
- value = operator == '=' ? value : value[0];
6079
+ if ((operator == 'in') && single_value) {
6080
+ value = value[0];
6081
+ }
6065
6082
  if (model.length && name.endsWith('.id')) {
6066
6083
  model = model[0];
6067
6084
  value = [model, value];
@@ -8151,6 +8168,7 @@ var Sao = {
8151
8168
  for (const record of this) {
8152
8169
  if (record.get_loaded([field]) || changed || record.id < 0) {
8153
8170
  if (prev) {
8171
+ prev.load(field, false);
8154
8172
  index = prev.field_get(field);
8155
8173
  } else {
8156
8174
  index = null;
@@ -9441,7 +9459,7 @@ var Sao = {
9441
9459
  setdefault = false;
9442
9460
  }
9443
9461
  }
9444
- if (setdefault && !pre_validate) {
9462
+ if (setdefault && jQuery.isEmptyObject(pre_validate)) {
9445
9463
  this.set_client(record, value);
9446
9464
  state_attrs.domain_readonly = domain_readonly;
9447
9465
  }
@@ -10295,7 +10313,7 @@ var Sao = {
10295
10313
  }
10296
10314
  for (const record2 of (record._values[this.name] || [])) {
10297
10315
  if (!record2.get_loaded() && (record2.id >= 0) &&
10298
- !pre_validate) {
10316
+ jQuery.isEmptyObject(pre_validate)) {
10299
10317
  continue;
10300
10318
  }
10301
10319
  if (!record2.validate(null, softvalidation, ldomain, true)) {
@@ -12284,6 +12302,8 @@ var Sao = {
12284
12302
  }
12285
12303
  this.dialogs = [];
12286
12304
  this.board = null;
12305
+ this.create_tabcontent();
12306
+ this.set_name(name);
12287
12307
  UIView = new Sao.Model('ir.ui.view');
12288
12308
  this.view_prm = UIView.execute(
12289
12309
  'view_get', [this.view_id], this.context);
@@ -12300,8 +12320,6 @@ var Sao = {
12300
12320
  });
12301
12321
  this.content.append(this.board.el);
12302
12322
  });
12303
- this.create_tabcontent();
12304
- this.set_name(name);
12305
12323
  },
12306
12324
  compare: function(attributes) {
12307
12325
  if (!attributes) {
@@ -13194,10 +13212,7 @@ var Sao = {
13194
13212
  'class': 'col-md-12'
13195
13213
  }).append(this.context_screen.screen_container.el))
13196
13214
  .prependTo(this.screen_container.filter_box);
13197
- return this.context_screen.new_(false).then(
13198
- // Set manually default to get context_screen_prm
13199
- // resolved when default is set.
13200
- record => record.default_get());
13215
+ return this.context_screen.new_();
13201
13216
  });
13202
13217
  }
13203
13218
 
@@ -14849,6 +14864,10 @@ function eval_pyson(value){
14849
14864
  (function() {
14850
14865
  'use strict';
14851
14866
 
14867
+ function remove_newline(value) {
14868
+ return value.replace(/[\n\r]/gm, '')
14869
+ }
14870
+
14852
14871
  Sao.View.FormXMLViewParser = Sao.class_(Sao.View.XMLViewParser, {
14853
14872
  init: function(view, exclude_field, field_attrs) {
14854
14873
  Sao.View.FormXMLViewParser._super.init.call(
@@ -17447,7 +17466,7 @@ function eval_pyson(value){
17447
17466
  get_text: function() {
17448
17467
  var record = this.record;
17449
17468
  if (record) {
17450
- return record.field_get_client(this.field_name);
17469
+ return remove_newline(record.field_get_client(this.field_name));
17451
17470
  }
17452
17471
  return '';
17453
17472
  },
@@ -17463,7 +17482,7 @@ function eval_pyson(value){
17463
17482
  set_value: function() {
17464
17483
  var record = this.record;
17465
17484
  var field = this.field;
17466
- if (field.get_client(record) != this.entry.val()) {
17485
+ if (this.get_text() != this.entry.val()) {
17467
17486
  field.set_client(record, this.value_from_id(null, ''));
17468
17487
  this.entry.val('');
17469
17488
  }
@@ -17558,7 +17577,7 @@ function eval_pyson(value){
17558
17577
  get modified() {
17559
17578
  if (this.record && this.field) {
17560
17579
  var value = this.entry.val();
17561
- return this.field.get_client(this.record) != value;
17580
+ return this.get_text() != value;
17562
17581
  }
17563
17582
  return false;
17564
17583
  },
@@ -17886,7 +17905,7 @@ function eval_pyson(value){
17886
17905
  name = '';
17887
17906
  if (value) {
17888
17907
  model = value[0];
17889
- name = value[1];
17908
+ name = remove_newline(value[1]);
17890
17909
  }
17891
17910
  return ((model != this.get_model()) ||
17892
17911
  (name != this.entry.val()));
@@ -17905,7 +17924,8 @@ function eval_pyson(value){
17905
17924
  get_text: function() {
17906
17925
  var record = this.record;
17907
17926
  if (record) {
17908
- return record.field_get_client(this.field_name)[1];
17927
+ return remove_newline(
17928
+ record.field_get_client(this.field_name)[1]);
17909
17929
  }
17910
17930
  return '';
17911
17931
  },
@@ -17959,7 +17979,7 @@ function eval_pyson(value){
17959
17979
  var model, name;
17960
17980
  if (value instanceof Array) {
17961
17981
  model = value[0];
17962
- name = value[1];
17982
+ name = remove_newline(value[1]);
17963
17983
  } else {
17964
17984
  model = '';
17965
17985
  name = '';
@@ -20152,7 +20172,7 @@ function eval_pyson(value){
20152
20172
  this.input.prop('disabled', readonly);
20153
20173
  },
20154
20174
  set_value: function(value) {
20155
- this.input.prop('checked', value);
20175
+ this.input.prop('checked', Boolean(value));
20156
20176
  }
20157
20177
  });
20158
20178
 
@@ -20255,7 +20275,8 @@ function eval_pyson(value){
20255
20275
  return value;
20256
20276
  },
20257
20277
  set_value: function(value, options) {
20258
- if (value !== null) {
20278
+ if ((typeof(value) == 'number') ||
20279
+ (value instanceof Sao.Decimal)) {
20259
20280
  this.input.val(value);
20260
20281
  this.input_text.val(value.toLocaleString(
20261
20282
  Sao.i18n.BC47(Sao.i18n.getlang()), options));
@@ -20390,7 +20411,13 @@ function eval_pyson(value){
20390
20411
  return this._parse(this.format, this.input.val());
20391
20412
  },
20392
20413
  set_value: function(value) {
20393
- this.input.val(this._format(this.format, value));
20414
+ if ((value instanceof Sao.DateTime) ||
20415
+ (value instanceof Sao.Date)) {
20416
+ value = this._format(this.format, value);
20417
+ } else {
20418
+ value = '';
20419
+ }
20420
+ this.input.val(value);
20394
20421
  },
20395
20422
  });
20396
20423
 
@@ -20574,7 +20601,7 @@ function eval_pyson(value){
20574
20601
  }
20575
20602
  this.view.columns.push(column);
20576
20603
 
20577
- if (attributes.optional) {
20604
+ if (attributes.optional && (name !== this.exclude_field)) {
20578
20605
  this.view.optionals.push(column);
20579
20606
  }
20580
20607
 
@@ -28090,6 +28117,7 @@ function eval_pyson(value){
28090
28117
  _parse_board: function(node, attributes) {
28091
28118
  var container = new Sao.View.Form.Container(
28092
28119
  Number(node.getAttribute('col') || 4));
28120
+ this.view.containers.push(container);
28093
28121
  this.view.el.append(container.el);
28094
28122
  this.parse_child(node, container);
28095
28123
  if (this._containers.length > 0) {
@@ -28133,9 +28161,23 @@ function eval_pyson(value){
28133
28161
  for (i = 0; i < this.actions.length; i++) {
28134
28162
  this.actions[i].display();
28135
28163
  }
28136
- for (i = 0; i < this.state_widgets.length; i++) {
28137
- this.state_widgets[i].set_state(null);
28164
+ var promesses = [];
28165
+ for (let state_widget of this.state_widgets.toReversed()) {
28166
+ var prm = state_widget.set_state(null);
28167
+ if (prm) {
28168
+ promesses.push(prm);
28169
+ }
28138
28170
  }
28171
+ for (const container of this.containers) {
28172
+ container.set_grid_template();
28173
+ }
28174
+ // re-set the grid templates for the StateWidget that are
28175
+ // asynchronous
28176
+ jQuery.when.apply(jQuery, promesses).done(() => {
28177
+ for (const container of this.containers) {
28178
+ container.set_grid_template();
28179
+ }
28180
+ });
28139
28181
  },
28140
28182
  active_changed: function(event_action) {
28141
28183
  for (const action of this.actions) {
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.2.9",
5
+ "version": "7.2.11",
6
6
  "homepage": "http://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/board.js CHANGED
@@ -7,6 +7,7 @@
7
7
  _parse_board: function(node, attributes) {
8
8
  var container = new Sao.View.Form.Container(
9
9
  Number(node.getAttribute('col') || 4));
10
+ this.view.containers.push(container);
10
11
  this.view.el.append(container.el);
11
12
  this.parse_child(node, container);
12
13
  if (this._containers.length > 0) {
@@ -50,9 +51,23 @@
50
51
  for (i = 0; i < this.actions.length; i++) {
51
52
  this.actions[i].display();
52
53
  }
53
- for (i = 0; i < this.state_widgets.length; i++) {
54
- this.state_widgets[i].set_state(null);
54
+ var promesses = [];
55
+ for (let state_widget of this.state_widgets.toReversed()) {
56
+ var prm = state_widget.set_state(null);
57
+ if (prm) {
58
+ promesses.push(prm);
59
+ }
60
+ }
61
+ for (const container of this.containers) {
62
+ container.set_grid_template();
55
63
  }
64
+ // re-set the grid templates for the StateWidget that are
65
+ // asynchronous
66
+ jQuery.when.apply(jQuery, promesses).done(() => {
67
+ for (const container of this.containers) {
68
+ container.set_grid_template();
69
+ }
70
+ });
56
71
  },
57
72
  active_changed: function(event_action) {
58
73
  for (const action of this.actions) {
package/src/common.js CHANGED
@@ -1293,10 +1293,18 @@
1293
1293
  .replace('not', '!').trim();
1294
1294
  }
1295
1295
  if (operator.endsWith('in')) {
1296
- if (operator == 'not in') {
1297
- operator = '!';
1296
+ if (value instanceof Array && value.length == 1) {
1297
+ if (operator == 'not in') {
1298
+ operator = '!=';
1299
+ } else {
1300
+ operator = '=';
1301
+ }
1298
1302
  } else {
1299
- operator = '';
1303
+ if (operator == 'not in') {
1304
+ operator = '!';
1305
+ } else {
1306
+ operator = '';
1307
+ }
1300
1308
  }
1301
1309
  }
1302
1310
  var formatted_value = this.format_value(field, value, target);
@@ -1934,10 +1942,13 @@
1934
1942
  .replace(escape + '%', '%')
1935
1943
  .replace(escape + '_', '_');
1936
1944
  },
1937
- quote: function(value) {
1945
+ quote: function(value, empty=false) {
1938
1946
  if (typeof value != 'string') {
1939
1947
  return value;
1940
1948
  }
1949
+ if (empty && value === '') {
1950
+ return '""';
1951
+ }
1941
1952
  if (value.contains('\\')) {
1942
1953
  value = value.replace(new RegExp('\\\\', 'g'), '\\\\');
1943
1954
  }
@@ -2096,7 +2107,8 @@
2096
2107
  return value;
2097
2108
  }
2098
2109
  },
2099
- format_value: function(field, value, target=null, context={}) {
2110
+ format_value: function(
2111
+ field, value, target=null, context={}, _quote_empty=false) {
2100
2112
  var format_float = function() {
2101
2113
  if (!value && value !== 0 && value !== new Sao.Decimal(0)) {
2102
2114
  return '';
@@ -2207,7 +2219,9 @@
2207
2219
  };
2208
2220
  converts.timestamp = converts.datetime;
2209
2221
  if (value instanceof Array) {
2210
- return value.map(v => this.format_value(field, v)).join(';');
2222
+ return value.map(
2223
+ v => this.format_value(field, v, null, context, true))
2224
+ .join(';');
2211
2225
  } else {
2212
2226
  var func = converts[field.type];
2213
2227
  if (func) {
@@ -2215,7 +2229,7 @@
2215
2229
  } else if (value === null) {
2216
2230
  return '';
2217
2231
  } else {
2218
- return this.quote(value);
2232
+ return this.quote(value, _quote_empty);
2219
2233
  }
2220
2234
  }
2221
2235
  },
@@ -2766,7 +2780,9 @@
2766
2780
  (single_value && operator == 'in' && value.length == 1)) &&
2767
2781
  (!count ||
2768
2782
  ((count === 1) && model.length && name.endsWith('.id')))) {
2769
- value = operator == '=' ? value : value[0];
2783
+ if ((operator == 'in') && single_value) {
2784
+ value = value[0];
2785
+ }
2770
2786
  if (model.length && name.endsWith('.id')) {
2771
2787
  model = model[0];
2772
2788
  value = [model, value];
package/src/model.js CHANGED
@@ -513,6 +513,7 @@
513
513
  for (const record of this) {
514
514
  if (record.get_loaded([field]) || changed || record.id < 0) {
515
515
  if (prev) {
516
+ prev.load(field, false);
516
517
  index = prev.field_get(field);
517
518
  } else {
518
519
  index = null;
@@ -1803,7 +1804,7 @@
1803
1804
  setdefault = false;
1804
1805
  }
1805
1806
  }
1806
- if (setdefault && !pre_validate) {
1807
+ if (setdefault && jQuery.isEmptyObject(pre_validate)) {
1807
1808
  this.set_client(record, value);
1808
1809
  state_attrs.domain_readonly = domain_readonly;
1809
1810
  }
@@ -2657,7 +2658,7 @@
2657
2658
  }
2658
2659
  for (const record2 of (record._values[this.name] || [])) {
2659
2660
  if (!record2.get_loaded() && (record2.id >= 0) &&
2660
- !pre_validate) {
2661
+ jQuery.isEmptyObject(pre_validate)) {
2661
2662
  continue;
2662
2663
  }
2663
2664
  if (!record2.validate(null, softvalidation, ldomain, true)) {
package/src/pyson.js CHANGED
@@ -431,7 +431,8 @@
431
431
  if ( (!(statement instanceof Sao.PYSON.DateTime ||
432
432
  statement instanceof Sao.PYSON.Date ||
433
433
  statement instanceof Sao.PYSON.TimeDelta)) &&
434
- (jQuery(statement.types()).not(['number']).length) ) {
434
+ (jQuery(statement.types()).not(
435
+ ['number', 'object']).length) ) {
435
436
  throw 'statement must be an integer, float, ' +
436
437
  'date, datetime or timedelta';
437
438
  }
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.2.9',
6
+ __version__: '7.2.11',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/sao.less CHANGED
@@ -393,6 +393,7 @@ html.accesskey {
393
393
  > .nav-tabs {
394
394
  display: inline-flex;
395
395
  white-space: nowrap;
396
+ width: 1px;
396
397
  }
397
398
  .badge {
398
399
  min-width: 3em;
@@ -500,7 +501,7 @@ img.icon {
500
501
  }
501
502
  }
502
503
 
503
- .screen-container {
504
+ .screen-container, .board {
504
505
  display: flex;
505
506
  flex-direction: column;
506
507
  flex: 1;
@@ -756,7 +757,7 @@ img.icon {
756
757
  }
757
758
  }
758
759
 
759
- .form {
760
+ .form, .board {
760
761
  width: 100%;
761
762
  height: 100%;
762
763
  .form-container, .form-hcontainer, .form-vcontainer {
package/src/screen.js CHANGED
@@ -833,10 +833,7 @@
833
833
  'class': 'col-md-12'
834
834
  }).append(this.context_screen.screen_container.el))
835
835
  .prependTo(this.screen_container.filter_box);
836
- return this.context_screen.new_(false).then(
837
- // Set manually default to get context_screen_prm
838
- // resolved when default is set.
839
- record => record.default_get());
836
+ return this.context_screen.new_();
840
837
  });
841
838
  }
842
839
 
package/src/tab.js CHANGED
@@ -1639,6 +1639,8 @@
1639
1639
  }
1640
1640
  this.dialogs = [];
1641
1641
  this.board = null;
1642
+ this.create_tabcontent();
1643
+ this.set_name(name);
1642
1644
  UIView = new Sao.Model('ir.ui.view');
1643
1645
  this.view_prm = UIView.execute(
1644
1646
  'view_get', [this.view_id], this.context);
@@ -1655,8 +1657,6 @@
1655
1657
  });
1656
1658
  this.content.append(this.board.el);
1657
1659
  });
1658
- this.create_tabcontent();
1659
- this.set_name(name);
1660
1660
  },
1661
1661
  compare: function(attributes) {
1662
1662
  if (!attributes) {
package/src/view/form.js CHANGED
@@ -14,6 +14,10 @@ function eval_pyson(value){
14
14
  (function() {
15
15
  'use strict';
16
16
 
17
+ function remove_newline(value) {
18
+ return value.replace(/[\n\r]/gm, '')
19
+ }
20
+
17
21
  Sao.View.FormXMLViewParser = Sao.class_(Sao.View.XMLViewParser, {
18
22
  init: function(view, exclude_field, field_attrs) {
19
23
  Sao.View.FormXMLViewParser._super.init.call(
@@ -2612,7 +2616,7 @@ function eval_pyson(value){
2612
2616
  get_text: function() {
2613
2617
  var record = this.record;
2614
2618
  if (record) {
2615
- return record.field_get_client(this.field_name);
2619
+ return remove_newline(record.field_get_client(this.field_name));
2616
2620
  }
2617
2621
  return '';
2618
2622
  },
@@ -2628,7 +2632,7 @@ function eval_pyson(value){
2628
2632
  set_value: function() {
2629
2633
  var record = this.record;
2630
2634
  var field = this.field;
2631
- if (field.get_client(record) != this.entry.val()) {
2635
+ if (this.get_text() != this.entry.val()) {
2632
2636
  field.set_client(record, this.value_from_id(null, ''));
2633
2637
  this.entry.val('');
2634
2638
  }
@@ -2723,7 +2727,7 @@ function eval_pyson(value){
2723
2727
  get modified() {
2724
2728
  if (this.record && this.field) {
2725
2729
  var value = this.entry.val();
2726
- return this.field.get_client(this.record) != value;
2730
+ return this.get_text() != value;
2727
2731
  }
2728
2732
  return false;
2729
2733
  },
@@ -3051,7 +3055,7 @@ function eval_pyson(value){
3051
3055
  name = '';
3052
3056
  if (value) {
3053
3057
  model = value[0];
3054
- name = value[1];
3058
+ name = remove_newline(value[1]);
3055
3059
  }
3056
3060
  return ((model != this.get_model()) ||
3057
3061
  (name != this.entry.val()));
@@ -3070,7 +3074,8 @@ function eval_pyson(value){
3070
3074
  get_text: function() {
3071
3075
  var record = this.record;
3072
3076
  if (record) {
3073
- return record.field_get_client(this.field_name)[1];
3077
+ return remove_newline(
3078
+ record.field_get_client(this.field_name)[1]);
3074
3079
  }
3075
3080
  return '';
3076
3081
  },
@@ -3124,7 +3129,7 @@ function eval_pyson(value){
3124
3129
  var model, name;
3125
3130
  if (value instanceof Array) {
3126
3131
  model = value[0];
3127
- name = value[1];
3132
+ name = remove_newline(value[1]);
3128
3133
  } else {
3129
3134
  model = '';
3130
3135
  name = '';
@@ -5317,7 +5322,7 @@ function eval_pyson(value){
5317
5322
  this.input.prop('disabled', readonly);
5318
5323
  },
5319
5324
  set_value: function(value) {
5320
- this.input.prop('checked', value);
5325
+ this.input.prop('checked', Boolean(value));
5321
5326
  }
5322
5327
  });
5323
5328
 
@@ -5420,7 +5425,8 @@ function eval_pyson(value){
5420
5425
  return value;
5421
5426
  },
5422
5427
  set_value: function(value, options) {
5423
- if (value !== null) {
5428
+ if ((typeof(value) == 'number') ||
5429
+ (value instanceof Sao.Decimal)) {
5424
5430
  this.input.val(value);
5425
5431
  this.input_text.val(value.toLocaleString(
5426
5432
  Sao.i18n.BC47(Sao.i18n.getlang()), options));
@@ -5555,7 +5561,13 @@ function eval_pyson(value){
5555
5561
  return this._parse(this.format, this.input.val());
5556
5562
  },
5557
5563
  set_value: function(value) {
5558
- this.input.val(this._format(this.format, value));
5564
+ if ((value instanceof Sao.DateTime) ||
5565
+ (value instanceof Sao.Date)) {
5566
+ value = this._format(this.format, value);
5567
+ } else {
5568
+ value = '';
5569
+ }
5570
+ this.input.val(value);
5559
5571
  },
5560
5572
  });
5561
5573
 
package/src/view/tree.js CHANGED
@@ -71,7 +71,7 @@
71
71
  }
72
72
  this.view.columns.push(column);
73
73
 
74
- if (attributes.optional) {
74
+ if (attributes.optional && (name !== this.exclude_field)) {
75
75
  this.view.optionals.push(column);
76
76
  }
77
77
 
package/tests/sao.js CHANGED
@@ -519,6 +519,20 @@
519
519
  QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false,
520
520
  'decode(Greater(PYSON.Date(2020, 1, 1), Date(2020, 0, 1)))');
521
521
 
522
+ eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(
523
+ new Sao.PYSON.Eval('foo', Sao.Date(2020, 0, 1)),
524
+ Sao.Date(2020, 0, 1)));
525
+ QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false,
526
+ 'decode(Greater(PYSON.Eval("foo", Date(2020, 1, 1)), ' +
527
+ 'Date(2020, 0, 1)))');
528
+
529
+ eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(
530
+ new Sao.PYSON.Eval('foo', new Sao.PYSON.Date(2020, 1, 1)),
531
+ new Sao.PYSON.Date(2020, 1, 1)));
532
+ QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false,
533
+ 'decode(Greater(PYSON.Eval("foo", PYSON.Date(2020, 1, 1)), ' +
534
+ 'PYSON.Date(2020, 1, 1)))');
535
+
522
536
  eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(
523
537
  new Sao.PYSON.Date(2020, 1, 1),
524
538
  new Sao.PYSON.DateTime(2020, 1, 1, 0, 0, 0, 1)));
@@ -2273,7 +2287,10 @@
2273
2287
  [[['name', 'ilike', 'Doe\\%']], 'Name: =Doe%'],
2274
2288
  [[['name', 'not ilike', '%Doe%']], 'Name: !Doe'],
2275
2289
  [[['name', 'in', ['John', 'Jane']]], 'Name: John;Jane'],
2290
+ [[['name', 'in', ['John', '']]], 'Name: John;""'],
2291
+ [[['name', 'in', ['John']]], 'Name: =John'],
2276
2292
  [[['name', 'not in', ['John', 'Jane']]], 'Name: !John;Jane'],
2293
+ [[['name', 'not in', ['John']]], 'Name: !=John'],
2277
2294
  [[
2278
2295
  ['name', 'ilike', '%Doe%'],
2279
2296
  ['name', 'ilike', '%Jane%']