shop_system_models 1.0.0.dev26932__py3-none-any.whl → 1.0.0.dev27183__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 (28) hide show
  1. shop_system_models/consts/languages.py +4 -0
  2. shop_system_models/consts/languages.pyi +4 -0
  3. shop_system_models/deployment_api/request/authorization.py +5 -0
  4. shop_system_models/deployment_api/request/processes.py +1 -0
  5. shop_system_models/deployment_api/request/services.py +36 -0
  6. shop_system_models/deployment_api/request/shop_categories.py +9 -0
  7. shop_system_models/deployment_api/request/shop_content/blocks.py +21 -0
  8. shop_system_models/deployment_api/request/shop_content/delivery_types.py +51 -0
  9. shop_system_models/deployment_api/request/shop_content/payment_methods.py +32 -0
  10. shop_system_models/deployment_api/request/shop_templates.py +18 -0
  11. shop_system_models/deployment_api/request/shops.py +102 -0
  12. shop_system_models/deployment_api/request/tasks.py +24 -0
  13. shop_system_models/deployment_api/request/users.py +53 -0
  14. shop_system_models/deployment_api/request/web_app_url.py +14 -0
  15. shop_system_models/deployment_api/response/general.py +23 -0
  16. shop_system_models/deployment_api/response/permissions.py +6 -0
  17. shop_system_models/deployment_api/response/premium.py +15 -0
  18. shop_system_models/deployment_api/response/shops.py +51 -0
  19. shop_system_models/deployment_api/response/simple_responses.py +61 -0
  20. shop_system_models/deployment_api/response/web_app_url.py +5 -0
  21. shop_system_models/deployment_api/shared.pyi +34 -0
  22. shop_system_models/deployment_api/users.pyi +37 -0
  23. shop_system_models/shop_api/shop/request/details.py +10 -0
  24. shop_system_models/shop_api/shop/request/orders.py +84 -62
  25. {shop_system_models-1.0.0.dev26932.dist-info → shop_system_models-1.0.0.dev27183.dist-info}/METADATA +1 -1
  26. {shop_system_models-1.0.0.dev26932.dist-info → shop_system_models-1.0.0.dev27183.dist-info}/RECORD +28 -9
  27. /shop_system_models/deployment_api/{request/servers.py → __init__.pyi} +0 -0
  28. {shop_system_models-1.0.0.dev26932.dist-info → shop_system_models-1.0.0.dev27183.dist-info}/WHEEL +0 -0
@@ -0,0 +1,4 @@
1
+ TG_LANGUAGES_MAPPING = {'ru': 'RU',
2
+ 'en': 'EN'}
3
+
4
+ LANGUAGES = {value: key for key, value in TG_LANGUAGES_MAPPING.items()} # reverse TG_LANGUAGES
@@ -0,0 +1,4 @@
1
+ from _typeshed import Incomplete
2
+
3
+ TG_LANGUAGES_MAPPING: Incomplete
4
+ LANGUAGES: Incomplete
@@ -1 +1,6 @@
1
+ from shop_system_models.deployment_api.request.users import User
2
+
3
+
4
+ class Token(User):
5
+ initData: str
1
6
 
@@ -12,3 +12,4 @@ class DeployVariables(BaseModel):
12
12
  contact_phone: Optional[str]
13
13
  bot_token: Optional[str]
14
14
  invite_user: bool = True
