cacholong-cloud-cli 0.3.0__py3-none-any.whl

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.
Files changed (39) hide show
  1. cacholong_cli/AsyncTyper.py +17 -0
  2. cacholong_cli/__init__.py +0 -0
  3. cacholong_cli/cli.py +110 -0
  4. cacholong_cli/commands/accounts.py +105 -0
  5. cacholong_cli/commands/addresses.py +280 -0
  6. cacholong_cli/commands/companies.py +100 -0
  7. cacholong_cli/commands/dns_records.py +275 -0
  8. cacholong_cli/commands/dns_templates.py +141 -0
  9. cacholong_cli/commands/dns_zones.py +277 -0
  10. cacholong_cli/commands/products.py +121 -0
  11. cacholong_cli/commands/purchases.py +127 -0
  12. cacholong_cli/common.py +179 -0
  13. cacholong_cli/connection.py +18 -0
  14. cacholong_cloud_cli-0.3.0.dist-info/METADATA +115 -0
  15. cacholong_cloud_cli-0.3.0.dist-info/RECORD +39 -0
  16. cacholong_cloud_cli-0.3.0.dist-info/WHEEL +4 -0
  17. cacholong_cloud_cli-0.3.0.dist-info/entry_points.txt +3 -0
  18. cacholong_sdk/__init__.py +18 -0
  19. cacholong_sdk/account.py +14 -0
  20. cacholong_sdk/address.py +14 -0
  21. cacholong_sdk/api_schema.py +124 -0
  22. cacholong_sdk/common.py +119 -0
  23. cacholong_sdk/company.py +14 -0
  24. cacholong_sdk/connection.py +22 -0
  25. cacholong_sdk/dns_record.py +14 -0
  26. cacholong_sdk/dns_template.py +14 -0
  27. cacholong_sdk/dns_zone.py +14 -0
  28. cacholong_sdk/exception.py +7 -0
  29. cacholong_sdk/product.py +14 -0
  30. cacholong_sdk/purchase.py +14 -0
  31. jsonapi_client/__init__.py +42 -0
  32. jsonapi_client/common.py +186 -0
  33. jsonapi_client/document.py +161 -0
  34. jsonapi_client/exceptions.py +62 -0
  35. jsonapi_client/filter.py +155 -0
  36. jsonapi_client/objects.py +187 -0
  37. jsonapi_client/relationships.py +447 -0
  38. jsonapi_client/resourceobject.py +656 -0
  39. jsonapi_client/session.py +755 -0
