geek-cafe-saas-sdk 0.7.0__py3-none-any.whl → 0.7.1__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.

Potentially problematic release.


This version of geek-cafe-saas-sdk might be problematic. Click here for more details.

Files changed (79) hide show
  1. geek_cafe_saas_sdk/__init__.py +1 -1
  2. geek_cafe_saas_sdk/domains/files/models/directory.py +42 -6
  3. geek_cafe_saas_sdk/domains/files/models/file.py +40 -4
  4. geek_cafe_saas_sdk/domains/files/models/file_share.py +33 -0
  5. geek_cafe_saas_sdk/domains/files/models/file_version.py +24 -0
  6. geek_cafe_saas_sdk/domains/files/services/directory_service.py +54 -135
  7. geek_cafe_saas_sdk/domains/files/services/file_share_service.py +37 -120
  8. geek_cafe_saas_sdk/domains/files/services/file_system_service.py +40 -102
  9. geek_cafe_saas_sdk/domains/files/services/file_version_service.py +44 -124
  10. geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +55 -7
  11. geek_cafe_saas_sdk/domains/notifications/__init__.py +18 -0
  12. geek_cafe_saas_sdk/domains/notifications/handlers/__init__.py +1 -0
  13. geek_cafe_saas_sdk/domains/notifications/handlers/create_webhook/app.py +73 -0
  14. geek_cafe_saas_sdk/domains/notifications/handlers/get/app.py +40 -0
  15. geek_cafe_saas_sdk/domains/notifications/handlers/get_preferences/app.py +34 -0
  16. geek_cafe_saas_sdk/domains/notifications/handlers/list/app.py +43 -0
  17. geek_cafe_saas_sdk/domains/notifications/handlers/list_webhooks/app.py +40 -0
  18. geek_cafe_saas_sdk/domains/notifications/handlers/mark_read/app.py +40 -0
  19. geek_cafe_saas_sdk/domains/notifications/handlers/send/app.py +83 -0
  20. geek_cafe_saas_sdk/domains/notifications/handlers/update_preferences/app.py +45 -0
  21. geek_cafe_saas_sdk/domains/notifications/models/__init__.py +16 -0
  22. geek_cafe_saas_sdk/domains/notifications/models/notification.py +717 -0
  23. geek_cafe_saas_sdk/domains/notifications/models/notification_preference.py +365 -0
  24. geek_cafe_saas_sdk/domains/notifications/models/webhook_subscription.py +339 -0
  25. geek_cafe_saas_sdk/domains/notifications/services/__init__.py +10 -0
  26. geek_cafe_saas_sdk/domains/notifications/services/notification_service.py +576 -0
  27. geek_cafe_saas_sdk/domains/payments/__init__.py +16 -0
  28. geek_cafe_saas_sdk/domains/payments/handlers/README.md +334 -0
  29. geek_cafe_saas_sdk/domains/payments/handlers/__init__.py +6 -0
  30. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/create/app.py +105 -0
  31. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/get/app.py +60 -0
  32. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/update/app.py +97 -0
  33. geek_cafe_saas_sdk/domains/payments/handlers/payment_intents/create/app.py +97 -0
  34. geek_cafe_saas_sdk/domains/payments/handlers/payment_intents/get/app.py +60 -0
  35. geek_cafe_saas_sdk/domains/payments/handlers/payments/get/app.py +60 -0
  36. geek_cafe_saas_sdk/domains/payments/handlers/payments/list/app.py +68 -0
  37. geek_cafe_saas_sdk/domains/payments/handlers/payments/record/app.py +118 -0
  38. geek_cafe_saas_sdk/domains/payments/handlers/refunds/create/app.py +89 -0
  39. geek_cafe_saas_sdk/domains/payments/handlers/refunds/get/app.py +60 -0
  40. geek_cafe_saas_sdk/domains/payments/models/__init__.py +17 -0
  41. geek_cafe_saas_sdk/domains/payments/models/billing_account.py +521 -0
  42. geek_cafe_saas_sdk/domains/payments/models/payment.py +639 -0
  43. geek_cafe_saas_sdk/domains/payments/models/payment_intent_ref.py +539 -0
  44. geek_cafe_saas_sdk/domains/payments/models/refund.py +404 -0
  45. geek_cafe_saas_sdk/domains/payments/services/__init__.py +11 -0
  46. geek_cafe_saas_sdk/domains/payments/services/payment_service.py +405 -0
  47. geek_cafe_saas_sdk/domains/subscriptions/__init__.py +19 -0
  48. geek_cafe_saas_sdk/domains/subscriptions/handlers/README.md +408 -0
  49. geek_cafe_saas_sdk/domains/subscriptions/handlers/__init__.py +1 -0
  50. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/create/app.py +81 -0
  51. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/get/app.py +48 -0
  52. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/list/app.py +54 -0
  53. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/update/app.py +54 -0
  54. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/create/app.py +83 -0
  55. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/get/app.py +47 -0
  56. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/validate/app.py +62 -0
  57. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/create/app.py +82 -0
  58. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/get/app.py +48 -0
  59. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/list/app.py +66 -0
  60. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/update/app.py +54 -0
  61. geek_cafe_saas_sdk/domains/subscriptions/handlers/usage/aggregate/app.py +72 -0
  62. geek_cafe_saas_sdk/domains/subscriptions/handlers/usage/record/app.py +89 -0
  63. geek_cafe_saas_sdk/domains/subscriptions/models/__init__.py +13 -0
  64. geek_cafe_saas_sdk/domains/subscriptions/models/addon.py +604 -0
  65. geek_cafe_saas_sdk/domains/subscriptions/models/discount.py +492 -0
  66. geek_cafe_saas_sdk/domains/subscriptions/models/plan.py +569 -0
  67. geek_cafe_saas_sdk/domains/subscriptions/models/usage_record.py +300 -0
  68. geek_cafe_saas_sdk/domains/subscriptions/services/__init__.py +10 -0
  69. geek_cafe_saas_sdk/domains/subscriptions/services/subscription_manager_service.py +694 -0
  70. geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +123 -1
  71. geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +213 -0
  72. geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +7 -0
  73. geek_cafe_saas_sdk/services/database_service.py +10 -6
  74. geek_cafe_saas_sdk/utilities/environment_variables.py +16 -0
  75. geek_cafe_saas_sdk/utilities/logging_utility.py +77 -0
  76. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/METADATA +1 -1
  77. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/RECORD +79 -20
  78. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/WHEEL +0 -0
  79. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,60 @@