15
+
@@ -0,0 +1,36 @@
1
+ from typing import Optional
2
+
3
+ from shop_system_models.consts.enums import ServiceNames
4
+ from pydantic import BaseModel, computed_field
5
+
6
+
7
+ class ServiceConfig(BaseModel):
8
+ name: ServiceNames
9
+ version: Optional[str] = 'latest'
10
+
11
+ class Config:
12
+ use_enum_values = True
13
+
14
+
15
+ class ProjectConfiguration(BaseModel):
16
+ shop_name: str
17
+
18
+ # Константы для URL — будут задаваться в рантайме
19
+ SHOP_BOT_URL: str = ''
20
+ SHOP_API_URL: str = ''
21
+ SHOP_APP_URL: str = ''
22
+
23
+ @computed_field # type: ignore
24
+ @property
25
+ def shop_bot_url(self) -> str:
26
+ return f"{self.SHOP_BOT_URL}/{self.shop_name}"
27
+
28
+ @computed_field # type: ignore
29
+ @property
30
+ def shop_api_url(self) -> str:
31
+ return f"{self.SHOP_API_URL}/{self.shop_name}"
32
+
33
+ @computed_field # type: ignore
34
+ @property
35
+ def shop_url(self) -> str:
36
+ return f"{self.SHOP_APP_URL}/{self.shop_name}"
@@ -0,0 +1,9 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class ShopCategory(BaseModel):
7
+ name: str
8
+ description: Optional[str] = None
9
+ preview_url: Optional[str] = None
@@ -0,0 +1,21 @@
1
+ from typing import Optional
2
+
3
+ from fastapi import HTTPException
4
+ from pydantic import BaseModel, field_validator
5
+
6
+
7
+ def link_validation(link: str) -> str:
8
+ if not link.startswith('http://') and not link.startswith('https://'):
9
+ raise HTTPException(status_code=400, detail=f'Invalid link: {link}')
10
+ return link
11
+
12
+
13
+ class LinkBlocks(BaseModel):
14
+ contacts: Optional[str] = None
15
+ info: Optional[str] = None
16
+
17
+ @field_validator('contacts', 'info')
18
+ def link_validation(cls, value: str) -> str:
19
+ if value:
20
+ return link_validation(link=value)
21
+ return value
@@ -0,0 +1,51 @@
1
+ from typing import List, Optional
2
+
3
+ from fastapi import HTTPException
4
+ from pydantic import BaseModel, field_validator
5
+
6
+
7
+ class Coordinates(BaseModel):
8
+ latitude: float
9
+ longitude: float
10
+
11
+
12
+ class ExtraField(BaseModel):
13
+ name: str
14
+ description: str
15
+ is_required: bool
16
+
17
+
18
+ # class ExtraFieldPayload(BaseModel):
19
+ # name: str
20
+ # value: str
21
+
22
+
23
+ class DeliveryType(BaseModel):
24
+ name: str
25
+ amount: float = 0.0
26
+ is_address_required: bool = False
27
+ address_hint: Optional[str] = ''
28
+ extra_fields: List[ExtraField] = []
29
+ is_timepicker_required: bool = False
30
+ details: str = ''
31
+ country: Optional[str] = ''
32
+ country_code: Optional[str] = '' # ISO format, ex.: RU, KZ, BY...
33
+ city: Optional[str] = None
34
+ delivery_location: Optional[Coordinates] = None
35
+ delivery_radius: Optional[int] = None
36
+ delivery_min_hour: Optional[int] = None
37
+ delivery_max_hour: Optional[int] = None
38
+ delivery_minutes_interval: Optional[int] = None
39
+ delivery_min_day: Optional[int] = None
40
+ delivery_max_day: Optional[int] = None
41
+
42
+ @field_validator('name')
43
+ def name_validation(cls, name):
44
+ name = name.strip()
45
+ if len(name) <= 2:
46
+ raise HTTPException(status_code=400, detail=f'Invalid delivery name: {name}')
47
+ return name
48
+
49
+
50
+ class DeliveryTypeResponse(DeliveryType):
51
+ id: str
@@ -0,0 +1,32 @@
1
+ from enum import Enum
2
+ from typing import List, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class PaymentTypes(str, Enum):
8
+ manual_payment_request = 'ManualPaymentRequest'
9
+ external_card_payment_provider = 'ExternalCardPaymentProvider'
10
+ crypto_ton = 'CryptoTON'
11
+ xtr = 'XTR'
12
+ life_pay = 'LifePay'
13
+ yookassa = "yookassa"
14
+ tkassa = "tkassa"
15
+
16
+ class Metadata(BaseModel):
17
+ key: str
18
+ value: List[str]
19
+
20
+
21
+ class PaymentMethod(BaseModel):
22
+ name: str
23
+ type: PaymentTypes
24
+ payment_data: str # payment_token, TON address etc....
25
+ meta: Optional[List[Metadata]] = []
26
+
27
+ class Config:
28
+ use_enum_values = True
29
+
30
+
31
+ class PaymentMethodResponse(PaymentMethod):
32
+ id: str
@@ -0,0 +1,18 @@
1
+ from typing import Optional
2
+
3
+ from fastapi import HTTPException
4
+ from pydantic import BaseModel, field_validator
5
+
6
+
7
+ class ShopTemplate(BaseModel):
8
+ template_id: str
9
+ name: str
10
+ description: Optional[str] = ''
11
+ bot_url: str
12
+ language: str
13
+
14
+ @field_validator('bot_url')
15
+ def url_validation(cls, bot_url):
16
+ if bot_url.startswith('http://') or bot_url.startswith('https://'):
17
+ return bot_url
18
+ raise HTTPException(status_code=400, detail=f'Invalid bot_url: {bot_url}')
@@ -0,0 +1,102 @@
1
+ import re
2
+ from datetime import datetime
3
+ from typing import Any, List, Optional, Union
4
+
5
+ from pydantic import BaseModel, ValidationError, computed_field, model_validator, Field
6
+ from transliterate import translit # type: ignore
7
+
8
+ from shop_system_models.consts.enums import ShopStatuses
9
+ from shop_system_models.deployment_api.request.nocodb import NocoDBConfig
10
+ from shop_system_models.deployment_api.request.services import ProjectConfiguration
11
+ from shop_system_models.deployment_api.request.tasks import Task
12
+ from shop_system_models.deployment_api.response.shops import ShopCategoryResponse
13
+
14
+
15
+ class Location(BaseModel):
16
+ latitude: float
17
+ longitude: float
18
+ address: str
19
+
20
+
21
+ class CreateShop(BaseModel):
22
+ name: str
23
+ categories: List[ShopCategoryResponse] = []
24
+ locations: Optional[List[Location]] = []
25
+ contact_email: str
26
+ template_id: str
27
+ orders_chat_id: int = 0
28
+ friendly_name: str = ''
29
+ contact_phone: Optional[str] = ''
30
+ bot_token: Optional[str] = ''
31
+ zone: Optional[int] = None
32
+
33
+ @model_validator(mode='before')
34
+ def set_friendly_name_and_format_name(cls, values: dict):
35
+ name = values.get('name', '')
36
+ if len(name) > 35:
37
+ raise ValueError('Shop name too long; must be less than 35 symbols')
38
+
39
+ if not values.get('friendly_name'):
40
+ values['friendly_name'] = name.strip().strip("-")
41
+
42
+ transliterated_name = translit(name, 'ru', reversed=True) if name else ''
43
+ no_whitespaces_and_underscores = transliterated_name.replace(' ', '-').replace('_', '-')
44
+ no_double_dashes = re.sub(r'-{2,}', '-', no_whitespaces_and_underscores)
45
+ to_lowercase = no_double_dashes.lower()
46
+ no_special_characters = re.sub(r'[^a-z0-9_-]', '', to_lowercase)
47
+ formatted_name = re.sub(r'^[^a-z0-9]+|[^a-z0-9]+$', '', no_special_characters)
48
+
49
+ values['name'] = formatted_name
50
+ return values
51
+
52
+
53
+ class Shop(CreateShop):
54
+ # КОНСТАНТЫ ИЗ CONFIG
55
+ WEB_APP_URL: str = ''
56
+ FRONTEND_HOST: str = ''
57
+
58
+ placeholder: Optional[Union[ShopStatuses, Any]] = ShopStatuses.deploying
59
+ tasks: List[Task] = []
60
+ language: str = 'RU'
61
+ nocodb_config: NocoDBConfig = NocoDBConfig()
62
+
63
+ search_enabled: Optional[bool] = False
64
+ warehouse_accounting: Optional[bool] = False
65
+ weekly_reports: Optional[bool] = True
66
+ orders_history_chat_id: Optional[int] = None
67
+ topic_chat_id: Optional[int] = None
68
+ premium_expiration_date: Optional[datetime] = None
69
+ broadcast_messages_count: Optional[int] = 0
70
+ web_app_url: str = Field(default_factory=lambda: Shop.WEB_APP_URL)
71
+
72
+ blocked: bool = False
73
+ block_reason: str = ""
74
+
75
+ @computed_field # type: ignore
76
+ @property
77
+ def sheet_link(self) -> Optional[str]:
78
+ if self.nocodb_config and self.nocodb_config.nocodb_project_id:
79
+ return f"{self.FRONTEND_HOST}/dashboard/#/nc/{self.nocodb_config.nocodb_project_id}"
80
+ return None
81
+
82
+
83
+ class ShopDB(Shop):
84
+ id: str
85
+ tg_admin_id: int = 0
86
+ is_changeable: Optional[bool] = True
87
+ order_process: str = "The-devs.Shop.CreateOrder"
88
+ nocodb_config: NocoDBConfig = NocoDBConfig()
89
+ preview_url: Optional[str] = None
90
+ views_id: List[str] = []
91
+
92
+ @computed_field # type: ignore
93
+ @property
94
+ def configuration(self) -> ProjectConfiguration:
95
+ return ProjectConfiguration(
96
+ shop_name=self.name
97
+ )
98
+
99
+
100
+ class UpdateFromProcess(BaseModel):
101
+ nocodb_config: NocoDBConfig
102
+ language: str
@@ -0,0 +1,24 @@
1
+ from typing import List
2
+
3
+ from shop_system_models.consts.enums import TaskStatuses
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class Task(BaseModel):
8
+ title: str
9
+ assignee_role: List = []
10
+ shop_id: str
11
+ shop_name: str
12
+ submit_url: str = ''
13
+ variables: dict
14
+ element_id: str
15
+ form_json: dict
16
+ job_key: int
17
+ process_id: str
18
+ process_instance_key: int
19
+ process_monitoring_url: str
20
+ deadline: int
21
+ status: TaskStatuses = TaskStatuses.pending
22
+
23
+ class Config:
24
+ use_enum_values = True
@@ -0,0 +1,53 @@
1
+ from typing import List, Optional
2
+
3
+ from shop_system_models.consts.enums import UserRoles
4
+ from shop_system_models.consts.languages import TG_LANGUAGES_MAPPING
5
+ from pydantic import BaseModel, field_validator, model_validator, computed_field
6
+
7
+
8
+ class ReferralUser(BaseModel):
9
+ first_name: str
10
+ last_name: Optional[str] = ''
11
+ username: Optional[str] = ''
12
+ tg_id: int
13
+
14
+
15
+ class User(BaseModel):
16
+ first_name: str
17
+ last_name: Optional[str] = ''
18
+ username: Optional[str] = ''
19
+ tg_id: int
20
+ tg_language: str = '' # language_code from TG
21
+
22
+ @computed_field # type: ignore
23
+ @property
24
+ def language(self) -> str:
25
+ return TG_LANGUAGES_MAPPING.get(self.tg_language, 'EN')
26
+
27
+
28
+ class UserDB(User):
29
+ invited_by_id: Optional[str] = None
30
+ invited_by_user: Optional[ReferralUser] = None
31
+ cache_key: Optional[str] = None
32
+
33
+
34
+ class UserExtended(UserDB):
35
+ SHOPS_LIMIT: int = 0 # сюда потом в рантайме подставишь значение из конфига
36
+
37
+ roles: List[str] = [] # 'shop_admin:<shop_id>' or 'admin'
38
+ shops_available: int = SHOPS_LIMIT
39
+
40
+ @field_validator('roles')
41
+ def if_admin(cls, roles: list):
42
+ for role in roles:
43
+ if role == UserRoles.admin.value:
44
+ return [UserRoles.admin.value]
45
+ return roles
46
+
47
+ @field_validator('shops_available')
48
+ def admin_limit(cls, shops_available, model):
49
+ roles = model.data['roles']
50
+ for role in roles:
51
+ if role == UserRoles.admin.value:
52
+ return 10
53
+ return shops_available
@@ -0,0 +1,14 @@
1
+ import re
2
+
3
+ from pydantic import BaseModel, Field, field_validator
4
+
5
+
6
+ class WebAppUrlUpdateRequest(BaseModel):
7
+ web_app_url: str = Field(..., description="The URL of the telegram web app")
8
+
9
+ @field_validator("web_app_url")
10
+ def validate_web_app_url(cls, value):
11
+ pattern = r"^https://t\.me/[A-Za-z0-9_]+/[A-Za-z0-9_]+$"
12
+ if not re.match(pattern, value):
13
+ raise ValueError("web_app_url must follow the pattern: 'https://t.me/{bot_name}/{webapp_name}', where bot_name and webapp_name can vary.")
14
+ return value
@@ -0,0 +1,23 @@
1
+ import enum
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class PageInfo(BaseModel):
6
+ total_rows: int
7
+ page: int
8
+ page_size: int
9
+ is_first_page: bool
10
+ is_last_page: bool
11
+
12
+
13
+ class ListResponseModel(BaseModel):
14
+ page_info: PageInfo
15
+
16
+
17
+ class ExtraOptionsModel(str, enum.Enum):
18
+ enabled = 'enabled'
19
+ disabled = 'disabled'
20
+
21
+
22
+ class ExtraOptionsStatusResponse(BaseModel):
23
+ status: ExtraOptionsModel
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class InviteLinkResponse(BaseModel):
5
+ valid_until: int
6
+ link: str
@@ -0,0 +1,15 @@
1
+ from pydantic import BaseModel
2
+
3
+ from shop_system_models.deployment_api.request.premium import PremiumPlanTypes
4
+
5
+
6
+ class PremiumLinkResponseModel(BaseModel):
7
+ shop_name: str
8
+ premium_type: str
9
+ link: str
10
+
11
+
12
+ class PremiumPlanType(BaseModel):
13
+ price: int
14
+ final_price: int
15
+ type: PremiumPlanTypes
@@ -0,0 +1,51 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+
4
+
5
+ from shop_system_models.deployment_api.request.nocodb import NocoDBConfig
6
+ from shop_system_models.deployment_api.request.shop_categories import ShopCategory
7
+ from shop_system_models.deployment_api.request.shop_content.blocks import LinkBlocks
8
+ from shop_system_models.deployment_api.request.shop_content.delivery_types import DeliveryTypeResponse
9
+ from shop_system_models.deployment_api.request.shop_content.payment_methods import PaymentMethodResponse
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class ContentDataResponseModel(BaseModel):
14
+ blocks: Optional[LinkBlocks]
15
+ delivery_types: Optional[List[DeliveryTypeResponse]]
16
+ payment_methods: Optional[List[PaymentMethodResponse]]
17
+
18
+
19
+ class ShopDetails(BaseModel):
20
+ shop_id: str
21
+ shop_name: str
22
+ friendly_name: str
23
+ shop_language: Optional[str] = 'RU'
24
+ shop_api_url: str
25
+ contact_phone: str
26
+ contact_email: str
27
+ orders_chat_id: int # orders_management_chat_id
28
+ orders_history_chat_id: Optional[int] = None
29
+ topic_chat_id: Optional[int] = None
30
+ bot_url: str
31
+ bot_token: str
32
+ placeholder: str
33
+ order_process: str
34
+ search_enabled: bool = False
35
+ warehouse_accounting: bool = False
36
+ nocodb_config: Optional[NocoDBConfig] = None
37
+ nocodb_project_id: Optional[str] = None
38
+ nocodb_categories_table: Optional[str] = None
39
+ nocodb_products_table: Optional[str] = None
40
+ nocodb_orders_table: Optional[str] = None
41
+ nocodb_status_table: Optional[str] = None
42
+ nocodb_bot_commands_table: Optional[str] = None
43
+ nocodb_options_table: Optional[str] = ""
44
+ nocodb_options_category_table: Optional[str] = ""
45
+ premium_expiration_date: Optional[datetime] = None
46
+ broadcast_messages_count: Optional[int] = 0
47
+ web_app_url: str
48
+
49
+
50
+ class ShopCategoryResponse(ShopCategory):
51
+ id: str
@@ -0,0 +1,61 @@
1
+ from typing import List, Optional
2
+
3
+
4
+ from shop_system_models.deployment_api.request.services import ServiceConfig
5
+ from shop_system_models.deployment_api.request.shop_templates import ShopTemplate
6
+ from shop_system_models.deployment_api.request.shops import CreateShop, Shop, ShopDB
7
+ from shop_system_models.deployment_api.request.tasks import Task
8
+ from shop_system_models.deployment_api.request.users import User, UserExtended
9
+ from pydantic import BaseModel
10
+
11
+ from shop_system_models.deployment_api.response.general import ListResponseModel
12
+
13
+
14
+ class BasicResponse(BaseModel):
15
+ message: str
16
+
17
+
18
+
19
+
20
+
21
+ class ServiceConfigResponse(ServiceConfig):
22
+ id: str
23
+
24
+
25
+ class CreateShopResponse(CreateShop):
26
+ id: str
27
+
28
+
29
+ class ShopResponse(Shop):
30
+ id: str
31
+ preview_url: Optional[str] = None
32
+
33
+
34
+ class ShopResponseId(ShopDB):
35
+ id: str
36
+
37
+
38
+ class ShopsListResponseModel(ListResponseModel):
39
+ shops: List[ShopResponseId]
40
+
41
+
42
+ class ShopDBResponse(ShopDB):
43
+ id: str
44
+
45
+
46
+ class TaskResponse(Task):
47
+ id: str
48
+
49
+
50
+ class UserResponse(UserExtended):
51
+ id: str
52
+ invited_users: Optional[List[User]] = None
53
+ cache_key: Optional[str] = None
54
+
55
+
56
+ class TokenResponse(BaseModel):
57
+ access_token: str
58
+
59
+
60
+ class ShopTemplateResponse(ShopTemplate):
61
+ id: str
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class WebAppUrlResponse(BaseModel):
5
+ web_app_url: str
@@ -0,0 +1,34 @@
1
+ from datetime import datetime
2
+ from pydantic import BaseModel
3
+
4
+ class NocoDBConfig(BaseModel):
5
+ nocodb_project_id: str
6
+ nocodb_categories_table: str
7
+ nocodb_products_table: str
8
+ nocodb_orders_table: str
9
+ nocodb_status_table: str
10
+ nocodb_bot_commands_table: str
11
+ nocodb_options_table: str | None
12
+ nocodb_options_category_table: str | None
13
+
14
+ class ShopDetailsModel(BaseModel):
15
+ shop_id: str
16
+ shop_name: str
17
+ friendly_name: str
18
+ shop_language: str
19
+ shop_api_url: str
20
+ contact_phone: str | None
21
+ contact_email: str
22
+ orders_chat_id: int
23
+ orders_history_chat_id: int | None
24
+ search_enabled: bool | None
25
+ warehouse_accounting: bool
26
+ bot_url: str | None
27
+ bot_token: str
28
+ payment_token: str | None
29
+ placeholder: str
30
+ order_process: str
31
+ nocodb_config: NocoDBConfig | None
32
+ topic_chat_id: int | None
33
+ premium_expiration_date: datetime | None
34
+ web_app_url: str
@@ -0,0 +1,37 @@
1
+ from pydantic import BaseModel
2
+
3
+ class UserHeadersUpdatingModel(BaseModel):
4
+ tg_id: int
5
+ first_name: str | None
6
+ last_name: str | None
7
+ tg_language: str | None
8
+ username: str | None
9
+
10
+ class UserModel(UserHeadersUpdatingModel):
11
+ password: str | None
12
+ preview_url: str | None
13
+ rights: str
14
+ delivery_addresses: list[str] | None
15
+
16
+ class ReferralUser(BaseModel):
17
+ tg_id: int
18
+ first_name: str
19
+ last_name: str | None
20
+ username: str | None
21
+
22
+ class InvitedUser(ReferralUser):
23
+ tg_language: str | None
24
+ language: str | None
25
+
26
+ class UserDeploymentModel(BaseModel):
27
+ id: str
28
+ first_name: str
29
+ last_name: str | None
30
+ username: str | None
31
+ tg_id: int
32
+ tg_language: str
33
+ invited_by_id: str | None
34
+ invited_by_user: ReferralUser | None
35
+ roles: list[str] | None
36
+ shops_available: int
37
+ invited_users: list[InvitedUser] | None
@@ -5,6 +5,16 @@ from pydantic import BaseModel, Field
5
5
 
