Skip to content

Commit 28e7054

Browse files
author
Callum Dickinson
committed
Add fiscal position record type
Add a new `FiscalPosition` record type, and an accompanying `fiscal_positions` record manager. Other record types have had model refs for fiscal positions added.
1 parent 4d4f097 commit 28e7054

File tree

8 files changed

+376
-0
lines changed

8 files changed

+376
-0
lines changed

docs/managers/fiscal-position.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Fiscal Positions
2+
3+
*Added in version 0.2.4.*
4+
5+
This page documents how to use the manager and record objects
6+
for fiscal positions.
7+
8+
## Details
9+
10+
| Name | Value |
11+
|-----------------|---------------------------|
12+
| Odoo Modules | Accounting, Point of Sale |
13+
| Odoo Model Name | `account.fiscal.position` |
14+
| Manager | `fiscal_positions` |
15+
| Record Type | `FiscalPosition` |
16+
17+
## Manager
18+
19+
The customer group manager is available as the `fiscal_positions`
20+
attribute on the Odoo client object.
21+
22+
```python
23+
>>> from openstack_odooclient import Client as OdooClient
24+
>>> odoo_client = OdooClient(
25+
... hostname="localhost",
26+
... port=8069,
27+
... protocol="jsonrpc",
28+
... database="odoodb",
29+
... user="test-user",
30+
... password="<password>",
31+
... )
32+
>>> odoo_client.fiscal_positions.get(1234)
33+
FiscalPosition(record={'id': 1234, ...}, fields=None)
34+
```
35+
36+
For more information on how to use managers, refer to [Managers](index.md).
37+
38+
## Record
39+
40+
The customer group manager returns `FiscalPosition` record objects.
41+
42+
To import the record class for type hinting purposes:
43+
44+
```python
45+
from openstack_odooclient import FiscalPosition
46+
```
47+
48+
The record class currently implements the following fields and methods.
49+
50+
For more information on attributes and methods common to all record types,
51+
see [Record Attributes and Methods](index.md#attributes-and-methods).
52+
53+
54+
### `active`
55+
56+
```python
57+
active: bool
58+
```
59+
60+
Whether or not this fiscal position is active (enabled).
61+
62+
### `company_id`
63+
64+
```python
65+
company_id: Annotated[int, ModelRef("company_id", Company)]
66+
```
67+
68+
The ID for the company this fiscal position is associated with.
69+
70+
### `company_name`
71+
72+
```python
73+
company_name: Annotated[str, ModelRef("company_id", Company)]
74+
```
75+
76+
The name of the company this fiscal position is associated with.
77+
78+
### `company`
79+
80+
```python
81+
company: Annotated[Company, ModelRef("company_id", Company)]
82+
```
83+
84+
The company this fiscal position is associated with.
85+
86+
This fetches the full record from Odoo once,
87+
and caches it for subsequent accesses.
88+
89+
### `name`
90+
91+
```python
92+
name: str
93+
```
94+
95+
The name of the fiscal position.
96+
97+
Not guaranteed to be unique.
98+
99+
### `tax_ids`
100+
101+
```python
102+
tax_ids: Annotated[list[int], ModelRef("tax_ids", Tax)]
103+
```
104+
105+
The list of IDs for the taxes that will be applied
106+
to sale orders and invoices for partners using this
107+
fiscal position.
108+
109+
### `taxes`
110+
111+
```python
112+
taxes: Annotated[list[Tax], ModelRef("tax_ids", Tax)]
113+
```
114+
115+
The list of taxes that will be applied
116+
to sale orders and invoices for partners using this
117+
fiscal position.
118+
119+
This fetches the full records from Odoo once,
120+
and caches them for subsequent accesses.

docs/managers/partner.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,39 @@ if it has a parent.
307307
This fetches the full record from Odoo once,
308308
and caches it for subsequent accesses.
309309

310+
### `property_account_position_id`
311+
312+
```python
313+
property_account_position_id: int | None
314+
```
315+
316+
The ID for the [fiscal position](fiscal-position.md) this partner uses, if it uses one.
317+
318+
*Added in version 0.2.4.*
319+
320+
### `property_account_position_name`
321+
322+
```python
323+
property_account_position_name: str | None
324+
```
325+
326+
The name of the [fiscal position](fiscal-position.md) this partner uses, if it uses one.
327+
328+
*Added in version 0.2.4.*
329+
330+
### `property_account_position`
331+
332+
```python
333+
property_account_position: FiscalPosition | None
334+
```
335+
336+
The [fiscal position](fiscal-position.md) this partner uses, if it uses one.
337+
338+
This fetches the full record from Odoo once,
339+
and caches it for subsequent accesses.
340+
341+
*Added in version 0.2.4.*
342+
310343
### `property_product_pricelist_id`
311344

312345
```python

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ nav:
4141
- managers/credit-transaction.md
4242
- managers/currency.md
4343
- managers/customer-group.md
44+
- managers/fiscal-position.md
4445
- managers/grant.md
4546
- managers/grant-type.md
4647
- managers/partner.md

openstack_odooclient/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
from .managers.credit_type import CreditType, CreditTypeManager
4545
from .managers.currency import Currency, CurrencyManager
4646
from .managers.customer_group import CustomerGroup, CustomerGroupManager
47+
from .managers.fiscal_position import FiscalPosition, FiscalPositionManager
48+
from .managers.fiscal_position_tax_mapping import (
49+
FiscalPositionTaxMapping,
50+
FiscalPositionTaxMappingManager,
51+
)
4752
from .managers.grant import Grant, GrantManager
4853
from .managers.grant_type import GrantType, GrantTypeManager
4954
from .managers.partner import Partner, PartnerManager
@@ -108,6 +113,10 @@
108113
"CustomerGroup",
109114
"CustomerGroupManager",
110115
"FieldAlias",
116+
"FiscalPosition",
117+
"FiscalPositionManager",
118+
"FiscalPositionTaxMapping",
119+
"FiscalPositionTaxMappingManager",
111120
"Grant",
112121
"GrantManager",
113122
"GrantType",

openstack_odooclient/client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
from .managers.credit_type import CreditTypeManager
2626
from .managers.currency import CurrencyManager
2727
from .managers.customer_group import CustomerGroupManager
28+
from .managers.fiscal_position import FiscalPositionManager
29+
from .managers.fiscal_position_tax_mapping import (
30+
FiscalPositionTaxMappingManager,
31+
)
2832
from .managers.grant import GrantManager
2933
from .managers.grant_type import GrantTypeManager
3034
from .managers.partner import PartnerManager
@@ -112,6 +116,12 @@ class Client(ClientBase):
112116
customer_groups: CustomerGroupManager
113117
"""OpenStack customer group manager."""
114118

119+
fiscal_positions: FiscalPositionManager
120+
"""Fiscal position manager."""
121+
122+
fiscal_position_tax_mappings: FiscalPositionTaxMappingManager
123+
"""Fiscal position tax mapping manager."""
124+
115125
grants: GrantManager
116126
"""OpenStack grant manager."""
117127

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (C) 2026 Catalyst Cloud Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from __future__ import annotations
17+
18+
from typing import Annotated
19+
20+
from ..base.record.base import RecordBase
21+
from ..base.record.types import ModelRef
22+
from ..base.record_manager.base import RecordManagerBase
23+
24+
25+
class FiscalPosition(RecordBase["FiscalPositionManager"]):
26+
active: bool
27+
"""Whether or not this fiscal position is active (enabled)."""
28+
29+
company_id: Annotated[int, ModelRef("company_id", Company)]
30+
"""The ID for the company this fiscal position is associated with."""
31+
32+
company_name: Annotated[str, ModelRef("company_id", Company)]
33+
"""The name of the company this fiscal position is associated with."""
34+
35+
company: Annotated[Company, ModelRef("company_id", Company)]
36+
"""The company this fiscal position is associated with.
37+
38+
This fetches the full record from Odoo once,
39+
and caches it for subsequent accesses.
40+
"""
41+
42+
name: str
43+
"""The name of the fiscal position.
44+
45+
Not guaranteed to be unique.
46+
"""
47+
48+
tax_ids: Annotated[
49+
list[int],
50+
ModelRef("tax_ids", FiscalPositionTaxMapping),
51+
]
52+
"""The list of IDs for the tax mappings that will be applied to
53+
sale orders and invoices for partners using this fiscal position.
54+
"""
55+
56+
taxes: Annotated[
57+
list[FiscalPositionTaxMapping],
58+
ModelRef("tax_ids", FiscalPositionTaxMapping),
59+
]
60+
"""The list of tax mappings that will be applied to
61+
sale orders and invoices for partners using this fiscal position.
62+
63+
This fetches the full records from Odoo once,
64+
and caches them for subsequent accesses.
65+
"""
66+
67+
68+
class FiscalPositionManager(RecordManagerBase[FiscalPosition]):
69+
env_name = "account.fiscal.position"
70+
record_class = FiscalPosition
71+
72+
73+
# NOTE(callumdickinson): Import here to make sure circular imports work.
74+
from .company import Company # noqa: E402
75+
from .fiscal_position_tax_mapping import FiscalPositionTaxMapping # noqa: E402
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright (C) 2026 Catalyst Cloud Limited
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from __future__ import annotations
17+
18+
from typing import Annotated
19+
20+
from ..base.record.base import RecordBase
21+
from ..base.record.types import ModelRef
22+
from ..base.record_manager.base import RecordManagerBase
23+
24+
25+
class FiscalPositionTaxMapping(RecordBase["FiscalPositionTaxMappingManager"]):
26+
company_id: Annotated[int, ModelRef("company_id", Company)]
27+
"""The ID for the company this fiscal position tax mapping
28+
is associated with.
29+
"""
30+
31+
company_name: Annotated[str, ModelRef("company_id", Company)]
32+
"""The name of the company this fiscal position tax mapping
33+
is associated with.
34+
"""
35+
36+
company: Annotated[Company, ModelRef("company_id", Company)]
37+
"""The company this fiscal position tax mapping
38+
is associated with.
39+
40+
This fetches the full record from Odoo once,
41+
and caches it for subsequent accesses.
42+
"""
43+
44+
position_id: Annotated[int, ModelRef("position_id", FiscalPosition)]
45+
"""The ID for the fiscal position this mapping is part of."""
46+
47+
position_name: Annotated[str, ModelRef("position_id", FiscalPosition)]
48+
"""The name of the fiscal position this mapping is part of."""
49+
50+
position: Annotated[
51+
FiscalPosition,
52+
ModelRef("position_id", FiscalPosition),
53+
]
54+
"""The fiscal position this mapping is part of.
55+
56+
This fetches the full record from Odoo once,
57+
and caches it for subsequent accesses.
58+
"""
59+
60+
tax_src_id: Annotated[int, ModelRef("tax_src_id", Tax)]
61+
"""The ID of the tax to be overridden on products."""
62+
63+
tax_src_name: Annotated[str, ModelRef("tax_src_id", Tax)]
64+
"""The name of the tax to be overridden on products."""
65+
66+
tax_src: Annotated[Tax, ModelRef("tax_src_id", Tax)]
67+
"""The tax to be overridden on products.
68+
69+
This fetches the full records from Odoo once,
70+
and caches them for subsequent accesses.
71+
"""
72+
73+
tax_dest_id: Annotated[int | None, ModelRef("tax_dest_id", Tax)]
74+
"""The ID of the tax to be overridden on products."""
75+
76+
tax_dest_name: Annotated[str | None, ModelRef("tax_dest_id", Tax)]
77+
"""The name of the tax to be overridden on products."""
78+
79+
tax_dest: Annotated[Tax | None, ModelRef("tax_dest_id", Tax)]
80+
"""The tax to be overridden on products, if set.
81+
82+
This fetches the full records from Odoo once,
83+
and caches them for subsequent accesses.
84+
"""
85+
86+
87+
class FiscalPositionTaxMappingManager(
88+
RecordManagerBase[FiscalPositionTaxMapping],
89+
):
90+
env_name = "account.fiscal.position.tax"
91+
record_class = FiscalPositionTaxMapping
92+
93+
94+
# NOTE(callumdickinson): Import here to make sure circular imports work.
95+
from .company import Company # noqa: E402
96+
from .fiscal_position import FiscalPosition # noqa: E402
97+
from .tax import Tax # noqa: E402

0 commit comments

Comments
 (0)