o
    i|                     @   s   d dl Z d dlmZmZ d dlmZmZ d dlmZ d dlm	Z	m
Z
 d dlmZ eje
 e
jZe je
je
jfdZddd	Zd
d Zdd Zdd Zdd Zdd Zdd Zdd ZdS )    N)datetime	timedelta)requestjsonify)closing)connect_to_databaseConfig)app)authc                 C   st   d}d}| r| |k s| |krt d| d| |r,||k s"||kr,t d| d| | r8|r8|| kr8t ddS )z$Validate timestamps for Razorpay APICm8   V	8 zstart_at must be between z and zexpire_by must be between z expire_by must be after start_atT)
ValueError)start_at	expire_byZmin_tsZmax_ts r   X/Users/harjaapdhillon/Desktop/newidea/medvista_backend/Services/Billing/Subscriptions.pyvalidate_razorpay_timestamps   s   r   c                  C   sF  t  } ddg}|D ]}|| vrtd| dddf  S q
t }zzt|jdd}|d| d f | }|r|d	 d
kr^tddddfW  d   W W |r]|  S S |d	 dkr|d rwz
t	j
|d  W n   Y |d|d f |d|d f |d| d f | }|stddddfW  d   W W |r|  S S t|d dk}|d dv r|s|d stddddfW  d   W W |r|  S S t }|tdd |tdd dd|d }	|rd
nd}
|d| d | d ||	|
|d |	f |j}|rd nd!}|rd"nd#}d$|d% d&| }|d'||||td(d |d |d |d) ||f	 |j}|rl|  td*|dd+d,d-fW  d   W W |rk|  S S ztt  }d.}d/}t|d0 |}|d dv r|d d1kr|d2 }d3}n|d4 }d5}t||}t|| td6|  td7| d8 td9|  |d |d:||t| d t|t||d; d<d=}td>|  t	j
|}|d?|d |f |d@|d |f |d tt|d dA|d; dB| dBdCi|dD}dE}nEt	jtt|d dF dA|t| d t|t||d; d<dG}|d@|d |f |d tt|d dA|d; dB| dBdCidH}dI}|  t||||d+dJd-fW W  d   W W |rx|  S S  tjj y } z|!  t|}tdK|  dL|v sdM|v sdN|v sdO|v rtdPd|dQdRfW  Y d}~W  d   W W |r|  S S dS|v rtdTdddRfW  Y d}~W  d   W W |r|  S S tdU| dddRfW  Y d}~W  d   W W |r|  S S d}~w tjj"yN } z-|!  tdVt|  tdWdddRfW  Y d}~W  d   W W |rI|  S S d}~w t#y } z0|!  tdXt|  tdYdt|dQdRfW  Y d}~W  d   W W |r|  S S d}~w t$y } z2|!  tdZt|  td[t| dddRfW  Y d}~W  d   W W |r|  S S d}~ww 1 sw   Y  W n: t$y } z-|r|!  td\t|  td]t| dddRfW  Y d}~W |r|  S S d}~ww W |r|  dS dS |r"|  w w )^zS
    Create a new subscription with proper validation and Razorpay integration
    user_id
package_idMissing required field: Tmessageerror  
dictionaryz
                SELECT id, package_id, status, razorpay_subscription_id
                FROM subscriptions 
                WHERE user_id = %s AND status IN ('active', 'pending')
                ORDER BY id DESC LIMIT 1
            statusactivez^You already have an active subscription. Please cancel it before subscribing to a new package.Npendingrazorpay_subscription_idz
                        UPDATE subscriptions SET status = 'canceled' 
                        WHERE id = %s
                    idz
                        UPDATE invoices SET status = 'canceled'
                        WHERE subscription_id = %s AND status IN ('draft', 'pending', 'unpaid')
                    z
                SELECT id, billing_cycle, razorpay_plan_id, price, currency_id, 
                       package_name, maximum_bookings, price_after_max
                FROM packages WHERE id = %s AND is_active = TRUE
            zActive package not found  priceg        billing_cycle)monthlyannualrazorpay_plan_idzWThis package is not properly configured for recurring payments. Please contact support.   daysm  )r$   r%   lifetimez
                INSERT INTO subscriptions (
                    user_id, package_id, start_date, end_date, 
                    status, billing_cycle, next_billing_date
                ) VALUES (%s, %s, %s, %s, %s, %s, %s)
            ZpaidZdraftfreerazorpayzINV-z%Y%m%d%H%M%S-a	  
                INSERT INTO invoices (
                    subscription_id, invoice_number, issue_date, due_date,
                    amount, total_amount, currency_id, status, gateway_type
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
               currency_idz(Free subscription activated successfullyF)r   subscription_idpayment_datar      r   r   i,  r$   i$.    i    zCurrent timestamp: zStart at timestamp: z (current + 5 min)zExpire by timestamp:    package_name)r   r1   