6
6
 
7
7
 
8
+ class NocoDBConfig(BaseModel):
9
+ nocodb_project_id: Optional[str] = None
10
+ nocodb_categories_table: Optional[str] = None
11
+ nocodb_products_table: Optional[str] = None
12
+ nocodb_orders_table: Optional[str] = None
13
+ nocodb_status_table: Optional[str] = None
14
+ nocodb_bot_commands_table: Optional[str] = None
15
+ nocodb_options_table: Optional[str] = ""
16
+ nocodb_options_category_table: Optional[str] = ""
17
+
8
18
 
9
19
  class ShopDetailsModel(BaseModel):
10
20
  shop_id: str
@@ -2,86 +2,109 @@ from datetime import datetime
2
2
  from typing import Optional, List, Dict, Any, Union
3
3
  from pydantic import Field, field_validator, BaseModel
4
4
 
5
- from shop_system_models.shop_api import MetaBaseModel
6
5
  from shop_system_models.shop_api.shop.response.baskets import UserBasketResponseModelV2
7
- from shop_system_models.shop_api.shop.response.products import ProductResponseModel
6
+ from pydantic_core.core_schema import ValidationInfo
7
+ from shop_system_models.consts.country_codes import ISO3166
8
8
 
9
9
 
10
- class ExtraFieldPayload(MetaBaseModel):
11
- """Model for extra field data in orders."""
10
+
11
+ class ExtraFieldPayload(BaseModel):
12
12
  name: str
