from flask import jsonify from app.utils.logger import logger from app.api.services.base_service import BaseService from sqlalchemy import func, desc from app.api.helpers.response_helper import ResponseHelper from app.api.schemas.user import UserSchema from app.api.schemas.subscription_session import SubscriptionSession from marshmallow import ValidationError from app.models import Members, MembersProducts, SubscriptionOptions, SubscriptionOptionsItems, PaymentsSession, \ Payments from app.extensions import db from app.api.integrations import StripeIntegration import json class SubscriptionsService(BaseService): # def get_all_subscriptions(cls, product_id=None, member_id=None, page=1, limit=20): @staticmethod def get_subscription_data(filters=None): try: if filters is None: filters = {} # Extract filters product_id = filters.get('product_id') member_id = filters.get('member_id') # Extract pagination parameters page = int(filters.get('page', 1)) limit = int(filters.get('limit', 20)) # Ensure page and limit are valid if page < 1: page = 1 if limit < 1 or limit > 100: limit = 20 membersSubList, total_count = MembersProducts.get_all_subscriptions(product_id, member_id, page, limit) # Convert loans to dictionary format member_sub_data = [] for subs in membersSubList: member_sub_data.append({ 'id': subs.id, 'subscription_uid': str(subs.uid), 'member_id': subs.member_id, 'product_id': subs.product_id, 'internal_url': subs.internal_url, 'external_url': subs.external_url, 'dns_group': subs.dns_group, 'primary_server': subs.primary_server, 'provision_port': subs.provision_port, 'status': subs.status, 'updated': subs.updated, "added": subs.added, }) # Calculate total pages total_pages = (total_count + limit - 1) // limit response_data = { 'subscriptions': member_sub_data, 'count': len(member_sub_data), 'pagination': { 'total_count': total_count, 'total_pages': total_pages, 'current_page': page, 'limit': limit, 'has_next': page < total_pages, 'has_prev': page > 1 } } return response_data except Exception as e: logger.error(f"An error occurred while getting dashboard data: {str(e)}", exc_info=True) return jsonify({"message": "Internal Server Error"}), 500 @staticmethod def subscription_available_products(data): try: with db.session.begin(): validated_data = SubscriptionsService.validate_data(data, UserSchema()) token = validated_data.get('token') uid = validated_data.get('uid') member_data = Members.get_member_by_uid(uid) if not member_data: invalid_data = { "error_message": "Member Data", "message_key": "invalid_member", } return ResponseHelper.success(data=invalid_data) # option_name member_id = member_data.id option_name = member_data.option_name trial_name = "TRIAL-90" res_options = [] sub_options = SubscriptionOptions.get_subscription_options(1) for t in sub_options: if t.stripe_product_id is None or t.stripe_product_id.strip() == "" or t.stripe_price_id is None or t.stripe_price_id.strip() == "": price_create_result = StripeIntegration.create_product(t.display_name, t.monthly) logger.info(f"Inside Stripe_Product ===== : {price_create_result}") if price_create_result: SubscriptionOptions.set_stripe_product_id(t.uid, price_create_result['product_id']) SubscriptionOptions.set_stripe_price_id(t.uid, price_create_result['price_id']) res_options.append({ 'option_id': t.id, 'package_uid': t.uid, 'display_name': t.display_name, 'option_name': t.option_name, 'monthly': round(t.monthly * 0.01, 2), 'currency': '$', 'payment_form': 'card_payment_usd', 'stripe_product_id': t.stripe_product_id, 'stripe_price_id': t.stripe_price_id, "items": SubscriptionsService.subscription_items_data(t.option_name), 'added': t.added.isoformat() if t.added else None, 'updated': t.updated.isoformat() if t.updated else None }) subscription_products_data = { "current_product": { "display_name": trial_name if option_name is None else option_name, "subs": [ 'Post Jobs', 'advanced instructors search', 'invite candidates', 'post events', 'Cancel Anytime' ], "next_payment": member_data.next_billing if member_data.next_billing!=None else member_data.trial_end, }, 'stripe_customer_id': member_data.stripe_customer_id, "options": res_options } return ResponseHelper.success(data=subscription_products_data) except Exception as e: logger.error(f"An error occurred while getting dashboard data: {str(e)}", exc_info=True) return jsonify({"message": "Internal Server Error"}), 500 @staticmethod def subscription_items_data(option_name): items_data = SubscriptionOptionsItems.get_subscription_item(option_name) res_options_items = [] for t in items_data: res_options_items.append({ 'description': t.description }) # return ['Post Jobs 222', 'advanced instructors search', 'invite candidates', 'post events', # 'Cancel anytime'] return res_options_items @staticmethod def subscription_session_start(data): try: with db.session.begin(): # logger.info(f"Incoming MyProduct data ==>>>> {data}") validated_data = SubscriptionsService.validate_data(data, SubscriptionSession()) token = validated_data.get('token') uid = validated_data.get('uid') customerId = validated_data.get('customerId') priceId = validated_data.get('priceId') member_data = Members.get_member_by_uid(uid) member_id = member_data.id option_name = validated_data.get('option_name') sub_option = SubscriptionOptions.get_subscription_options_by_option_name(option_name) if sub_option is None: logger.error(f"Invalid Option Name") return [] stripe_session = StripeIntegration.create_checkout_session_subscription(priceId, customerId) if stripe_session: logger.info(f"Inside Stripe_Session ===== : {stripe_session}") logger.info(f"Inside Stripe_Session ID ===== : {stripe_session.id}") PaymentsSession.add_payment_session(member_id, option_name, 'STRIPE', stripe_session.id) else: stripe_error = f"Stripe Returned {stripe_session}" db.session.rollback() return ResponseHelper.error(result_description=str(stripe_error)) # # product_id = validated_data.get('product_id') # product_subscription_uid='' # product_subscription_external_url = '' # product_subscription_internal_url = '' # product_data = Products.get_product_by_product_id(product_id) # product_description = ProductsDetails.get_product_details_with_product_id('A000002') # productDataStatus = product_data.status # # memberSubscription = MembersProducts.get_member_product_by_product_member_id(member_id, product_id) # if memberSubscription is not None: # logger.info(f"Incoming MyProduct data ==>>>> {memberSubscription}") # productDataStatus = memberSubscription.status # product_subscription_uid = memberSubscription.uid # product_subscription_external_url = memberSubscription.external_url # product_subscription_internal_url = memberSubscription.internal_url # Simulate processing response_data = { "stripe_session": stripe_session.url, "member_id": member_id, "uid": uid, } return ResponseHelper.success(data=response_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error() @staticmethod def subscription_webhook_start(data): try: with db.session.begin(): hook_data = data["data"]["object"] # logger.info(f"***** HOOK Data ALL ==>>>> {hook_data}") # json_hook_output = json.dumps(hook_data["data"]) for key, value in hook_data.items(): logger.info(f"**************** Key: {key}, *********** Value: {value}") data_id = hook_data["id"] amount_subtotal = hook_data["amount_subtotal"] logger.info(f"HOOK Result DATA ==>>>> {data_id} {amount_subtotal}") currentPaymentsession = PaymentsSession.get_payment_session_with_session_id(data_id) logger.info(f"HOOK currentPaymentsession ==>>>> {currentPaymentsession}") if currentPaymentsession: payment_data = { "payment_uid": currentPaymentsession.uid, "member_id": currentPaymentsession.member_id, "option_name": currentPaymentsession.option_name, "amount": amount_subtotal, "option_type": "MAIN", "next_billing_days": 30 } logger.info(f"HOOK payment_data ==>>>> {payment_data}") paymentAddResult = Payments.add_payment(payment_data["member_id"], payment_data["payment_uid"], payment_data["option_name"], payment_data["amount"], payment_data["option_type"], payment_data["next_billing_days"]) logger.info(f"HOOK paymentAddResult next_billing ==>>>> {paymentAddResult.next_billing}") logger.info(f"HOOK paymentAddResult id ==>>>> {paymentAddResult.id}") logger.info(f"HOOK paymentAddResult payment_uid ==>>>> {paymentAddResult.payment_uid}") if paymentAddResult: Members.set_user_option_name(payment_data["member_id"], payment_data["option_name"]) Members.set_user_next_billing(payment_data["member_id"], paymentAddResult.next_billing) # Simulate processing response_data = { "data_id": data_id, "member_id": "", "uid": "", } return ResponseHelper.success(data=response_data) except ValidationError as err: logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.unprocessable_entity(result_description="Validation exception") except ValueError as err: logger.error(f"{getattr(err, 'messages', str(err))}") db.session.rollback() return ResponseHelper.error(result_description=str(err)) except Exception as e: logger.error(f"An error occurred: {str(e)}", exc_info=True) db.session.rollback() return ResponseHelper.internal_server_error()