letschatty 0.4.348__py3-none-any.whl → 0.4.349__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.
@@ -1,4 +1,9 @@
1
1
  from .assets import *
2
2
  from .empresa import EmpresaModel
3
3
  from .form_field import FormField, FormFieldPreview, CollectedData, SystemFormFields
4
- from .CRM.funnel import Funnel, FunnelPreview, ChatFunnel, StageTransition, FunnelStatus
4
+ from .CRM.funnel import Funnel, FunnelPreview, ChatFunnel, StageTransition, FunnelStatus
5
+ from .integrations.product_sync_status import ProductSyncStatus
6
+ from .integrations.sync_status_enum import SyncStatusEnum
7
+ from .integrations.shopify.shopify_webhook_topics import ShopifyWebhookTopic
8
+ from .integrations.shopify.company_shopify_integration import ShopifyIntegration
9
+ from .integrations.shopify.shopify_product_sync_status import ShopifyProductSyncStatus, ShopifyProductSyncStatusEnum
@@ -1,3 +1,4 @@
1
+ from letschatty.models.company.integrations.shopify.company_shopify_integration import ShopifyIntegration
1
2
  from pydantic import Field, ConfigDict, field_validator, SecretStr, model_validator
2
3
  from typing import Optional, List, Dict
3
4
 
@@ -34,7 +35,7 @@ class EmpresaModel(ChattyAssetModel):
34
35
  continuous_conversation_template_name: Optional[str] = Field(default = None, description="The name of the continuous conversation template")
35
36
  default_follow_up_strategy_id: Optional[StrObjectId] = Field(default = None, description="The id of the default follow up strategy")
36
37
  messaging_settings: MessagingSettings = Field(default = MessagingSettings(), description="The messaging settings for the company")
37
-
38
+ shopify_integration: ShopifyIntegration = Field(default = ShopifyIntegration(), description="The Shopify integration for the company")
38
39
 