13
13
  value: str
14
14
 
15
15
 
16
16
  class OrderDeliveryTypeModel(BaseModel):
17
- """Model for order delivery details."""
18
17
  name: str
19
- address: Optional[str] = ""
20
- amount: Optional[float] = 0.0
21
- extra_fields_payload: Optional[List[ExtraFieldPayload]] = Field(default_factory=lambda: [])
18
+ address: str | None = ""
19
+ amount: float | None = 0.0
20
+ extra_fields_payload: list[ExtraFieldPayload] | None = []
22
21
 
23
22
 
24
- class Coordinates(MetaBaseModel):
25
- """Geographic coordinates."""
26
- latitude: Optional[float] = None
27
- longitude: Optional[float] = None
23
+ class Coordinates(BaseModel):
24
+ latitude: float | None = None
25
+ longitude: float | None = None
28
26
 
29
27
 
30
- class AddressModel(MetaBaseModel):
31
- """Address model with optional coordinates."""
32
- coordinates: Optional[Coordinates] = None
33
- address: Optional[str] = None
28
+ class AddressModel(BaseModel):
29
+ coordinates: Coordinates | None = None
30
+ address: str | None = None
34
31
 
35
32
 
36
- class ExtraField(MetaBaseModel):
37
- """Model for defining extra fields."""
33
+ class ExtraField(BaseModel):
38
34
  name: str
