The main goal of this commit is to reduce the size of the registry by
removing the (almost) useless __last_update field.
Statistics # of fields with all modules installed:
before 30184 fields, 1299x last_update (4.30%)
Before this commit, the computed field __last_update was added on every model.
The idea behind this field was to have a computed field that had either
the write_date or the create_date if the write_date was empty. However,
the write_date is always written, even on creation, making it useless
to have the computed field __last_update
After this update, we completely remove from BaseModel:
* __last_update
* CONCURRENCY_CHECK_FIELD that was always defined as "__last_update"
* _compute_concurrency_field that was the compute function for __last_update
closesodoo/odoo#105739
Task-id: 3062140 (part of 3062137 improve registry load time)
Related: odoo/upgrade#4038
Related: odoo/enterprise#33939
Signed-off-by: Raphael Collet <rco@odoo.com>
Steps to reproduce
==================
- Create an invoice
- Add a line
- Type storage in the product field
- Ctrl+A then press backspace
- Press escape to close the autocomplete dropdown
- Click elsewhere
-> The first suggestion is now selected
opw-3055185
closesodoo/odoo#107302
X-original-commit: e0613bc06ba9f2653dd0cfc4057ba93abf8513f7
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
The fix in #106174 was not good.
The translation dialog cannot update not translated terms
the initial term value may be empty "" when the source and the translation are
the same at first. So, the source to for update_field_translations should be
const source = term.value ? term.value : term.source;
closesodoo/odoo#106528
X-original-commit: 1ed5ce6f16d32efc0c5ec4cead67b2d8a57f6c41
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Before this commit, new model term translations cannot be saved if it has been
translated before.
The reason is while translating fr_FR
the backend needs the mapping {old_term_fr: new_term_fr} to update old_value_fr
However the UI sent {old_term_en: new_term_fr} which was wrong
This commit fixes the bug by changing the key of the mapping from the
old_term_en to the old_term_fr
opw-3074712
closesodoo/odoo#106257
X-original-commit: f28c11917e093d0d3f5d18f0b377cfb24a7dbd92
Signed-off-by: Samuel Degueldre <sad@odoo.com>
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
Unused catch block arguments are now forbidden even when prefixed with an
underscore: if the argument on the catch block is not needed, the use of the
optional catch binding is enforced.
Part-of: odoo/odoo#105433
Due to a previous fix, attachments uploaded through media dialog would appear in the attachments of mail marketting.
That fix prevents attachments from 'dangling' and being garbage collected later.
That fix is now limited to the mail composer in this commit as attachments are only garbage collected for that model, for now.
related commit: c112361bf9e2f5e7b087c5e5b9a31879856b1da4
task 3003939
closesodoo/odoo#103038
X-original-commit: 69fdca133b06eb66443635bc52d380233580ef51
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit adapts several components in order to correctly handle
color-scheme variations.
It also allows user_menu to handle switch entries
task-2710677
Part-of: odoo/odoo#102868
This field widget is no longer used in form, list or kanban views,
so it hasn't been converted to owl. This commit removes its legacy
implementation from the registry, s.t. we ensure nobody use it
again. Moreover, we adapted a new view test using it to use another
field widget instead, to remove the dependency and ease the removal
that should happen soon.
closesodoo/odoo#101787
X-original-commit: 68cfd4b08bc9ab0305ae9033e42820370b52bdf3
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
An event was not called on uploading files in a media dialog.
This meant the parent of html field didn't know of the new attachments
which resulted in attachments being linked to no record at all
and not being garbage collected later.
This adds a reference inside the media dialog file input so that it can
trigger that event on behalf of the html field.
The attachments newly uploaded in media dialog are uneditable
to prevent users from unlinking attachments
that are still used in the body of the composer (causing the same issue)
Task-2860761
closesodoo/odoo#101405
X-original-commit: f4dd1eb3f25672e7309759c347e2b552c5652b2f
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Steps to reproduce:
- in Barcode > Inventory Adjustment
In the quantities add a decimal numpad
Issue:
Traceback
Cause:
The field is from type=number. This kind of field does not accept methods such `selectionStart()` or `selectionEnd` which causes an error: https://html.spec.whatwg.org/multipage/input.html#do-not-apply
Solution:
When of type=number, just return.
On Chrome, numpad won't be possible for regions such as Portugese - BR. They would have to use the keyboard key `period`, code '.' in order to be able to put a decimal via the keyboard.
In Firefox, HTML is parsing the input correctly if the browser settings are set to the right localization. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#localization
opw-2956481
closesodoo/odoo#100953
X-original-commit: d95fbd80f63efbb47c9635e299f6ac417c5cb4c2
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Yolann Sabaux (yosa) <yosa@odoo.com>
In a form view, have a o2m field (A), with a nested o2m field (B).
The A field should have multiple pages, with each record having at least one record
in their B field.
Have a (C) field that will modify a record in the nested o2m when changed.
Change the C field, and save.
Before this commit, the record's nested o2m from the other page had a wrong value
(a mere 4 command).
After this commit, their value is a command 4 and a command 1, with the right values.
closesodoo/odoo#99986
X-original-commit: e45e3b83f0f3116cc983c6bd8a9212e815b4d4f5
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Purpose:
Improve performance/reduce server load for the status bar widget when
the underlying field is a m2o.
Before this commit:
The status bar widget does two calls:
- a search_read request to retrieve ids and folds
- a name_get to retrieve names
With this commit:
The name_get can be avoided to save a call by fetching display_name in
the search_read.
This commit removes the name_get call to retrieve the name directly
from search_read.
task-2919535
closesodoo/odoo#98164
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Steps to reproduce:
- Switch language to french
- Refresh the page
- Create a new payment
- Select a partner
- Enter an amount of 100000,00
- Save the record
-> The following field is incorrect: amount
Cause of the issue:
Since https://github.com/odoo/odoo/pull/97425 ,
`parseMonetary` wrongly assumed that a currency was always passed in
the parameters
opw-2937403
closesodoo/odoo#97861
X-original-commit: 9d518f847d2204fc5159a92bc4e4de655acf88fa
Signed-off-by: Jorge Pinna Puissant (jpp) <jpp@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
Steps to reproduce:
- Switch odoo language to french
- Create a client bill for Azure Interior of $1 000 000
- Confirm it
- Go to the accounting dashboard
- On the bank, click on reconcile
- Select Azure interior
- Click on the correct bill
- Switch to Manual operations
-> $1 000 000 is not a correct monetary field
Cause of the issue:
Recently in https://github.com/odoo/odoo/pull/94126 , `formatMonetary`
switched from joining the currency and symbol from ` ` to a non
breaking space, NBSP.
To parse monetary values, the behavior was to split around NBSP to
get the symbol on one side and the value on the other which is then
passed to `parseFloat`.
For the following examples, NBSP is replaced with an underscore.
So `$_1000` becomes `$, 1000`
But some languages such as french uses the same char as thousands
separator.
In that case, `$_1_000` becomes `$, 1, 000` and then the parse fails.
opw-2937403
closesodoo/odoo#97513
X-original-commit: 9d36722797669498dfd1ad4659e5f29347ba30f3
Signed-off-by: Jorge Pinna Puissant (jpp) <jpp@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
Fields with widget `radio` and `boolean` can't be edited
Steps to reproduce:
1. Install Discuss
2. Connect as demo and go to your preferences (top right)
3. You can't edit your notification type
Solution:
Use widgetOptions' mode along with hasReadonlyModifier to disable the
fields
Problem:
This PR https://github.com/odoo/odoo/pull/88223 modified the value of
hasReadonlyModifier which is used to disable radio and boolean fields
opw-2898464
closesodoo/odoo#97106
X-original-commit: 6befccd7c8ac22fe4da2a741efeecde2d036a7b9
Signed-off-by: Guillaume Merlin (megu) <megu@odoo.com>
The new list and form views were merged recently [1], but they
weren't activated because they weren't 100% ready yet. This is now
the case. This commit adds those views to the view registry. As a
consequence, a lot of qunit tests and tours needed to be adapted,
mostly for selector changes.
We also add legacy list and form views to the view registry, with
keys 'legacy_list' and 'legacy_form'. This allows to force those
legacy views when necessary. For instance, we did it in views
using complex custom legacy x2many field widgets that haven't been
converted yet (we have a compatibility layer but it isn't complete
and doesn't support every advanced usecases).
[1] odoo/odoo#92475
Part-of: odoo/odoo#78221
Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Bruno Boi <boi@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Samuel Degueldre <sad@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Co-authored-by: Simon Genin (ges) <ges@odoo.com>
Co-authored-by: Francois (fge) <fge@odoo.com>
Co-authored-by: Michael Mattiello (mcm) <mcm@odoo.com>
Co-authored-by: Julien Mougenot <jum@odoo.com>
Co-authored-by: Lucas Perais (lpe) <lpe@odoo.com>
Co-authored-by: Jorge Pinna Puissant <jpp@odoo.com>
Co-authored-by: luvi <luvi@odoo.com>
- BS5 uses native inputs instead of pseudo-element for some
input like checkbox, radio, ...
in BS5 input checkbox don't have "virtual visual" checkbox anymore
(::before), so we remove the relative's rules
- removed `.custom-control` class
- `form-switch` use a new layout system in BS5 we adapt the code to
match the Bootstrap approach (inline SVG).
- In tests, we don't check the exact value of the background as it
change in community/enterprise, and it's difficult to check the value
of an SVG.
- Overflow in progressbar is now hidden.
-> we had to restore it.
- In BS5 margins in forms/inputs has been changed
-> we had to restore it (e.g. 'mb-3')
- .form-group, .form-row, .form-inline
> Dropped form-specific layout classes for our grid system.
> Use our grid and utilities instead of .form-group, .form-row,
> or .form-inline.
- .input-group-append and .input-group-prepend
> Dropped .input-group-append and .input-group-prepend.
> You can now just add buttons and .input-group-text as direct
> children of the input groups.
Ref:
[1] https://getbootstrap.com/docs/5.1/migration/#forms
Task ID: 2766483
Part-of: odoo/odoo#95450
- modal 'show' option doesn't exist anymore
-> We need to call .show()
- by default, show is not the default
-> we need to call .show() explicitly.
- generic close button for dismissing content like modals and alerts.
- BS5 modals needs `modal-dialog` class to work
- normally we need also to add `modal-content` class but as the original
XML don't have this nested level of div we don't use it, but instead
we add `pointer-events: auto` for all children `DIV` of `modal-dialog`
-> See DocumentViewer
Task ID: 2766483
Part-of: odoo/odoo#95450
* data('bs.popover') is not a jQuery data anymore
-> fetch data from the instance instead.
* use the new class name 'popover-arrow' instead of 'arrow'
* website_forum: offset is not a number anymore
-> Convert to string instead.
* BS5 event listener: 'focus' -> 'focusin'
* use `mouseover` event to show and `mouseout` to hide.
* disable at some point the animation to avoid remaining listener
in the DOM.
Ref:
https://getbootstrap.com/docs/5.1/migration/#popovers
Task ID: 2766483
Part-of: odoo/odoo#95450
This commit introduces the new kanban, list and form views written
in owl. Even though it contains the implementation of those 3 views,
only the kanban view is activated for now (the list and form views
aren't 100% ready yet, so they aren't added to the view registry).
Alongside the views, the fields (<field name="..."/> in archs) and
widgets (<widget name="..." in archs) of web/ have been implemented
in owl as well. Legacy ones remaining in other addons are supported
in our new views, thanks to a compatibility layer. The goal is to convert
them asap though.
Legacy views, fields and widgets are kept for now, which explains the
number of added lines in this PR (around half of them concern tests).
They are still extended by custom code in other addons, that still need
to be converted (a lot of them are already on the way). Moreover,
they are still used in Studio as well. The plan is to lazy load them in
the Studio bundle when all custom code extending them will be
converted. Studio will be converted for v17.
Part-of: odoo/odoo#92475
Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Bruno Boi <boi@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Samuel Degueldre <sad@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Co-authored-by: Simon Genin (ges) <ges@odoo.com>
Co-authored-by: Francois (fge) <fge@odoo.com>
Co-authored-by: Michael Mattiello (mcm) <mcm@odoo.com>
Co-authored-by: Julien Mougenot <jum@odoo.com>
Co-authored-by: Lucas Perais (lpe) <lpe@odoo.com>
Co-authored-by: Jorge Pinna Puissant <jpp@odoo.com>
Co-authored-by: luvi <luvi@odoo.com>
When creating a custom datetime field (with date option type) with Studio and
that you edit the field manually then validates with the ENTER keyboard, the
date is changed (one day is removed - mm/dd-1/yy).
Since [1].
Step to reproduce the issue:
1. Put yourself in Europe timezone (e.g. BE)
2. Add a datetime field via studio (e.g. on the product form)
3. Put a date widget (no datetime)
4. Enter a date manually mm/dd/yy
5. Hit ENTER without clicking outside the box
You will see that the final date will be mm/dd-1/yy.
Solution: The path applied when clicking outside the box and cliking ENTER is
not the same. In the ENTER path, we check if the type of the field is a
`datetime`, if so, we remove the offset TZ to match 00:00:00 instead of
02:00:00 (if you were in GMT+2 zone). The issue is that we do this offset
if the customm field (via Studio) is a `datetime`. This check is incorrect: we
can have a `datetime` field but a date widget, in that case, if we are not on
GMT time we offset by some hours and we end up the day before (as we offset by
2 hours starting from midnight which results in 22PM the day before and when
rendered as a simple date we "loose" one day).
[1]: https://github.com/odoo/odoo/commit/08a423577f732b65ad5035e8f4662386a8631c5f
opw-2830843
closesodoo/odoo#93293
X-original-commit: 37a58832bc966f28fb2c1d627dfe28cef4fb5de7
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Desausoi Laurent (lade) <lade@odoo.com>
Step to reproduce:
- Open 'Sales'
- Open a SO
- Click on the product link in the OrderLine tree
Current Behaviour:
- Breadcrumbs are cleared
Since https://github.com/odoo/odoo/commit/cefd6ade293e6cfa8ec405f55c6d4d7194f36e7e the onClick is only triggered in form view
Behaviour after PR:
- Breadcrumbs are not cleared
Link are now trigger via another click action '_onLinkClick' and quickEdit does not trigger on URL click
Test provided by Anh Thao (pta)
opw-2748041
closesodoo/odoo#85203
X-original-commit: 8ba45fde9f248e5a2b76ff3e934d9784d5d57ff0
Signed-off-by: Damhaut Florian (flda) <flda@odoo.com>
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
In some cases, we want to use the regular FieldMonetary widget (performing the amount rounding correctly) but without displaying the currency symbol since the currency code is displayed elsewhere.
This is needed because some currencies are using the same currency symbol like USD / MXN.
Task: 2555114
Part-of: odoo/odoo#91448
It is very common when using kanban view to need a way to declare what
action is executed when clicking on a record. The default action
(switching to form view) is sometimes not what we would like. For
example, clicking on a project kanban record should open the
corresponding tasks, instead of the project form view.
Until this commit, it was not possible to do this simply for a whole
kanban record, however it was possible to add a button with a name and
type attribute to specify the resulting action. This commit introduces
the same idea, but on the complete kanban record, instead of just a sub
element.
To specify the action that should be executed when clicking on a record,
one can now use the 2 attributes 'action' and 'type' (which corresponds
to the 'name' and 'type' attribute for the kanban record. 'name' was
also considered, but it was too weird). For example:
<kanban default_order="name" action="action_brand_model" type="object">
...
</kanban>
Part-of: odoo/odoo#92071
The boolean_toggle should only be disabled when there is a readonly
modifier, not when the view is in readonly mode.
Cause of the issue
The input was disabled but the `_onClick` was registered on the
widget root node.
Solution
- Listen for clicks on the input element
- Override the render method to set the disabled prop according to the
readonly modifier.
opw-2739468
closesodoo/odoo#91601
X-original-commit: 29a2402153dc95414dad8c833487e7dd18c8a222
Signed-off-by: Michaël Mattiello <mcm@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
Since https://github.com/odoo/odoo/pull/87584
with `date` field, pressing enter will removes 1 day to the value.
To fix it we have to ignore the offset suppression used for `datetime`
opw-2818927
closesodoo/odoo#90115
X-original-commit: 46e6475708c7ba8289345c4f7c125f60fc77d08c
Signed-off-by: Achraf <abz@odoo.com>
The problem is generally due to the use of `var`, this one
https://github.com/odoo-dev/odoo/blob/58a046d2146e884d467cde827f89fa603ed98a3b/addons/web/static/src/js/views/basic/basic_model.js#L1780 followed by an asynchronous call to a function using it
We can therefore summarize the part of the `_applyOnChange` function
that interests us by
```js
for () {
if (field. type === 'one2many' || field. type === 'many2many') {
var list;
...
//using list
...
promiseFunction(list).then(function(){
//using list
})
}
}
```
In the case where we have two one2many which follow each other,
this scenario occurs:
- `list` is initially the first o2m
- the `promiseFunction` is called with `list` (first o2m)
- before the promise is resolved the loop continues
- `list` is `Promise.then()` the second o2m
- the first call to `promiseFunction` with `list` (first o2m) is done
- we enter in `Promise.then()`
- `list` is currently worth the value of the second o2m because
`list` is a `var`
- the second call to `promiseFunction` with `list` is finished
- we enter the `Promise.then()`
- `list` is currently worth the value of the second o2m because
`list` is a `var`
Result: `Promise.then()` is called twice with the first o2m and never
with the second
We can see what happened with this code example:
```js
const array = ["a", "b"];
const asyncRead = async(value) => {
console.log("async function arg", value)
setTimeout(()=>{
return Promise. resolve(value);
}, 100)
}
const forFunction = () => {
for (let i = 0; i < array.length; i++){
var list = array[i];
asyncRead(list).then(function (){
console.log("then async function arg", list)
})
}
}
forFunction()
/*
async function arg a
async function arg b
then async function arg b
then async function arg b
*/
```
While if:
We use `let`
by replacing `var list = array[i];` with `let list = array[i];`
OR
We force the use of `Promise.resolve()` argument
by replacing `.then(function (){}` with `.then(function (list){}`
We will get:
```js
/*
async function arg a
async function arg b
then async function arg a
then async function arg b
*/
```
opw-2694855
closesodoo/odoo#89160
X-original-commit: 99cb2f52e109ccf94ac8bd735cd776e84ef04260
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
opw-2729810
closesodoo/odoo#87918
X-original-commit: 65f4c4f29a9c747f114eb6359d3ebb036efab9d6
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
When entering a date in a datetime field, it will be in the format
`08/01/2022 00:00:00`. If we place our cursor at the end of the
entry (after the hour) and each time we press enter, the timezone
offset is applied (so if offset is +1 it does +1 hour each time)
opw-2754116
closesodoo/odoo#87655
X-original-commit: 33e8540d64bb6e21debb7da9a121b706f551ab2e
Signed-off-by: Achraf <abz@odoo.com>
This commit fixes a bug present in FieldEmail and
FieldPhone where the handler on the click event was
triggered twice and was not preventing the field to
turn into quick edit mode appropriately.
A test has been added for EmailField to ensure the
correct behavior
PR enterprise: odoo/enterprise#25506closesodoo/odoo#87196
X-original-commit: 852e084c355e9be77c693b32bf1119570e4d49d0
Related: odoo/enterprise#25558
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Steps to follow
- Go to the product page
- Open studio
- Click on the picture and set the size to large
- Save and quit studio
-> The size doesn't change
Cause of the issue
Studio sets the size attribute on the field as `[0, 270]`
This means the picture should have a height of 270px and an unspecified width.
But for that to work, we need to handle the case were only one
dimension is set.
opw-2745625
closesodoo/odoo#87226
X-original-commit: 50368a9db8ac67986cf64ff84ee625cbf7a90a1f
Signed-off-by: Anh Thao PHAM <pta@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
Steps to reproduce:
- create a contact with a very long name
- create a quotation
- in customer, type the first letter of the very long customer's name
- try to use the horizontal scroll bar
Issue:
close window on horizontal scroll
Solution:
Discriminate an horizontal scroll from a vertical scroll
A test has been added as well as the triggerScroll utility function
to allow proper tests when scrolling on elements
opw-2777443
closesodoo/odoo#86744
X-original-commit: e0b26496196bd4ee39fa06e1a3274982d2c7fb12
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Co-authored-by: Iucapad <luvi@odoo.com>
All named arguments on the catch block must be used. If for some motive
the named argument on the catch block is not used, its name must begin
with '_'.
closesodoo/odoo#85569
Related: odoo/enterprise#24867
Related: odoo/design-themes#552
Signed-off-by: Géry Debongnie <ged@odoo.com>
For the moment we cannot star a product from the form of sales view
Steps:
-Sales/Quotation
- Create new quotation
- Add a new product in the order lines
- Open product form from External link
- Try to star product
Because of the quickedit the onClick is called when it shouldn't,
the solution would be to rename the onClick function so that it
doesn't interfere with the quickEdit.
opw-2759063
closesodoo/odoo#85242
X-original-commit: edafd9fe49b1e4c73ee1768efc3df26b463b2f14
Signed-off-by: Achraf <abz@odoo.com>
*: mail, mrp
Previously, to prevent images and iframes from making GET requests in
tests, we would listen for the DOMNodeInserted event. This event is
deprecated and should not be used. Additionally, we weren't listening
for attiribute changes for performance reasons, which would result in
some GET requests still being made when an src attribute was changed.
This commit changes the mechanism that is used to do this from mutation
events to a MutationObserver which is not deprecated, and now also
listens for attribute modifications as MutationObservers can be
configured to only listen for changes to certain attributes, greatly
alleviating the performance impact of listening for those.
This mechanism has also been enabled globally by doing it once in the
test setup code, instead of requiring one to call a specific helper, as
we never want to make real requests during tests.
Some tests have been adapted to this new behaviour.
closesodoo/odoo#85216
Related: odoo/enterprise#24665
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
When combining the context for an RPC, the
additional context is being added before the raw
context.
Because of this, a use case such as:
- A o2m field with a context {'field': 'a'}
with a tree editable view below it
- That view defines controls to create lines,
which would change the context key 'field' to
another value.
=> The field context key would take precedence on
the creates key, making it impossible to override
that key in specific circumstances.
closesodoo/odoo#83996
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Purpose of this commit to add format_type option in daterange
widget.
So, In this add format_type option in nodeoption which convert
actual formatType to given format_type in option and add test
case for that feature.
task:2710539
Closes: #81630
Related: odoo/enterprise#22994
Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>