Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/12.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add/fix missing/incorrect field definitions for records
26 changes: 23 additions & 3 deletions docs/managers/product.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,16 @@ The record class currently implements the following fields and methods.
For more information on attributes and methods common to all record types,
see [Record Attributes and Methods](index.md#attributes-and-methods).

### `active`

```python
active: bool
```

Whether or not this product is active (enabled).

*Added in version 0.2.0.*

### `categ_id`

```python
Expand Down Expand Up @@ -311,14 +321,15 @@ and caches it for subsequent accesses.
### `default_code`

```python
default_code: str
default_code: str | Literal[False]
```

The Default Code for this product.
The Default Code for this product, if set.

In the OpenStack Integration add-on, this is used to store
the rated unit for the service product.

*Changed in version 0.2.0*: Made `default_code` optional.

### `description`

Expand Down Expand Up @@ -346,7 +357,6 @@ The list price of the product.

This becomes the unit price of the product on invoices.


### `name`

```python
Expand All @@ -355,6 +365,16 @@ name: str

The name of the product.

### `sale_ok`

```python
sale_ok: bool
```

Whether or not this product is sellable.

*Added in version 0.2.0.*

### `uom_id`

```python
Expand Down
90 changes: 90 additions & 0 deletions docs/managers/sale-order.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,39 @@ For more information on how to use managers, refer to [Managers](index.md).

The following manager methods are also available, in addition to the standard methods.

### `action_cancel`

```python
action_cancel(
sale_order: int | SaleOrder,
) -> None
```

Cancel the given sale order.

```python
>>> from openstack_odooclient import Client as OdooClient
>>> odoo_client = OdooClient(
... hostname="localhost",
... port=8069,
... protocol="jsonrpc",
... database="odoodb",
... user="test-user",
... password="<password>",
... )
>>> odoo_client.sale_orders.action_cancel(
... sale_order=1234, # ID or object
... )
```

*Added in version 0.2.0.*

#### Parameters

| Name | Type | Description | Default |
|--------------|-------------------|--------------------------|------------|
| `sale_order` | `int | SaleOrder` | The sale order to cancel | (required) |

### `action_confirm`

```python
Expand Down Expand Up @@ -187,6 +220,39 @@ display_name: str

The display name of the sale order.

### `invoice_count`

```python
invoice_count: int
```

The number of [invoices (account moves)](account-move.md) generated from the sale order.

*Added in version 0.2.0.*

### `invoice_ids`

```python
invoice_ids: list[int]
```

A list of IDs for [invoices (account moves)](account-move.md) generated from the sale order.

*Added in version 0.2.0.*

### `invoices`

```python
invoices: list[AccountMove]
```

The [invoices (account moves)](account-move.md) generated from the sale order.

This fetches the full records from Odoo once,
and caches them for subsequent accesses.

*Added in version 0.2.0.*

### `invoice_status`

```python
Expand Down Expand Up @@ -337,6 +403,30 @@ Values:
* ``done`` - Finalised and settled sale order, cannot be modified
* ``cancel`` - Cancelled sale order, can be deleted in most cases

### `action_cancel`

```python
action_cancel() -> None
```

Cancel this sale order.

```python
>>> from openstack_odooclient import Client as OdooClient
>>> odoo_client = OdooClient(
... hostname="localhost",
... port=8069,
... protocol="jsonrpc",
... database="odoodb",
... user="test-user",
... password="<password>",
... )
>>> sale_order = odoo_client.sale_orders.get(1234)
>>> sale_order.action_cancel()
```

*Added in version 0.2.0.*

### `action_confirm`

```python
Expand Down
5 changes: 3 additions & 2 deletions openstack_odooclient/base/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from dataclasses import dataclass
from datetime import date, datetime
from types import MappingProxyType
from types import MappingProxyType, UnionType
from typing import (
TYPE_CHECKING,
Annotated,
Expand Down Expand Up @@ -392,7 +392,8 @@ def _getattr_model_ref(
# The following is for decoding a singular model ref value.
# Check if the model ref is optional, and if it is,
# return the desired value for when the value is empty.
if get_type_origin(attr_type) is Union:
attr_type_origin = get_type_origin(attr_type)
if attr_type_origin is Union or attr_type_origin is UnionType:
unsupported_union = (
"Only unions of the format Optional[T], "
"Union[T, type(None)] or Union[T, Literal[False]] "
Expand Down
2 changes: 1 addition & 1 deletion openstack_odooclient/base/record_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def get(
:param optional: Return ``None`` if not found, defaults to ``False``
:raises RecordNotFoundError: Record with the given ID not found
:return: List of records
:rtype: Record | list[str, Any]
:rtype: Record | dict[str, Any]
"""
try:
return self.list(
Expand Down
18 changes: 16 additions & 2 deletions openstack_odooclient/managers/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@


class Product(RecordBase["ProductManager"]):
active: bool
"""Whether or not this product is active (enabled).

*Added in version 0.2.0.*
"""

categ_id: Annotated[int, ModelRef("categ_id", ProductCategory)]
"""The ID for the category this product is under."""

Expand All @@ -53,11 +59,13 @@ class Product(RecordBase["ProductManager"]):
and caches it for subsequent accesses.
"""

default_code: str
"""The Default Code for this product.
default_code: str | Literal[False]
"""The Default Code for this product, if set.

In the OpenStack Integration add-on, this is used to store
the rated unit for the service product.

*Changed in version 0.2.0*: Made `default_code` optional.
"""

description: str
Expand All @@ -75,6 +83,12 @@ class Product(RecordBase["ProductManager"]):
name: str
"""The name of the product."""

sale_ok: bool
"""Whether or not this product is sellable.

*Added in version 0.2.0.*
"""

uom_id: Annotated[int, ModelRef("uom_id", Uom)]
"""The ID for the Unit of Measure for this product."""

Expand Down
48 changes: 48 additions & 0 deletions openstack_odooclient/managers/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,30 @@ class SaleOrder(RecordBase["SaleOrderManager"]):
display_name: str
"""The display name of the sale order."""

invoice_count: int
"""The number of invoices generated from the sale order.

*Added in version 0.2.0.*
"""

invoice_ids: Annotated[list[int], ModelRef("invoice_ids", AccountMove)]
"""A list of IDs for invoices generated from the sale order.

*Added in version 0.2.0.*
"""

invoices: Annotated[
list[AccountMove],
ModelRef("invoice_ids", AccountMove),
]
"""The invoices generated from the sale order.

This fetches the full records from Odoo once,
and caches them for subsequent accesses.

*Added in version 0.2.0.*
"""

invoice_status: Literal["no", "to invoice", "invoiced", "upselling"]
"""The current invoicing status of this sale order.

Expand Down Expand Up @@ -145,6 +169,13 @@ class SaleOrder(RecordBase["SaleOrderManager"]):
* ``cancel`` - Cancelled sale order, can be deleted in most cases
"""

def action_cancel(self) -> None:
"""Cancel this sale order.

*Added in version 0.2.0.*
"""
self._env.action_cancel(self.id)

def action_confirm(self) -> None:
"""Confirm this sale order."""
self._env.action_confirm(self.id)
Expand All @@ -158,6 +189,22 @@ class SaleOrderManager(NamedRecordManagerBase[SaleOrder]):
env_name = "sale.order"
record_class = SaleOrder

def action_cancel(self, sale_order: int | SaleOrder) -> None:
"""Cancel the given sale order.

*Added in version 0.2.0.*

:param sale_order: The sale order to cancel
:type sale_order: int | SaleOrder
"""
self._env.action_cancel(
(
sale_order.id
if isinstance(sale_order, SaleOrder)
else sale_order
),
)

def action_confirm(self, sale_order: int | SaleOrder) -> None:
"""Confirm the given sale order.

Expand Down Expand Up @@ -188,6 +235,7 @@ def create_invoices(self, sale_order: int | SaleOrder) -> None:


# NOTE(callumdickinson): Import here to avoid circular imports.
from .account_move import AccountMove # noqa: E402
from .currency import Currency # noqa: E402
from .partner import Partner # noqa: E402
from .project import Project # noqa: E402
Expand Down
Loading