39
35
  description: str
40
- is_required: Optional[bool] = None
36
+ is_required: bool | None
41
37
 
42
38
 
43
- class DeliveryTypeModel(MetaBaseModel):
44
- """Delivery type configuration model."""
39
+ class DeliveryTypeModel(BaseModel):
45
40
  name: str
46
41
  amount: float = 0.0
47
- is_address_required: Optional[bool] = False
48
- address_hint: Optional[str] = ""
49
- extra_fields: List[ExtraField] = Field(default_factory=list)
42
+ is_address_required: bool | None = False
43
+ address_hint: str | None = ""
44
+ extra_fields: list[ExtraField] = []
50
45
  is_timepicker_required: bool = False
51
- details: Optional[str] = None
52
- country: Optional[str] = None
53
- country_code: Optional[str] = None # ISO format, ex.: RU, KZ, BY...
54
- city: Optional[str] = None
55
- delivery_location: Optional[Coordinates] = None
56
- delivery_radius: Optional[int] = None
57
- delivery_min_hour: Optional[int] = None
58
- delivery_max_hour: Optional[int] = None
59
- delivery_minutes_interval: Optional[int] = None
60
- delivery_min_day: Optional[int] = None
61
- delivery_max_day: Optional[int] = None
62
-
63
-
64
- class BookingOrderModel(MetaBaseModel):
65
- """Details for a booking order."""
46
+ details: str | None = ""
47
+ country: str | None = ""
48
+ country_code: str | None = "" # ISO format, ex.: RU, KZ, BY...
49
+ city: str | None = ""
50
+ delivery_location: Coordinates | None = None
51
+ delivery_radius: int | None = None
52
+ delivery_min_hour: int | None = None
53
+ delivery_max_hour: int | None = None
54
+ delivery_minutes_interval: int | None = None
55
+ delivery_min_day: int | None = None
56
+ delivery_max_day: int | None = None
57
+
58
+ @field_validator("country_code", mode="before")
59
+ def set_country_code(cls, value, values: ValidationInfo):
60
+ country_code_upper = value.upper()
61
+ if ISO3166.get(country_code_upper):
62
+ return country_code_upper
63
+ return "RU"
64
+
65
+
66
+ def format_order_number(order_count: int) -> str:
67
+ return f"#{order_count:04}"
68
+
69
+
70
+ """
71
+ {
72
+ "user_id": 123,
73
+ "basket_id": None,
74
+ "basket": None,
75
+ "status": "booking_request",
76
+ "delivery": None,
77
+ "delivery_date_from": None,
78
+ "user_contact_number": None,
79
+ "client_coordinates": None,
80
+ "comment": "",# НАДО
81
+ "payment_type_id": # НАДО
82
+ "preview_url": ''
83
+ "booking_details": {
84
+ "booking_id": "123123",
85
+ "from_date": datetime.now(),
86
+ "till_date": datetime.now(),
87
+ "item_id": "123123",
88
+ }
89
+ }"""
90
+
91
+
92
+ class BookingOrderModel(BaseModel):
66
93
  booking_id: str