invoice_idr7   )plan_idtotal_countZcustomer_notifyr   r   notesz*Creating Razorpay subscription with data: z
                        UPDATE subscriptions 
                        SET razorpay_subscription_id = %s 
                        WHERE id = %s
                    z
                        UPDATE invoices
                        SET gateway_order_id = %s
                        WHERE id = %s
                    ZINRemail )r   razorpay_keyamountcurrencynameprefillr:   z&Subscription created, awaiting paymentd   )r?   r@   Zreceiptr;   )razorpay_order_idr>   r?   r@   rA   rB   z(One-time order created, awaiting payment)r   r1   r8   r2   r   zRazorpay BadRequestError: end_time	timestampr   r   z@Subscription timing configuration error. Please contact support.)r   r   details  r9   z4Package configuration error. Please contact support.zPayment gateway error: zRazorpay ServerError: z=Payment gateway is temporarily unavailable. Please try again.zTimestamp validation error: z2Subscription timing error. Please contact support.zPayment creation error: zPayment creation failed: zSubscription creation error: zError creating subscription: )%r   get_jsonr   r   r   cursorexecutefetchonecloserazorpay_clientsubscriptioncancelfloatr   nowr   get	lastrowidstrftimecommitintrF   maxminr   printstrcreateRAZORPAY_KEY_IDorderr-   errorsBadRequestErrorrollbackServerErrorr   	Exception)datarequired_fieldsfield
connectionrJ   Zexisting_subscriptionpackageis_free
start_dateend_dateZ
sub_statusr1   invoice_statusZgateway_typeZinvoice_numberr8   Zcurrent_timestampZmin_timestampZmax_timestampr   r   r:   Zsubscription_dataZrazorpay_subscriptionr2   r   Zrazorpay_ordereZ	error_msgr   r   r   create_subscription   s    
    
   
 

	
  
 








   
(   

   
   
   
    
    
    (
    

rn   c                 C   s  t  }tjd}zzt|jdd}d}| g}|r$|d7 }|| |d7 }||t| |	 }i }d}|D ]R}	|	d }
|sN|	d	 |	d
 |	d d}|
|vru|	d |	d |	d |	d |	d |	d |	d t
|	d |	d g d
||
< |	d r||
 d |	d |	d |	d d q:tt| |dddfW  d   W W |r|  S S 1 sw   Y  W n1 ty } z%tdt|  tdt| ddd fW  Y d}~W |r|  S S d}~ww W |r|  dS dS |r|  w w )!z4Get all subscriptions for a user with their invoicesr   Tr   ab  
                SELECT 
                    s.id AS subscription_id,
                    s.razorpay_subscription_id,
                    s.status AS subscription_status,
                    s.start_date,
                    s.end_date,
                    s.next_billing_date,
                    p.package_name,
                    p.price,
                    p.billing_cycle,
                    i.id AS invoice_id,
                    i.status AS invoice_status,
                    i.created_at AS invoice_date,
                    u.email,
                    u.firstname,
                    u.lastname
                FROM subscriptions s
                JOIN packages p ON s.package_id = p.id
                LEFT JOIN invoices i ON s.id = i.subscription_id
                JOIN users u ON s.user_id = u.id
                WHERE s.user_id = %s
             AND s.status = %sz. ORDER BY s.start_date DESC, i.created_at DESCNr1   r<   	firstnamelastname)r<   rp   rq   r   subscription_statusrj   rk   next_billing_dater7   r"   r#   )
r1   r   rr   rj   rk   rs   r7   r"   r#   invoicesr8   rt   rl   invoice_date)r8   rl   ru   F)rd   userr      Error fetching subscriptions: r   rH   )r   r   argsrS   r   rJ   appendrK   tuplefetchallrQ   r   listvaluesrM   rc   rZ   r[   )r   rg   Zstatus_filterrJ   ZsqlparamsrecordssubscriptionsZ	user_inforowZsub_idrm   r   r   r   get_user_subscriptionsE  s   