39
40
  model_config = ConfigDict(
40
41
  validate_by_name=True,
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import ClassVar, Optional
5
+
6
+ from pydantic import Field
7
+
8
+ from letschatty.models.company.integrations.sync_status_enum import SyncStatusEnum
9
+ from letschatty.models.base_models import CompanyAssetModel
10
+
11
+
12
+ class ProductSyncStatus(CompanyAssetModel):
13
+ """Generic product sync status for any e-commerce integration."""
14
+
15
+ COLLECTION: ClassVar[str] = "product_sync_statuses"
16
+
17
+ integration_type: str = Field(
18
+ description="Integration type (shopify, tiendanube, etc.)"
19
+ )
20
+ status: SyncStatusEnum = Field(description="Current sync status")
21
+
22
+ products_created: int = Field(default=0)
23
+ products_updated: int = Field(default=0)
24
+
25
+ name: str = Field(default="")
26
+
27
+ finished_at: Optional[datetime] = Field(default=None)
28
+
@@ -0,0 +1,62 @@
1
+ from typing import List, Optional
2
+ from datetime import datetime
3
+ from zoneinfo import ZoneInfo
4
+ from pydantic import BaseModel, Field
5
+
6
+ class ShopifyWebhookSubscription(BaseModel):
7
+ """Represents a single webhook subscription"""
8
+ topic: str = Field(description="Webhook topic (e.g., 'products/create')")
9
+ webhook_id: Optional[str] = Field(default=None, description="Shopify webhook ID")
10
+ subscribed_at: datetime = Field(default_factory=lambda: datetime.now(tz=ZoneInfo("UTC")))
11
+ is_active: bool = Field(default=True, description="Whether subscription is active")
12
+
13
+ class ShopifyIntegration(BaseModel):
14
+ """Shopify integration for the company"""
15
+ shopify_store_url: str = Field(default="")
16
+ oauth_state: str = Field(default="")
17
+ oauth_state_at: datetime = Field(default_factory=lambda: datetime.now(tz=ZoneInfo("UTC")))
18
+ access_token: Optional[str] = Field(default=None)
19
+ connected_at: Optional[datetime] = Field(default=None)
20
+ scope: Optional[str] = Field(default=None)
21
+
22
+ # Webhook subscriptions
23
+ webhook_subscriptions: List[ShopifyWebhookSubscription] = Field(
24
+ default_factory=list,
25
+ description="List of active webhook subscriptions"
26
+ )
27
+
28
+ # Scheduled sync settings
29
+ product_sync_enabled: bool = Field(
30
+ default=False,
31
+ description="Whether scheduled product sync is enabled"
32
+ )
33
+ product_sync_interval_hours: int = Field(
34
+ default=24,
35
+ description="Interval in hours for scheduled product sync"
36
+ )
37
+ last_product_sync_at: Optional[datetime] = Field(
38
+ default=None,
39
+ description="Timestamp of last product sync"
40
+ )
41
+
42
+ @property
43
+ def is_connected(self) -> bool:
44
+ """Check if the integration is fully connected"""
45
+ return bool(self.access_token and self.shopify_store_url)
46
+
47
+ def get_subscribed_topics(self) -> List[str]:
48
+ """Get list of currently subscribed webhook topics"""
49
+ return [sub.topic for sub in self.webhook_subscriptions if sub.is_active]
50
+
51
+ def reset(self) -> None:
52
+ """Reset integration to disconnected state"""
53
+ self.shopify_store_url = ""
54
+ self.oauth_state = ""
55
+ self.oauth_state_at = datetime.now(tz=ZoneInfo("UTC"))
56
+ self.access_token = None
57
+ self.connected_at = None
58
+ self.scope = None
59
+ self.webhook_subscriptions = []
60
+ self.product_sync_enabled = False
61
+ self.product_sync_interval_hours = 24
62
+ self.last_product_sync_at = None
@@ -0,0 +1,18 @@
1
+ from pydantic import Field
2
+
3
+ from letschatty.models.company.integrations.product_sync_status import ProductSyncStatus
4
+ from letschatty.models.company.integrations.sync_status_enum import SyncStatusEnum
5
+
6
+
7
+ # Backwards-compatible alias (Shopify-specific name, generic enum)
8
+ ShopifyProductSyncStatusEnum = SyncStatusEnum
9
+
10
+
11
+ class ShopifyProductSyncStatus(ProductSyncStatus):
12
+ """Shopify-flavored wrapper for the generic ProductSyncStatus."""
13
+
14
+ integration_type: str = Field(
15
+ default="shopify",
16
+ frozen=True,
17
+ description="Integration type for this sync status"
18
+ )
@@ -0,0 +1,40 @@
1
+ from enum import Enum
2
+
3
+ class ShopifyWebhookTopic(str, Enum):
4
+ """Shopify webhook topics for products and orders"""
5
+
6
+ # Product webhooks
7
+ PRODUCTS_CREATE = "products/create"
8
+ PRODUCTS_UPDATE = "products/update"
9
+ PRODUCTS_DELETE = "products/delete"
10
+
11
+ # Order webhooks
12
+ ORDERS_CREATE = "orders/create"
13
+ ORDERS_UPDATE = "orders/updated"
14
+ ORDERS_DELETE = "orders/delete"
15
+ ORDERS_FULFILLED = "orders/fulfilled"
16
+ ORDERS_PARTIALLY_FULFILLED = "orders/partially_fulfilled"
17
+ ORDERS_PAID = "orders/paid"
18
+ ORDERS_CANCELLED = "orders/cancelled"
19
+
20
+ @classmethod
21
+ def get_product_topics(cls) -> list[str]:
22
+ """Get all product-related webhook topics"""
23
+ return [
24
+ cls.PRODUCTS_CREATE.value,
25
+ cls.PRODUCTS_UPDATE.value,
26
+ cls.PRODUCTS_DELETE.value,
27
+ ]
28
+
29
+ @classmethod
30
+ def get_order_topics(cls) -> list[str]:
31
+ """Get all order-related webhook topics"""
32
+ return [
33
+ cls.ORDERS_CREATE.value,
34
+ cls.ORDERS_UPDATE.value,
35
+ cls.ORDERS_DELETE.value,
36
+ cls.ORDERS_FULFILLED.value,
37
+ cls.ORDERS_PARTIALLY_FULFILLED.value,
38
+ cls.ORDERS_PAID.value,
39
+ cls.ORDERS_CANCELLED.value,
40
+ ]
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+
4
+ class SyncStatusEnum(str, Enum):
5
+ STARTED = "STARTED"
6
+ RUNNING = "RUNNING"
7
+ FINISHED = "FINISHED"
8
+ FAILED = "FAILED"
9
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: letschatty
3
- Version: 0.4.348
3
+ Version: 0.4.349
4
4
  Summary: Models and custom classes to work across the Chattyverse
5
5
  License: MIT
6
6
  Author: Axel
@@ -79,7 +79,7 @@ letschatty/models/chat/temporary_chat.py,sha256=MR68vYrNvoyf40cLs2p5NnI8BNeN1VGT
79
79
  letschatty/models/chat/time_left.py,sha256=2uA9dS_0QAVnWn7Q2wIwGe4tMrlYBP9qySC7M8I0jb8,3307
80
80
  letschatty/models/company/CRM/business_area.py,sha256=U0F_7Rbq-e5tMSj_MugPqMHm2-IHxbAKbN0PWZ_93-o,296
81
81
  letschatty/models/company/CRM/funnel.py,sha256=gBGZhud060sK5QFI5y9NgmFuhLCOAtzK81TKBhK2gxE,15820
82
- letschatty/models/company/__init__.py,sha256=N_I-kRMHrtnp00c_bbFSiYYM47HJRS-d5slgtbexsl4,229
82
+ letschatty/models/company/__init__.py,sha256=s6maWpREH-RAPoTm8svdivJ5foNEBkb5K6ncyZ0oEjo,626
83
83
  letschatty/models/company/assets/__init__.py,sha256=z0xN_lt1D76bXt8DXVdbH3GkofUPQPZU9NioRSLt_lI,244
84
84
  letschatty/models/company/assets/ai_agents_v2/ai_agent_message_draft.py,sha256=xbshA34RSjHm2g8J7hW2FkWo-Qm8MH2HTbcRcoYmyvc,2076
85
85
  letschatty/models/company/assets/ai_agents_v2/ai_agents_decision_output.py,sha256=aEKZCOsGiFFPSx23fkS5Khfsxo-r8JGk3O0sxiGs8T0,5876
@@ -126,9 +126,14 @@ letschatty/models/company/assets/workflow_execution.py,sha256=CKlT9JTryKC8kNniRX
126
126
  letschatty/models/company/company_chats_snapshot.py,sha256=Mg9Wmu3pfE-t5Sf57FCj-psvc5TkDkFfma-hdh6nE0Q,668
127
127
  letschatty/models/company/company_messaging_settgins.py,sha256=7isXt7gmqw-FKSUSZwdctdXDFMfPi2OyPuWqB7WpC6c,957
128
128
  letschatty/models/company/conversation_topic.py,sha256=__IinJ3YcUsiApF4Em5uAgd01ydRUrlCVxaat-pCCRg,1704
129
- letschatty/models/company/empresa.py,sha256=2INPC8YSZJcT10Gny_zXV_PujeqUGccsZHV31ZSywyw,5961
129
+ letschatty/models/company/empresa.py,sha256=o3IgQqMjQmyDjmR9je3bSF4EiIlJk7BnafiCO5c3pVE,6205
130
130
  letschatty/models/company/form_field.py,sha256=LGyMLybwvfEPG3hMmwsoP_4wnMaPJbVFpG6c1HdVC8E,9802
131
131
  letschatty/models/company/insight.py,sha256=B7BL07E4Z1b9aJHi3PXC1atln4-7fSo9JeqgQoeB_ao,7459
132
+ letschatty/models/company/integrations/product_sync_status.py,sha256=115zOvkaeXpHIUQftXe6dJsOUki3ru8hG3c75e2v4ag,814
133
+ letschatty/models/company/integrations/shopify/company_shopify_integration.py,sha256=PbxgIOG0Qp9Bz0WDrQffuSWrbEiV93JjX7PtHeYsqa0,2496
134
+ letschatty/models/company/integrations/shopify/shopify_product_sync_status.py,sha256=FhsmtFIf82pO9a1_OwV3MyKiJ6CGzlw-SCANZoV2M2g,588
135
+ letschatty/models/company/integrations/shopify/shopify_webhook_topics.py,sha256=HlSm0JHH6G3NPug8tbx9PQaC9yO3cwXJPTuU3qkWdDk,1263
136
+ letschatty/models/company/integrations/sync_status_enum.py,sha256=gh5kkKgLRqhygFFUPhITksp0Z-ImFEpGpzVABr7JiFM,154
132
137
  letschatty/models/company/notifications/notification.py,sha256=wE7rIi21nZno6jjIxajMz4e7OJbzrDHjH1KdkNzJiF8,1907
133
138
  letschatty/models/copilot/links.py,sha256=mcddNR6WdWOoOr3NgDl_FElxF15SiZZXw9wmIV08HRw,185
134
139
  letschatty/models/data_base/__init__.py,sha256=cUTj-TBUYJn1iAofztCr3VUJFF9qg1vmaQlOuoKb1MM,45
@@ -276,7 +281,7 @@ letschatty/services/template_campaigns/template_campaign_service.py,sha256=jORgD
276
281
  letschatty/services/users/agent_service.py,sha256=hIkUUJ1SpkKbh5_uo4i2CeqGtuMTjU7tSV8k5J7WPG4,279
277
282
  letschatty/services/users/user_factory.py,sha256=FCB9uiAfjMeYfh4kMdx5h8VDHJ8MCsD-uaxW3X3KaWM,6681
278
283
  letschatty/services/validators/analytics_validator.py,sha256=6ejecLcif2i1C5trUo1qQgp8vKr9WchdljFZ5GzB2i4,7239
279
- letschatty-0.4.348.dist-info/LICENSE,sha256=EClLu_bO2HBLDcThowIwfaIg5EOwIYhpRsBJjVEk92A,1197
280
- letschatty-0.4.348.dist-info/METADATA,sha256=v718GGEk56rt4dRJa4zpho6WWar_mileYNkNKqDArzk,3283
281
- letschatty-0.4.348.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
282
- letschatty-0.4.348.dist-info/RECORD,,
284
+ letschatty-0.4.349.dist-info/LICENSE,sha256=EClLu_bO2HBLDcThowIwfaIg5EOwIYhpRsBJjVEk92A,1197
285
+ letschatty-0.4.349.dist-info/METADATA,sha256=ATZLw89l0YE2PLTXbysezhxCDad8Epk_7yCeReWIzUA,3283
286
+ letschatty-0.4.349.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
287
+ letschatty-0.4.349.dist-info/RECORD,,