67
94
  from_date: datetime
68
95
  till_date: datetime
69
96
  item_id: str
70
97
 
71
98
 
72
- class CreateOrderModel(MetaBaseModel):
73
- """Model for creating a new order."""
74
- delivery: Optional[OrderDeliveryTypeModel] = None
99
+ class CreateOrderModel(BaseModel):
100
+ delivery: OrderDeliveryTypeModel | None = None
75
101
  delivery_date_from: datetime = Field(default_factory=datetime.now)
76
- comment: Optional[str] = None
77
- user_contact_number: Optional[str] = None
78
- payment_type_id: Optional[str] = None
79
- booking_details: Optional[BookingOrderModel] = None
80
- preview_url: Optional[str] = ""
81
-
102
+ comment: str | None = None
103
+ user_contact_number: str | None = None
104
+ payment_type_id: str | None = None
105
+ booking_details: BookingOrderModel | None = None
106
+ preview_url: str | None = ""
82
107
 
83
- class ProductsInBasket(ProductResponseModel):
84
- count_in_basket: int = 1
85
108
 
86
109
  class OrderPaymentDetails(BaseModel):
87
110
  title: str
@@ -89,21 +112,20 @@ class OrderPaymentDetails(BaseModel):
89
112
  expires_at: datetime
90
113
  link: str
91
114
 
92
- # This depends on UserBasketResponseModelV2 which we'll define in a separate file
93
- # For now, we'll create a placeholder class that can be updated later
115
+
94
116
  class OrderModel(CreateOrderModel):
95
- """Complete order model."""
96
- basket: UserBasketResponseModelV2 # This will be implemented in basket models
97
- user_id: Optional[str] = None
98
- basket_id: Optional[str] = None
99
- status: Optional[str] = None
100
- client_coordinates: Optional[AddressModel] = None
101
- created: datetime = Field(default_factory=datetime.now)
102
- updated: datetime = Field(default_factory=datetime.now)
117
+ basket: UserBasketResponseModelV2
118
+ user_id: str | None = None
119
+ basket_id: str | None = None
120
+ status: str | None = None
121
+ client_coordinates: AddressModel | None = None
122
+ created: datetime = datetime.now()
123
+ updated: datetime = datetime.now()
103
124
  order_number: str = "#0001"
104
- process_key: Optional[int] = None
105
- coupon: Optional[str] = None
125
+ process_key: int | None = None
126
+ coupon: str | None = None
106
127
  admin_message_id: str | None = None