@@ -0,0 +1,17 @@
1
+ from asyncio import run
2
+ from functools import wraps
3
+
4
+ import typer
5
+
6
+
7
+ class AsyncTyper(typer.Typer):
8
+ def async_command(self, *args, **kwargs):
9
+ def decorator(async_func):
10
+ @wraps(async_func)
11
+ def sync_func(*_args, **_kwargs):
12
+ return run(async_func(*_args, **_kwargs))
13
+
14
+ self.command(*args, **kwargs)(sync_func)
15
+ return async_func
16
+
17
+ return decorator
File without changes
cacholong_cli/cli.py ADDED
@@ -0,0 +1,110 @@
1
+ import importlib.metadata
2
+
3
+ import os
4
+ import sys
5
+ import typer
6
+ from typing import Optional
7
+ from cacholong_cli.commands import (
8
+ accounts,
9
+ addresses,
10
+ companies,
11
+ dns_records,
12
+ dns_templates,
13
+ dns_zones,
14
+ products,
15
+ purchases,
16
+ )
17
+ from cacholong_cli.common import OutputFormat
18
+ from xdg import BaseDirectory
19
+
20
+
21
+ # Version of our CLI
22
+ __version__ = importlib.metadata.version("cacholong-cloud-cli")
23
+
24
+ # Check if required config.ini file exists
25
+ configpath = BaseDirectory.save_config_path("cacholong-cli")
26
+ if not os.path.exists(os.path.join(configpath, "config.ini")):
27
+ print("Get a token through our panel at https://cp.cacholong.eu/")
28
+ token = input("API Token: ")
29
+ if len(token) == 0:
30
+ print("Invalid token")
31
+ sys.exit(1)
32
+ with open(os.path.join(configpath, "config.ini"), "w") as f:
33
+ f.write("[DEFAULT]\n")
34
+ f.write("api_url = 'https://api.cacholong.eu/api/v1/'\n")
35
+ f.write("api_key = '" + token + "'\n")
36
+
37
+ # Generate the available commands
38
+ app = typer.Typer()
39
+ app.add_typer(accounts.app, name="accounts", help="Manage accounts")
40
+ app.add_typer(
41
+ addresses.app, name="addresses", help="Manage addresses for users and companies"
42
+ )
43
+ app.add_typer(companies.app, name="companies", help="Manage companies")
44
+ app.add_typer(dns_records.app, name="dns-records", help="Manage DNS records")
45
+ app.add_typer(dns_templates.app, name="dns-templates", help="Manage DNS templates")
46
+ app.add_typer(dns_zones.app, name="dns-zones", help="Manage DNS zones")
47
+ app.add_typer(products.app, name="products", help="Manage products")
48
+ app.add_typer(purchases.app, name="purchases", help="Manage purchases")
49
+
50
+
51
+ # Handle version
52
+ def _version_callback(value: bool) -> None:
53
+ if value:
54
+ typer.echo(f"cacholong cli version: {__version__}")
55
+ raise typer.Exit()
56
+
57
+
58
+ def _verbose_callback(ctx: typer.Context, value: bool) -> None:
59
+ ctx.obj["verbose"] = False
60
+ if value:
61
+ ctx.obj["verbose"] = True
62
+
63
+
64
+ def _output_callback(ctx: typer.Context, value: OutputFormat) -> None:
65
+ ctx.obj["output"] = value
66
+
67
+
68
+ def _create_issue_callback(ctx: typer.Context, value: bool) -> None:
69
+ ctx.obj["create_issue"] = value
70
+
71
+
72
+ def _sync_callback(ctx: typer.Context, value: bool) -> None:
73
+ ctx.obj["sync"] = value
74
+
75
+
76
+ def _sort_callback(ctx: typer.Context, value: str) -> None:
77
+ ctx.obj["sort"] = value
78
+
79
+
80
+ @app.callback(context_settings={"obj": {}})
81
+ def main(
82
+ ctx: typer.Context,
83
+ version: Optional[bool] = typer.Option(
84
+ None,
85
+ "--version",
86
+ help="Show the application's version and exit.",
87
+ callback=_version_callback,
88
+ is_eager=True,
89
+ ),
90
+ verbose: Optional[bool] = typer.Option(
91
+ None, "--verbose", help="Verbose output", callback=_verbose_callback
92
+ ),
93
+ sort: Optional[str] = typer.Option(
94
+ "-created_at", "--sort", help="Field to sort on", callback=_sort_callback
95
+ ),
96
+ create_issue: bool = typer.Option(
97
+ False,
98
+ "--create-issue",
99
+ help="Create an issue in gitlab",
100
+ callback=_create_issue_callback,
101
+ ),
102
+ sync: bool = typer.Option(
103
+ False, "--sync", help="Process action directly", callback=_sync_callback
104
+ ),
105
+ output: OutputFormat = typer.Option(
106
+ "table", "--output", help="Output format", callback=_output_callback
107
+ ),
108
+ ) -> None:
109
+
110
+ return
@@ -0,0 +1,105 @@
1
+ import asyncio
2
+ import typer
3
+ from typing import List, Optional
4
+ from typing_extensions import Annotated
5
+ from rich.table import Column
6
+ from uuid import UUID
7
+ from cacholong_cli.AsyncTyper import AsyncTyper
8
+ from cacholong_cli.common import (
9
+ list_resources,
10
+ list_relation_resources,
11
+ show_resource,
12
+ print_document_error,
13
+ )
14
+ from cacholong_cli.connection import Connection
15
+ from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
16
+ from cacholong_sdk import Account, AccountModel
17
+
18
+ # Create typer object
19
+ app = AsyncTyper()
20
+
21
+
22
+ @app.async_command()
23
+ async def list(
24
+ ctx: typer.Context,
25
+ name: Annotated[
26
+ Optional[str],
27
+ typer.Option(
28
+ help="Must be unique. Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote, numbers 0 to 9, space or the following symbols: @ & + - ( ) ? ! * # /"
29
+ ),
30
+ ] = None,
31
+ display_name: Annotated[Optional[str], typer.Option(help="")] = None,
32
+ description: Annotated[Optional[str], typer.Option(help="")] = None,
33
+ created_at: Annotated[Optional[str], typer.Option(help="")] = None,
34
+ updated_at: Annotated[Optional[str], typer.Option(help="")] = None,
35
+ account_type: Annotated[
36
+ Optional[str], typer.Option(help="Only available for certain users.")
37
+ ] = None,
38
+ account_account_id: Annotated[
39
+ Optional[str],
40
+ typer.Option(
41
+ help="Only available for certain users. When used, account_account_relation is mandatory."
42
+ ),
43
+ ] = None,
44
+ account_account_relation: Annotated[
45
+ Optional[str],
46
+ typer.Option(
47
+ help="Only available for certain users. When used, account_account_id is mandatory."
48
+ ),
49
+ ] = None,
50
+ company: Annotated[Optional[UUID], typer.Option(help="")] = None,
51
+ ):
52
+ # Build modifier
53
+ modifier = []
54
+ if name is not None:
55
+ modifier.append(Filter(name=name))
56
+ if display_name is not None:
57
+ modifier.append(Filter(query_str="filter[display_name]=" + str(display_name)))
58
+ if description is not None:
59
+ modifier.append(Filter(description=description))
60
+ if created_at is not None:
61
+ modifier.append(Filter(query_str="filter[created_at]=" + str(created_at)))
62
+ if updated_at is not None:
63
+ modifier.append(Filter(query_str="filter[updated_at]=" + str(updated_at)))
64
+ if account_type is not None:
65
+ modifier.append(Filter(query_str="filter[account_type]=" + str(account_type)))
66
+ if account_account_id is not None:
67
+ modifier.append(
68
+ Filter(query_str="filter[account_account_id]=" + str(account_account_id))
69
+ )
70
+ if account_account_relation is not None:
71
+ modifier.append(
72
+ Filter(
73
+ query_str="filter[account_account_relation]="
74
+ + str(account_account_relation)
75
+ )
76
+ )
77
+ if company is not None:
78
+ modifier.append(Filter(company=str(company)))
79
+
80
+ # Table definition
81
+ tabledef = [
82
+ {"header": Column("Id", no_wrap=True), "column": "id"},
83
+ {"header": "Name", "column": "name"},
84
+ {"header": "Display name", "column": "display_name"},
85
+ {"header": "Created", "column": "created_at"},
86
+ {"header": "Updated", "column": "updated_at"},
87
+ ]
88
+ async with Connection() as conn:
89
+ await list_resources(ctx, Account(conn), tabledef, modifier)
90
+
91
+
92
+ @app.async_command()
93
+ async def show(
94
+ ctx: typer.Context,
95
+ account_id: Annotated[UUID, typer.Argument()],
96
+ ):
97
+ # Show resource
98
+ try:
99
+ async with Connection() as conn:
100
+ ctrl = Account(conn)
101
+ model = await ctrl.fetch(account_id)
102
+
103
+ show_resource(ctx, model)
104
+ except DocumentError as e:
105
+ await print_document_error(e)
@@ -0,0 +1,280 @@
1
+ import asyncio
2
+ import typer
3
+ from typing import List, Optional
4
+ from typing_extensions import Annotated
5
+ from rich.table import Column
6
+ from uuid import UUID
7
+ from cacholong_cli.AsyncTyper import AsyncTyper
8
+ from cacholong_cli.common import (
9
+ list_resources,
10
+ list_relation_resources,
11
+ show_resource,
12
+ print_document_error,
13
+ )
14
+ from cacholong_cli.connection import Connection
15
+ from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
16
+ from cacholong_sdk import Address, AddressModel
17
+
18
+ # Create typer object
19
+ app = AsyncTyper()
20
+
21
+
22
+ @app.async_command()
23
+ async def list(
24
+ ctx: typer.Context,
25
+ street: Annotated[
26
+ Optional[str],
27
+ typer.Option(
28
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
29
+ ),
30
+ ] = None,
31
+ number: Annotated[
32
+ Optional[str], typer.Option(help="Can contain any number from any language.")
33
+ ] = None,
34
+ suffix: Annotated[
35
+ Optional[str],
36
+ typer.Option(
37
+ help="Can contain any letter or number from any language or space."
38
+ ),
39
+ ] = None,
40
+ zipcode: Annotated[
41
+ Optional[str],
42
+ typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US."),
43
+ ] = None,
44
+ city: Annotated[
45
+ Optional[str],
46
+ typer.Option(help="Can contain any letter from any language or space."),
47
+ ] = None,
48
+ state: Annotated[
49
+ Optional[str],
50
+ typer.Option(
51
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
52
+ ),
53
+ ] = None,
54
+ country: Annotated[
55
+ Optional[str], typer.Option(help="Must contain two uppercase letters (A-Z).")
56
+ ] = None,
57
+ user: Annotated[
58
+ Optional[UUID],
59
+ typer.Option(
60
+ help="Existing user. Required unless company is given. Readonly on update."
61
+ ),
62
+ ] = None,
63
+ company: Annotated[
64
+ Optional[UUID],
65
+ typer.Option(
66
+ help="Existing company. Required unless user is given. Readonly on update."
67
+ ),
68
+ ] = None,
69
+ ):
70
+ # Build modifier
71
+ modifier = []
72
+ if street is not None:
73
+ modifier.append(Filter(street=street))
74
+ if number is not None:
75
+ modifier.append(Filter(number=number))
76
+ if suffix is not None:
77
+ modifier.append(Filter(suffix=suffix))
78
+ if zipcode is not None:
79
+ modifier.append(Filter(zipcode=zipcode))
80
+ if city is not None:
81
+ modifier.append(Filter(city=city))
82
+ if state is not None:
83
+ modifier.append(Filter(state=state))
84
+ if country is not None:
85
+ modifier.append(Filter(country=country))
86
+ if user is not None:
87
+ modifier.append(Filter(user=str(user)))
88
+ if company is not None:
89
+ modifier.append(Filter(company=str(company)))
90
+ modifier.append(Inclusion("company"))
91
+ modifier.append(Inclusion("user"))
92
+
93
+ # Table definition
94
+ tabledef = [
95
+ {"header": Column("Id", no_wrap=True), "column": "id"},
96
+ {"header": "Company", "column": "company", "nested_column": "name"},
97
+ {"header": "User", "column": "user", "nested_column": "name"},
98
+ {"header": "Street", "column": "street"},
99
+ {"header": "Number", "column": "number"},
100
+ {"header": "City", "column": "city"},
101
+ {"header": "Created", "column": "created_at"},
102
+ {"header": "Updated", "column": "updated_at"},
103
+ ]
104
+ async with Connection() as conn:
105
+ await list_resources(ctx, Address(conn), tabledef, modifier)
106
+
107
+
108
+ @app.async_command()
109
+ async def show(
110
+ ctx: typer.Context,
111
+ address_id: Annotated[UUID, typer.Argument()],
112
+ ):
113
+ # Show resource
114
+ try:
115
+ async with Connection() as conn:
116
+ ctrl = Address(conn)
117
+ model = await ctrl.fetch(address_id)
118
+
119
+ show_resource(ctx, model)
120
+ except DocumentError as e:
121
+ await print_document_error(e)
122
+
123
+
124
+ @app.async_command()
125
+ async def create(
126
+ ctx: typer.Context,
127
+ street: Annotated[
128
+ str,
129
+ typer.Option(
130
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
131
+ ),
132
+ ],
133
+ number: Annotated[
134
+ str, typer.Option(help="Can contain any number from any language.")
135
+ ],
136
+ zipcode: Annotated[
137
+ str, typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US.")
138
+ ],
139
+ city: Annotated[
140
+ str, typer.Option(help="Can contain any letter from any language or space.")
141
+ ],
142
+ country: Annotated[
143
+ str, typer.Option(help="Must contain two uppercase letters (A-Z).")
144
+ ],
145
+ suffix: Annotated[
146
+ Optional[str],
147
+ typer.Option(
148
+ help="Can contain any letter or number from any language or space."
149
+ ),
150
+ ] = None,
151
+ state: Annotated[
152
+ Optional[str],
153
+ typer.Option(
154
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
155
+ ),
156
+ ] = None,
157
+ user: Annotated[
158
+ Optional[UUID],
159
+ typer.Option(
160
+ help="Existing user. Required unless company is given. Readonly on update."
161
+ ),
162
+ ] = None,
163
+ company: Annotated[
164
+ Optional[UUID],
165
+ typer.Option(
166
+ help="Existing company. Required unless user is given. Readonly on update."
167
+ ),
168
+ ] = None,
169
+ ):
170
+ try:
171
+ async with Connection() as conn:
172
+ ctrl = Address(conn)
173
+ model = ctrl.create()
174
+ model["street"] = street
175
+ model["number"] = number
176
+ if suffix is not None:
177
+ model["suffix"] = suffix
178
+ model["zipcode"] = zipcode
179
+ model["city"] = city
180
+ if state is not None:
181
+ model["state"] = state
182
+ model["country"] = country
183
+ if user is not None:
184
+ model["user"] = ResourceTuple(user, "users")
185
+ if company is not None:
186
+ model["company"] = ResourceTuple(company, "companies")
187
+ await ctrl.store(model, ctx.obj["create_issue"])
188
+
189
+ show_resource(ctx, model)
190
+ except DocumentError as e:
191
+ await print_document_error(e)
192
+
193
+
194
+ @app.async_command()
195
+ async def update(
196
+ ctx: typer.Context,
197
+ address_id: Annotated[UUID, typer.Argument()],
198
+ street: Annotated[
199
+ Optional[str],
200
+ typer.Option(
201
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
202
+ ),
203
+ ] = None,
204
+ number: Annotated[
205
+ Optional[str], typer.Option(help="Can contain any number from any language.")
206
+ ] = None,
207
+ suffix: Annotated[
208
+ Optional[str],
209
+ typer.Option(
210
+ help="Can contain any letter or number from any language or space."
211
+ ),
212
+ ] = None,
213
+ zipcode: Annotated[
214
+ Optional[str],
215
+ typer.Option(help="Must contain valid zipcode from NL,BE,DE,GB or US."),
216
+ ] = None,
217
+ city: Annotated[
218
+ Optional[str],
219
+ typer.Option(help="Can contain any letter from any language or space."),
220
+ ] = None,
221
+ state: Annotated[
222
+ Optional[str],
223
+ typer.Option(
224
+ help="Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, single or alternative quote or space."
225
+ ),
226
+ ] = None,
227
+ country: Annotated[
228
+ Optional[str], typer.Option(help="Must contain two uppercase letters (A-Z).")
229
+ ] = None,
230
+ user: Annotated[
231
+ Optional[UUID],
232
+ typer.Option(
233
+ help="Existing user. Required unless company is given. Readonly on update."
234
+ ),
235
+ ] = None,
236
+ company: Annotated[
237
+ Optional[UUID],
238
+ typer.Option(
239
+ help="Existing company. Required unless user is given. Readonly on update."
240
+ ),
241
+ ] = None,
242
+ ):
243
+ try:
244
+ async with Connection() as conn:
245
+ ctrl = Address(conn)
246
+ model = await ctrl.fetch(address_id)
247
+ if street is not None:
248
+ model["street"] = street
249
+ if number is not None:
250
+ model["number"] = number
251
+ if suffix is not None:
252
+ model["suffix"] = suffix
253
+ if zipcode is not None:
254
+ model["zipcode"] = zipcode
255
+ if city is not None:
256
+ model["city"] = city
257
+ if state is not None:
258
+ model["state"] = state
259
+ if country is not None:
260
+ model["country"] = country
261
+ if user is not None:
262
+ model["user"].set(user, "users")
263
+ if company is not None:
264
+ model["company"].set(company, "companies")
265
+ except DocumentError as e:
266
+ await print_document_error(e)
267
+
268
+
269
+ @app.async_command()
270
+ async def delete(
271
+ ctx: typer.Context,
272
+ address_id: Annotated[List[UUID], typer.Argument()],
273
+ ):
274
+ try:
275
+ async with Connection() as conn, asyncio.TaskGroup() as tg:
276
+ ctrl = Address(conn)
277
+ for resource_id in address_id:
278
+ tg.create_task(ctrl.destroy(resource_id))
279
+ except DocumentError as e:
280
+ await print_document_error(e)
@@ -0,0 +1,100 @@
1
+ import asyncio
2
+ import typer
3
+ from typing import List, Optional
4
+ from typing_extensions import Annotated
5
+ from rich.table import Column
6
+ from uuid import UUID
7
+ from cacholong_cli.AsyncTyper import AsyncTyper
8
+ from cacholong_cli.common import (
9
+ list_resources,
10
+ list_relation_resources,
11
+ show_resource,
12
+ print_document_error,
13
+ )
14
+ from cacholong_cli.connection import Connection
15
+ from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
16
+ from cacholong_sdk import Company, CompanyModel
17
+
18
+ # Create typer object
19
+ app = AsyncTyper()
20
+
21
+
22
+ @app.async_command()
23
+ async def show(
24
+ ctx: typer.Context,
25
+ company_id: Annotated[UUID, typer.Argument()],
26
+ ):
27
+ # Show resource
28
+ try:
29
+ async with Connection() as conn:
30
+ ctrl = Company(conn)
31
+ model = await ctrl.fetch(company_id)
32
+
33
+ show_resource(ctx, model)
34
+ except DocumentError as e:
35
+ await print_document_error(e)
36
+
37
+
38
+ @app.async_command()
39
+ async def update(
40
+ ctx: typer.Context,
41
+ company_id: Annotated[UUID, typer.Argument()],
42
+ name: Annotated[
43
+ Optional[str],
44
+ typer.Option(
45
+ help="Must be unique. Can contain any letter (combined with accent) from any language, any kind of hyphen or dash, numbers 0 to 9, space, point or the folowing symbols: @ & + - ( ) ? ! * # /"
46
+ ),
47
+ ] = None,
48
+ kvknr: Annotated[Optional[str], typer.Option(help="")] = None,
49
+ phone: Annotated[
50
+ Optional[str],
51
+ typer.Option(help="Can contain valid phonenumber from NL,BE,DE,GB or US."),
52
+ ] = None,
53
+ email: Annotated[
54
+ Optional[str],
55
+ typer.Option(
56
+ help="Email will be validated and DNS records checked to make sure server accepts emails."
57
+ ),
58
+ ] = None,
59
+ email_invoice: Annotated[
60
+ Optional[str],
61
+ typer.Option(
62
+ help="Email for invoicing, defaults to email if not given. Email will be validated and DNS records checked to make sure server accepts emails."
63
+ ),
64
+ ] = None,
65
+ vat_number: Annotated[
66
+ Optional[str],
67
+ typer.Option(
68
+ help="VAT number, must be valid. If not given, it will be set to null. If given, it will be validated."
69
+ ),
70
+ ] = None,
71
+ account: Annotated[
72
+ Optional[UUID],
73
+ typer.Option(help="Existing account. Must be unique. Readonly on update."),
74
+ ] = None,
75
+ addresses: Annotated[
76
+ Optional[List[UUID]], typer.Option(help="Existing addresses. Readonly.")
77
+ ] = None,
78
+ ):
79
+ try:
80
+ async with Connection() as conn:
81
+ ctrl = Company(conn)
82
+ model = await ctrl.fetch(company_id)
83
+ if name is not None:
84
+ model["name"] = name
85
+ if kvknr is not None:
86
+ model["kvknr"] = kvknr
87
+ if phone is not None:
88
+ model["phone"] = phone
89
+ if email is not None:
90
+ model["email"] = email
91
+ if email_invoice is not None:
92
+ model["email_invoice"] = email_invoice
93
+ if vat_number is not None:
94
+ model["vat_number"] = vat_number
95
+ if account is not None:
96
+ model["account"].set(account, "accounts")
97
+ if addresses is not None:
98
+ model["addresses"].set(addresses, "addresses")
99
+ except DocumentError as e:
100
+ await print_document_error(e)