P
L(
P
r   c                 C   s   t  }zzt|jdd}|d| f | }|s5tddddfW  d   W W |r4|  S S |d }|d	 }|rztj	| t
d
|  W n7 tjjyk } zt
dt|  W Y d}~nd}~w ty } zt
dt|  W Y d}~nd}~ww |dt t | f |dt | f |  tddddfW  d   W W |r|  S S 1 sw   Y  W n7 ty } z+|r|  t
dt|  tdt| dddfW  Y d}~W |r|  S S d}~ww W |r|  dS dS |r|  w w )z3Cancel a subscription in both Razorpay and databaseTr   z
                SELECT razorpay_subscription_id, status, user_id
                FROM subscriptions
                WHERE id = %s AND status IN ('active', 'pending')
            z2No active or pending subscription found to cancel.r   r!   Nr   r   z!Cancelled Razorpay subscription: zRazorpay cancellation warning: zRazorpay cancellation error: z
                UPDATE subscriptions 
                SET status = 'canceled', end_date = %s, updated_at = %s
                WHERE id = %s
            z
                UPDATE invoices 
                SET status = 'canceled', updated_at = %s
                WHERE subscription_id = %s AND status IN ('draft', 'unpaid', 'pending')
            z#Subscription canceled successfully.Frw   zError canceling subscription: rH   )r   r   rJ   rK   rL   r   rM   rN   rO   rP   rZ   r-   r_   r`   r[   rc   r   rR   rV   ra   )r1   rg   rJ   rO   Zrazorpay_sub_idZprevious_statusrm   r   r   r   cancel_subscription  s   9

9
3(
9

r   c           
      C   s  t  }zzt|jdd}|d|| f | }|s5tddddfW  d   W W |r4|  S S |d|f | }|D ]}|d	|d
 f | }||d< |d rat|d |d< qB|d
 |d |d |d |d |d |	d|d |d rt|d ndt|d |d |d}t|dddfW  d   W W |r|  S S 1 sw   Y  W n1 t
y }	 z%tdt|	  tdt|	 dddfW  Y d}	~	W |r|  S S d}	~	ww W |r|  dS dS |r|  w w )zBGet detailed subscription information including usage and invoicesTr   a6  
                SELECT s.*, 
                       p.package_name, p.maximum_bookings, 
                       p.price_after_max, p.price, p.currency_id
                FROM subscriptions s
                JOIN packages p ON s.package_id = p.id
                WHERE s.id = %s AND s.user_id = %s
            Subscription not foundr   r!   Na  
                SELECT id, invoice_number, total_amount, status, due_date, issue_date,
                       gateway_order_id, gateway_type
                FROM invoices
                WHERE subscription_id = %s
                ORDER BY issue_date DESC
            a  
                    SELECT id, amount, payment_method, transaction_id, payment_date, status
                    FROM payments
                    WHERE invoice_id = %s
                    ORDER BY payment_date DESC
                    LIMIT 1
                r    Zlatest_paymenttotal_amountr7   r#   r   rj   rk   rs   maximum_bookingsprice_after_maxr"   r   )r1   r7   r#   r   rj   rk   rs   r   r   r"   r   rt   Frd   r   rw   z%Error fetching subscription details: rH   )r   r   rJ   rK   rL   r   rM   r|   rQ   rS   rc   rZ   r[   )
r   r1   rg   rJ   rO   rt   invoicepaymentresponse_datarm   r   r   r   get_user_subscription_details  s   	B

B
>(
B
r   c               
   C   s  t jd} t jjddtd}t jjddtd}t }zzt|jddy}d	}g }| r5|d
7 }||  d| d}||| |	 d }|d7 }|
||d | g ||| | }	|	D ]}
|d|
d f |	 }||
d< |
d rt|
d |
d< qbt|	|||dddfW  d   W W |r|  S S 1 sw   Y  W n1 ty } z%tdt|  tdt| dddfW  Y d}~W |r|  S S d}~ww W |r|  dS dS |r|  w w )z&Get all subscriptions (admin endpoint)r   pager6   )defaulttypelimit
   Tr   a  
                SELECT 
                    s.id, s.user_id, s.package_id, s.status, s.start_date, s.end_date, s.billing_cycle,
                    s.razorpay_subscription_id, s.created_at,
                    p.package_name, p.price,
                    u.email, u.firstname, u.lastname
                FROM subscriptions s
                JOIN packages p ON s.package_id = p.id
                JOIN users u ON s.user_id = u.id
                WHERE 1=1
            ro   zSELECT COUNT(*) as total FROM (z) AS subquerytotalz. ORDER BY s.start_date DESC LIMIT %s OFFSET %sz
                    SELECT id, invoice_number, total_amount, status, issue_date
                    FROM invoices
                    WHERE subscription_id = %s
                    ORDER BY issue_date DESC
                    LIMIT 1
                r    latest_invoicer"   F)rd   r   r   per_pager   rw   Nrx   r   rH   )r   ry   rS   rW   r   r   rJ   rz   rK   rL   extendr|   rQ   r   rM   rc   rZ   r[   )r   r   r   rg   rJ   Z