128
+
107
129
  payment_data: OrderPaymentDetails | None = None
108
130
 
109
131
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: shop_system_models
3
- Version: 1.0.0.dev26932
3
+ Version: 1.0.0.dev27183
4
4
  Summary: Shared model definitions for shop system services
5
5
  Author: Pavel Mulin
6
6
  Author-email: pavel@tg-shops.com
@@ -6,20 +6,39 @@ shop_system_models/consts/country_codes.py,sha256=YklfJ4AtRe1jpmLiG2c7PEkzC8LIaH
6
6
  shop_system_models/consts/country_codes.pyi,sha256=zp1m5IkrZLYcQDyCNub7PSBw6ieVVCEQXYW1uibeZTk,54
7
7
  shop_system_models/consts/enums.py,sha256=gangFPp3nEZB7kBN5b4hrw-bje8OFjZt01_laJBRg5I,1545
8
8
  shop_system_models/consts/enums.pyi,sha256=vF6MchkJh4q970es7BFaCj2Jj2jI3VdHWXQPJ17snQM,737
9
+ shop_system_models/consts/languages.py,sha256=wgj2Q0IqXXFDcsL6KM2vP0x-XDA-i-FROUBAdfHyvu0,169
10
+ shop_system_models/consts/languages.pyi,sha256=kUQ3W__UjF3bfox3BlKEkoLq-9Ug7ksR3SYwNscKMho,89
9
11
  shop_system_models/consts/messages/admin.py,sha256=OmHXEeZkg3vysdbNuTBb3MOwynXAHsXEPfHkwLyTelY,7439
10
12
  shop_system_models/consts/messages/locales/en.json,sha256=kKA3Q1raL4aojC-m484H22esCSmjAP_eyBIPn7LapIU,5233
11
13
  shop_system_models/consts/messages/locales/ru.json,sha256=2WUpor_Rui6xPXTspYXNDijoVltCgl0re2mUiWtz-o8,7049
12
14
  shop_system_models/consts/messages/mapping.py,sha256=ud_qJCfWYGUNyztSWj7jjR1ZVqn4AFdO_pQzjeskv_k,952
13
15
  shop_system_models/deployment_api/__init__.py,sha256=hkfYuImAeOVE7d3y9VbuMY9AY9GCaz4a5GhAig-sqBc,22
14
- shop_system_models/deployment_api/request/authorization.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
16
+ shop_system_models/deployment_api/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ shop_system_models/deployment_api/request/authorization.py,sha256=wxwZYs_IhOHMkFST9t-fFPfgcKMnnY0sMwP-KO9sMbA,105
15
18
  shop_system_models/deployment_api/request/bot.py,sha256=URJzYawioh0zxEw2lpF0XprpPi2hLFoIoA3MXMadlAo,232
16
19
  shop_system_models/deployment_api/request/nocodb.py,sha256=_2ri01vBKcNlSqhYZXdchmPclhNZXp1czEMuXauIQ3w,478
17
20
  shop_system_models/deployment_api/request/premium.py,sha256=PrK_WBDgeBKyG-E3c71YD_OZuxBVvI0Z5l9qMglKsqQ,277
18
- shop_system_models/deployment_api/request/processes.py,sha256=gaY1PL7kFbE6E_iDOJgEqIUXAFY01wuNBV3mbe6hVrA,316
19
- shop_system_models/deployment_api/request/servers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- shop_system_models/deployment_api/request/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ shop_system_models/deployment_api/request/processes.py,sha256=6SvMgFyMSO0JdVtIi5BFr6iBHLx8d2BdLJ1KncuWtck,317
22
+ shop_system_models/deployment_api/request/services.py,sha256=XFs9drMz9JZC_GOiVyJwcoIgT01Cg3SAT_SLO6gXEB0,931
23
+ shop_system_models/deployment_api/request/shop_categories.py,sha256=rRvUZoFZTyEINQmutACS2PuAcjRnsYZQKIBwjrsaLZk,183
24
+ shop_system_models/deployment_api/request/shop_content/blocks.py,sha256=ea2WVU7nLBggYv4u2xAQGRmTPRJC19bcmlEAcy7SqCo,594
25
+ shop_system_models/deployment_api/request/shop_content/delivery_types.py,sha256=UAzqBE9fY_L-5hjthJ5zx2YKvskA_59D6wsmSmIguXg,1341
26
+ shop_system_models/deployment_api/request/shop_content/payment_methods.py,sha256=dkBOULMOLG7qjHrhfLKySvGegTDg2JVojTSid73jV4g,699
27
+ shop_system_models/deployment_api/request/shop_templates.py,sha256=orbn4uRLGYrSmpExbWnlebKEaNlnb6uz3RkUguUTneQ,507
28
+ shop_system_models/deployment_api/request/shops.py,sha256=SHUBXs5-H3Gh8Sjm9EV0CSBqK3NllJv9VkvqHh0Zgk4,3472
29
+ shop_system_models/deployment_api/request/tasks.py,sha256=ixjn3I93uE_2d8pb--VMs6g5K2QbHqWqRMDLMfT8d4s,518
30
+ shop_system_models/deployment_api/request/users.py,sha256=5oi4i2T1wOGTxrkCKyUz_Lf8aQjEqWtkeV5QgenXYGo,1571
31
+ shop_system_models/deployment_api/request/web_app_url.py,sha256=UTLmaaidlldkX9bT94ifXVnLJhrkJJZ7WCOaIJ59SKI,546
32
+ shop_system_models/deployment_api/response/general.py,sha256=YLdVdMr-RrVdRYweyOs7No3Td2ApydFKZf-TVGgNoUA,403
33
+ shop_system_models/deployment_api/response/permissions.py,sha256=aKSoUkwUwMizVQ2XARwt3iGnuXV-txVmUs3crtkr5Oo,104
34
+ shop_system_models/deployment_api/response/premium.py,sha256=-Pu6ZB1F8KH1_x19J5hvdy8dRsORsg_tZQLu9BwoLGk,310
35
+ shop_system_models/deployment_api/response/shops.py,sha256=5jBuw0_BUFTw8Mjj3U6MlIwJQXr_CgbV0Ih87WkWm8g,1854
36
+ shop_system_models/deployment_api/response/simple_responses.py,sha256=DoSRLUSsmmgxFgF7gNCjn6t12akxDHAz8mN5Ssz-DD4,1233
37
+ shop_system_models/deployment_api/response/web_app_url.py,sha256=G2KbdkivhZfKQV8gsryQKDGhwiO2RWsNP1-crsJZt0A,89
21
38
  shop_system_models/deployment_api/shared.py,sha256=8xweJ8Wqe72oZTEVdClZkfXdlGRbKhCOBKXuQOqM-dk,1070