1
+ """
2
+ Lambda handler for getting payment intent by ID.
3
+
4
+ Requires authentication (secure mode).
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
10
+
11
+
12
+ # Factory creates handler (defaults to secure auth)
13
+ handler_wrapper = create_handler(
14
+ service_class=PaymentService,
15
+ require_body=False,
16
+ convert_case=True
17
+ )
18
+
19
+
20
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
21
+ """
22
+ Get payment intent by ID.
23
+
24
+ Args:
25
+ event: Lambda event from API Gateway
26
+ context: Lambda context
27
+ injected_service: Optional PaymentService for testing
28
+
29
+ Path parameters:
30
+ - intentId: Payment intent reference ID
31
+
32
+ Returns 200 with payment intent data
33
+ """
34
+ return handler_wrapper.execute(event, context, get_payment_intent, injected_service)
35
+
36
+
37
+ def get_payment_intent(
38
+ event: Dict[str, Any],
39
+ service: PaymentService,
40
+ user_context: Dict[str, str]
41
+ ) -> Any:
42
+ """
43
+ Business logic for getting payment intent.
44
+ """
45
+ tenant_id = user_context.get("tenant_id")
46
+
47
+ # Extract intent ID from path parameters
48
+ path_params = event.get("pathParameters", {})
49
+ intent_id = path_params.get("intentId")
50
+
51
+ if not intent_id:
52
+ raise ValueError("intentId path parameter is required")
53
+
54
+ # Get payment intent
55
+ result = service.get_payment_intent(
56
+ intent_ref_id=intent_id,
57
+ tenant_id=tenant_id
58
+ )
59
+
60
+ return result
@@ -0,0 +1,60 @@
1
+ """
2
+ Lambda handler for getting payment by ID.
3
+
4
+ Requires authentication (secure mode).
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
10
+
11
+
12
+ # Factory creates handler (defaults to secure auth)
13
+ handler_wrapper = create_handler(
14
+ service_class=PaymentService,
15
+ require_body=False,
16
+ convert_case=True
17
+ )
18
+
19
+
20
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
21
+ """
22
+ Get payment by ID.
23
+
24
+ Args:
25
+ event: Lambda event from API Gateway
26
+ context: Lambda context
27
+ injected_service: Optional PaymentService for testing
28
+
29
+ Path parameters:
30
+ - paymentId: Payment ID
31
+
32
+ Returns 200 with payment data
33
+ """
34
+ return handler_wrapper.execute(event, context, get_payment, injected_service)
35
+
36
+
37
+ def get_payment(
38
+ event: Dict[str, Any],
39
+ service: PaymentService,
40
+ user_context: Dict[str, str]
41
+ ) -> Any:
42
+ """
43
+ Business logic for getting payment.
44
+ """
45
+ tenant_id = user_context.get("tenant_id")
46
+
47
+ # Extract payment ID from path parameters
48
+ path_params = event.get("pathParameters", {})
49
+ payment_id = path_params.get("paymentId")
50
+
51
+ if not payment_id:
52
+ raise ValueError("paymentId path parameter is required")
53
+
54
+ # Get payment
55
+ result = service.get_payment(
56
+ payment_id=payment_id,
57
+ tenant_id=tenant_id
58
+ )
59
+
60
+ return result
@@ -0,0 +1,68 @@
1
+ """
2
+ Lambda handler for listing payments.
3
+
4
+ Requires authentication (secure mode).
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
10
+
11
+
12
+ # Factory creates handler (defaults to secure auth)
13
+ handler_wrapper = create_handler(
14
+ service_class=PaymentService,
15
+ require_body=False,
16
+ convert_case=True
17
+ )
18
+
19
+
20
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
21
+ """
22
+ List payments for a tenant or billing account.
23
+
24
+ Args:
25
+ event: Lambda event from API Gateway
26
+ context: Lambda context
27
+ injected_service: Optional PaymentService for testing
28
+
29
+ Query parameters:
30
+ - billingAccountId: Optional billing account ID to filter by
31
+ - limit: Optional page size (default: 50, max: 100)
32
+
33
+ Returns 200 with list of payments
34
+ """
35
+ return handler_wrapper.execute(event, context, list_payments, injected_service)
36
+
37
+
38
+ def list_payments(
39
+ event: Dict[str, Any],
40
+ service: PaymentService,
41
+ user_context: Dict[str, str]
42
+ ) -> Any:
43
+ """
44
+ Business logic for listing payments.
45
+ """
46
+ tenant_id = user_context.get("tenant_id")
47
+
48
+ # Extract query parameters
49
+ query_params = event.get("queryStringParameters") or {}
50
+ billing_account_id = query_params.get("billingAccountId")
51
+ limit = query_params.get("limit", "50")
52
+
53
+ # Validate and convert limit
54
+ try:
55
+ limit = int(limit)
56
+ if limit < 1 or limit > 100:
57
+ raise ValueError("limit must be between 1 and 100")
58
+ except ValueError as e:
59
+ raise ValueError(f"Invalid limit parameter: {str(e)}")
60
+
61
+ # List payments
62
+ result = service.list_payments(
63
+ tenant_id=tenant_id,
64
+ billing_account_id=billing_account_id,
65
+ limit=limit
66
+ )
67
+
68
+ return result
@@ -0,0 +1,118 @@
1
+ """
2
+ Lambda handler for recording settled payments.
3
+
4
+ Typically called from Stripe webhooks or payment processor callbacks.
5
+ Requires authentication (secure mode).
6
+ """
7
+
8
+ from typing import Dict, Any
9
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
10
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
11
+
12
+
13
+ # Factory creates handler (defaults to secure auth)
14
+ handler_wrapper = create_handler(
15
+ service_class=PaymentService,
16
+ require_body=True,
17
+ convert_case=True
18
+ )
19
+
20
+
21
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
22
+ """
23
+ Record a settled payment.
24
+
25
+ Args:
26
+ event: Lambda event from API Gateway or webhook
27
+ context: Lambda context
28
+ injected_service: Optional PaymentService for testing
29
+
30
+ Expected body (camelCase from frontend/webhook):
31
+ {
32
+ "billingAccountId": "account-123",
33
+ "paymentIntentRefId": "intent-123", // Optional
34
+ "grossAmountCents": 5000, // $50.00
35
+ "feeAmountCents": 145, // $1.45 (Stripe fee)
36
+ "currencyCode": "USD",
37
+ "pspType": "stripe",
38
+ "pspTransactionId": "txn_xxx",
39
+ "pspChargeId": "ch_xxx",
40
+ "pspBalanceTransactionId": "txn_balance_xxx",
41
+ "paymentMethodId": "pm_xxx",
42
+ "paymentMethodType": "card",
43
+ "paymentMethodLast4": "4242",
44
+ "paymentMethodBrand": "visa",
45
+ "paymentMethodFunding": "credit",
46
+ "description": "Subscription payment",
47
+ "statementDescriptor": "ACME SUBSCRIPTION",
48
+ "receiptEmail": "user@example.com",
49
+ "receiptUrl": "https://stripe.com/receipt/xxx",
50
+ "customerId": "user-123", // Optional
51
+ "invoiceId": "inv-123", // Optional
52
+ "subscriptionId": "sub-123" // Optional
53
+ }
54
+
55
+ Returns 201 with recorded payment
56
+ """
57
+ return handler_wrapper.execute(event, context, record_payment, injected_service)
58
+
59
+
60
+ def record_payment(
61
+ event: Dict[str, Any],
62
+ service: PaymentService,
63
+ user_context: Dict[str, str]
64
+ ) -> Any:
65
+ """
66
+ Business logic for recording payments.
67
+ """
68
+ payload = event["parsed_body"]
69
+ tenant_id = user_context.get("tenant_id")
70
+
71
+ # Extract required fields
72
+ billing_account_id = payload.get("billing_account_id")
73
+ gross_amount_cents = payload.get("gross_amount_cents")
74
+ fee_amount_cents = payload.get("fee_amount_cents")
75
+
76
+ if not billing_account_id:
77
+ raise ValueError("billing_account_id is required")
78
+ if gross_amount_cents is None or gross_amount_cents <= 0:
79
+ raise ValueError("gross_amount_cents must be greater than 0")
80
+ if fee_amount_cents is None or fee_amount_cents < 0:
81
+ raise ValueError("fee_amount_cents must be non-negative")
82
+
83
+ # Extract optional fields
84
+ payment_intent_ref_id = payload.get("payment_intent_ref_id")
85
+ currency_code = payload.get("currency_code", "USD")
86
+ psp_type = payload.get("psp_type", "stripe")
87
+
88
+ # Build kwargs for optional fields
89
+ kwargs = {}
90
+ optional_fields = [
91
+ "psp_transaction_id", "psp_charge_id", "psp_balance_transaction_id",
92
+ "fee_details",
93
+ "payment_method_id", "payment_method_type", "payment_method_last4",
94
+ "payment_method_brand", "payment_method_funding",
95
+ "settlement_date", "payout_id",
96
+ "customer_id", "invoice_id", "subscription_id",
97
+ "description", "statement_descriptor",
98
+ "receipt_number", "receipt_email", "receipt_url",
99
+ "psp_metadata", "application_fee_amount_cents"
100
+ ]
101
+
102
+ for field in optional_fields:
103
+ if field in payload:
104
+ kwargs[field] = payload[field]
105
+
106
+ # Record payment
107
+ result = service.record_payment(
108
+ tenant_id=tenant_id,
109
+ billing_account_id=billing_account_id,
110
+ payment_intent_ref_id=payment_intent_ref_id,
111
+ gross_amount_cents=gross_amount_cents,
112
+ fee_amount_cents=fee_amount_cents,
113
+ currency_code=currency_code,
114
+ psp_type=psp_type,
115
+ **kwargs
116
+ )
117
+
118
+ return result
@@ -0,0 +1,89 @@
1
+ """
2
+ Lambda handler for creating refunds.
3
+
4
+ Requires authentication (secure mode).
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
10
+
11
+
12
+ # Factory creates handler (defaults to secure auth)
13
+ handler_wrapper = create_handler(
14
+ service_class=PaymentService,
15
+ require_body=True,
16
+ convert_case=True
17
+ )
18
+
19
+
20
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
21
+ """
22
+ Create a refund for a payment.
23
+
24
+ Args:
25
+ event: Lambda event from API Gateway
26
+ context: Lambda context
27
+ injected_service: Optional PaymentService for testing
28
+
29
+ Expected body (camelCase from frontend):
30
+ {
31
+ "paymentId": "payment-123",
32
+ "amountCents": 5000, // Amount to refund (must not exceed remaining)
33
+ "reason": "requested_by_customer", // "duplicate", "fraudulent", "requested_by_customer"
34
+ "description": "Customer requested refund",
35
+ "pspRefundId": "re_xxx", // Optional - PSP refund ID if already created
36
+ "disputeId": "dp_xxx" // Optional - if related to dispute
37
+ }
38
+
39
+ Returns 201 with created refund
40
+ """
41
+ return handler_wrapper.execute(event, context, create_refund, injected_service)
42
+
43
+
44
+ def create_refund(
45
+ event: Dict[str, Any],
46
+ service: PaymentService,
47
+ user_context: Dict[str, str]
48
+ ) -> Any:
49
+ """
50
+ Business logic for creating refunds.
51
+ """
52
+ payload = event["parsed_body"]
53
+ tenant_id = user_context.get("tenant_id")
54
+ user_id = user_context.get("user_id")
55
+
56
+ # Extract required fields
57
+ payment_id = payload.get("payment_id")
58
+ amount_cents = payload.get("amount_cents")
59
+
60
+ if not payment_id:
61
+ raise ValueError("payment_id is required")
62
+ if amount_cents is None or amount_cents <= 0:
63
+ raise ValueError("amount_cents must be greater than 0")
64
+
65
+ # Extract optional fields
66
+ reason = payload.get("reason")
67
+
68
+ # Build kwargs for optional fields
69
+ kwargs = {}
70
+ optional_fields = [
71
+ "description", "psp_refund_id", "psp_balance_transaction_id",
72
+ "dispute_id", "notes"
73
+ ]
74
+
75
+ for field in optional_fields:
76
+ if field in payload:
77
+ kwargs[field] = payload[field]
78
+
79
+ # Create refund
80
+ result = service.create_refund(
81
+ tenant_id=tenant_id,
82
+ payment_id=payment_id,
83
+ amount_cents=amount_cents,
84
+ reason=reason,
85
+ initiated_by_id=user_id,
86
+ **kwargs
87
+ )
88
+
89
+ return result
@@ -0,0 +1,60 @@
1
+ """
2
+ Lambda handler for getting refund by ID.
3
+
4
+ Requires authentication (secure mode).
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.payments.services import PaymentService
10
+
11
+
12
+ # Factory creates handler (defaults to secure auth)
13
+ handler_wrapper = create_handler(
14
+ service_class=PaymentService,
15
+ require_body=False,
16
+ convert_case=True
17
+ )
18
+
19
+
20
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
21
+ """
22
+ Get refund by ID.
23
+
24
+ Args:
25
+ event: Lambda event from API Gateway
26
+ context: Lambda context
27
+ injected_service: Optional PaymentService for testing
28
+
29
+ Path parameters:
30
+ - refundId: Refund ID
31
+
32
+ Returns 200 with refund data
33
+ """
34
+ return handler_wrapper.execute(event, context, get_refund, injected_service)
35
+
36
+
37
+ def get_refund(
38
+ event: Dict[str, Any],
39
+ service: PaymentService,
40
+ user_context: Dict[str, str]
41
+ ) -> Any:
42
+ """
43
+ Business logic for getting refund.
44
+ """
45
+ tenant_id = user_context.get("tenant_id")
46
+
47
+ # Extract refund ID from path parameters
48
+ path_params = event.get("pathParameters", {})
49
+ refund_id = path_params.get("refundId")
50
+
51
+ if not refund_id:
52
+ raise ValueError("refundId path parameter is required")
53
+
54
+ # Get refund
55
+ result = service.get_refund(
56
+ refund_id=refund_id,
57
+ tenant_id=tenant_id
58
+ )
59
+
60
+ return result
@@ -0,0 +1,17 @@
1
+ """Payment models.
2
+
3
+ Geek Cafe, LLC
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from .billing_account import BillingAccount
8
+ from .payment_intent_ref import PaymentIntentRef
9
+ from .payment import Payment
10
+ from .refund import Refund
11
+
12
+ __all__ = [
13
+ "BillingAccount",
14
+ "PaymentIntentRef",
15
+ "Payment",
16
+ "Refund",
17
+ ]