base_queryr   count_queryr   r   subr   rm   r   r   r   get_all_subscriptions,  sn   
:
6(
:
r   c            
      C   sj  t  } ddg}|D ]}|| vrtd| dddf  S q
t }zz@t|jdd,}|d| d f | }|sXtd	ddd
fW  d   W W |rW|  S S zt	j
| d }|d dkrt }d}|d dkr{|tdd }n|d dkr|tdd }|d|||t | d f |dt | d f |d| d t t|| d f |  tdddddfW W  d   W W |r|  S S td|d  |d dddfW W  d   W W |r|  S S  tjjy) }	 z%tdt|	 dddfW  Y d}	~	W  d   W W |r$|  S S d}	~	w tyZ }	 z%tdt|	 dddfW  Y d}	~	W  d   W W |rU|  S S d}	~	ww 1 s_w   Y  W n: ty }	 z-|ru|  tdt|	  td t|	 dddfW  Y d}	~	W |r|  S S d}	~	ww W |r|  dS dS |r|  w w )!z1Verify Razorpay payment and activate subscription
payment_idr1   r   Tr   r   r   z
                SELECT s.*, p.package_name, p.billing_cycle
                FROM subscriptions s
                JOIN packages p ON s.package_id = p.id
                WHERE s.id = %s
            r   r!   Nr   Zcapturedr#   r$   r'   r(   r%   r*   z
                        UPDATE subscriptions 
                        SET status = 'active', start_date = %s, end_date = %s, 
                            next_billing_date = %s, updated_at = %s
                        WHERE id = %s
                    z
                        UPDATE invoices 
                        SET status = 'paid', updated_at = %s
                        WHERE subscription_id = %s AND status IN ('draft', 'pending', 'unpaid')
                    a  
                        INSERT INTO payments (
                            invoice_id, amount, payment_method, transaction_id, 
                            payment_date, status, gateway_response
                        ) SELECT 
                            i.id, i.total_amount, 'razorpay', %s,
                            %s, 'completed', %s
                        FROM invoices i
                        WHERE i.subscription_id = %s AND i.status = 'paid'
                        ORDER BY i.id DESC LIMIT 1
                    z8Payment verified and subscription activated successfullyF)r   Zpayment_statusr   rw   zPayment not captured. Status: zInvalid payment ID: zPayment verification failed: rH   zPayment verification error: zError verifying payment: )r   rI   r   r   r   rJ   rK   rL   rM   rN   r   fetchr   rR   r   r[   rV   r-   r_   r`   rc   ra   rZ   )
rd   re   rf   rg   rJ   rO   r   rj   rk   rm   r   r   r   verify_payments  s   W

W
W
W
W
Q(
W

r   c              
   C   s:  t  }zzTt|jddB}|d| f | }|D ]}|d r)t|d |d< |d r5t|d |d< qt|dddfW  d	   W W |rN|  S S 1 sRw   Y  W n1 ty } z%t	d
t
|  td
t
| dddfW  Y d	}~W |r|  S S d	}~ww W |r|  d	S d	S |r|  w w )z,Get all invoices for a specific subscriptionTr   aU  
                SELECT 
                    i.*,
                    p.payment_method, p.transaction_id, p.payment_date, p.status as payment_status
                FROM invoices i
                LEFT JOIN payments p ON i.id = p.invoice_id
                WHERE i.subscription_id = %s
                ORDER BY i.issue_date DESC
            r?   r   Fr   rw   NzError fetching invoices: r   rH   )r   r   rJ   rK   r|   rQ   r   rM   rc   rZ   r[   )r1   rg   rJ   rt   r   rm   r   r   r   get_subscription_invoices  sL   

(

r   )NN)r-   r   r   flaskr   r   
contextlibr   confr   r   r	   configfrom_objectr]   ClientRAZORPAY_KEY_SECRETrN   r   rn   r   r   r   r   r   r   r   r   r   r   <module>   s&    
  *ZBKGg