39
+ shop_system_models/deployment_api/shared.pyi,sha256=PWxbMaUwi6-rB2vLT9M-scLTGfAKvnOnibxXSDoniuM,931
22
40
  shop_system_models/deployment_api/users.py,sha256=R35Xi201PWwKUovqOC-D0GiXmB7xF6Q8eF4I41H97pM,1022
41
+ shop_system_models/deployment_api/users.pyi,sha256=Vv15K7-ICPzf-hT-k0hltG3nu6Wr7oIymk85ETv9tiM,881
23
42
  shop_system_models/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
43
  shop_system_models/shop_api/__init__.py,sha256=jzSxNJuK5ODw451Jx1BhDt_Dyh1fC1jnstICZ5dOrLo,206
25
44
  shop_system_models/shop_api/__init__.pyi,sha256=iKEzD4j101gPfFRfbkx1s9Yi46pNMbWzgfJE32BuW0g,83
@@ -39,8 +58,8 @@ shop_system_models/shop_api/shop/request/__init__.py,sha256=kFEy1H52PuduvkyKZtFe
39
58
  shop_system_models/shop_api/shop/request/baskets.py,sha256=pQsnXoekis2_5aZYmktUa5YAp3vCAv5MNpD1wBTtDsM,1123
40
59
  shop_system_models/shop_api/shop/request/categories.py,sha256=Z5BTycKC3rQfBP5GI2s3VpxaGxJ3DstfwmJpgF8EVXw,626
41
60
  shop_system_models/shop_api/shop/request/coupons.py,sha256=9TigEAUKie8Rdg38llkQ6oSRl3aWzppJd1FvWEllolI,1537
42
- shop_system_models/shop_api/shop/request/details.py,sha256=6cWi5jKpLP9gKQkNryCOkuuB_MU6dZTwXnKgTQ6QOkw,1047
43
- shop_system_models/shop_api/shop/request/orders.py,sha256=o4_G1OtolUVGK1svHISHE8yxJaGslxFA4S9ga-xwOPI,4691
61
+ shop_system_models/shop_api/shop/request/details.py,sha256=yMz07icr4rbhwLEm8zvoFU38nou3QdrUoX0JfEpzgXE,1464
62
+ shop_system_models/shop_api/shop/request/orders.py,sha256=Q3DRwCYA-qE3TEdns4l320xBRCgnyFyDVYfaP1wNIV4,4601
44
63
  shop_system_models/shop_api/shop/request/payment_methods.py,sha256=KnHM0nz9lp3J8vQ36QIra_jEiaF2uEipNnKKYKsFD6g,388
45
64
  shop_system_models/shop_api/shop/request/products.py,sha256=LKIxg0OcmD-uGK9DkuCVJzOgqOv3LWmCa2W5c-uX0os,1076
46
65
  shop_system_models/shop_api/shop/request/review.py,sha256=jZOaKx2cPymXnd2RjWKnKZZvSHljYDG3VdyPSWAi54o,270
@@ -57,6 +76,6 @@ shop_system_models/shop_api/shop/response/payment_methods.py,sha256=gSb5zU_8LX4x
57
76
  shop_system_models/shop_api/shop/response/products.py,sha256=_r5ZZwJJe4iYht4yIu266xsm1U_zQeSFkj5P3P6Y9Oo,1275
58
77
  shop_system_models/shop_api/shop/response/review.py,sha256=k5jzgS1HinyjbGfR6gnJENB5WufAedsMS77-vZm6fdw,486
59
78
  shop_system_models/shop_api/shop/response/users.py,sha256=DdZOTxGxQdxEg1yZi4v4mm8V8O0pV6K7zc6DWylLrMY,141
60
- shop_system_models-1.0.0.dev26932.dist-info/METADATA,sha256=tD5doaU3SR_k2zscbvI9FnmICDY06YMHlxLmE1dNMIg,978
61
- shop_system_models-1.0.0.dev26932.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
62
- shop_system_models-1.0.0.dev26932.dist-info/RECORD,,
79
+ shop_system_models-1.0.0.dev27183.dist-info/METADATA,sha256=yqgCI5ReGJYugodAeA2lo4dAsADcqjVtkKIKd0cKX5o,978
80
+ shop_system_models-1.0.0.dev27183.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
81
+ shop_system_models-1.0.0.dev27183.dist-info/RECORD,,