
    Bi                        d dl mZmZmZmZmZ d dlmZmZ d dl	Z	d dl
Z
d dlZd dlZd dlZd dlZd dlmZmZmZmZ d dlmZ d dlmZmZmZmZ d dlmZ d dlmZmZ  ed	e          Z d
ede!defdZ"dede#fdZ$d Z%d Z& e%            Z' e&            Z(d dl)Z) e)j*        e          Z+e+,                    de	j-        .                    dd           de' de(            e	j-        .                    d          e	j-        .                    d          dddddZ/d Z0d9d Z1d:d!Z2d" Z3e 4                    d#d$g%          d&             Z5e 4                    d'd$g%          d(             Z6e 4                    d)d$g%          d*             Z7e 4                    d+d$g%          d,             Z8e 4                    d-d.g%          d/             Z9d0 Z:e 4                    d1d$g%          d2             Z;e 4                    d3d$g%          d4             Z<e 4                    d5d.g%          d6             Z=e 4                    d7d.g%          d8             Z>dS );    )	Blueprintrequestjsonifysessioncurrent_app)login_requiredcurrent_userN)datetime	timedeltatimezonedate)
monthrange)dbSubscriptionPaymentMethodPaymentStatus)env)parse_mlink_order_user_idresolve_user_refpayments_v2	base_date	start_dayreturnc                     | j         dk    r| j        dz   d}}n| j        | j         dz   }}t          ||          d         }t          ||          }t	          |||          S )uO   base_date 기준으로 +1개월, 시작일의 '일(day)' 유지. 말일 보정.      )monthyearr   minr   )r   r   ymlast_daykeep_days         O/var/www/html/web/mlink/mlink_AI_Server/mlink-backend/src/routes/payments_v2.py_add_one_month_same_dayr%      sl     "~!11~y21 !Q"H9h''H1h    
start_datebilling_cyclec                 N   |dk    rdnd}| j         1|                     t          t          d                              n| }|                    t          t          d                              }|j        }|                                }t          ||          }d}|||fS )u   구독 생성 시 크레딧 관련 필드 계산
    Returns:
        tuple: (prepaid_cycles_remaining, next_credit_date, last_credit_date)
    yearlyr   r   N	   )hours)tzinfo)r-   replacer   r   
astimezonedayr   r%   )	r'   r(   prepaid_cycles_remainingstart_date_kststart_date_localr   start_date_onlynext_credit_datelast_credit_dates	            r$   %_calculate_subscription_credit_fieldsr7      s     &3h%>%>rrA Q[PaPiZ''x	8J8J8J/K/K'LLLoyN%00)!:L:L:L1M1MNN $I&++--O.	JJ #%57GGGr&   c                  h    t           j                            d          } | r| S t          j        rdS dS )u&   프론트엔드 URL 반환 (환경별)	FRONT_URLhttps://mlink.sellmall.co.krzhttp://localhost:3001osenvirongetr   is_production)	front_urls    r$   get_front_urlrA   4   s:    
{++I 
 .--""r&   c                  h    t           j                            d          } | r| S t          j        rdS dS )u    백엔드 URL 반환 (환경별)BACK_URLr:   zhttp://localhost:8011r;   )back_urls    r$   get_back_urlrE   >   s9    z~~j))H 
 .--""r&   u   환경 설정: ENVIRONMENT=ENVIRONMENTdevelopmentz, FRONT_URL=z, BACK_URL=TOSS_API_KEYTOSS_SECRET_KEYz#https://pay.toss.im/api/v2/paymentsz"https://pay.toss.im/api/v2/refundsz!https://pay.toss.im/api/v2/status"https://pay.toss.im/api/v2/execute)api_key
secret_keybase_url
refund_url
status_urlexecute_urlc                    	 |s!t           j                            d           dS t          j        |                    d          |                     d          t          j                                                  }t          j	        ||          }|s%t           j        
                    d| d|            |S # t          $ r:}t           j        
                    dt          |                      Y d}~dS d}~ww xY w)	u    토스페이먼츠 서명 검증u@   TOSS_SECRET_KEY가 설정되지 않음 - 서명 검증 건너뜀Tzutf-8u2   토스페이먼츠 서명 검증 실패: expected=z, received=u)   토스페이먼츠 서명 검증 오류: NF)r   loggerwarninghmacnewencodehashlibsha256	hexdigestcompare_digesterror	Exceptionstr)payload	signaturerL   expected_signatureis_valides         r$   verify_toss_signaturerc   Z   s.    	&&'ijjj4 "Xg&&NN7##N
 
 )++	 	 &y2DEE 	F$$  &EZl  &E  &E  zC  &E  &E  F  F  F     !USQRVV!U!UVVVuuuuus   !B; BB; ;
C?/C::C?c                    	 | s|sdS t          j        t          d         ddit          d         | |dd          }|j        d	k    r:|                                }t
          j                            d
|            |dfS d|j         d|j         }t
          j        	                    |           d|fS # t          $ r?}dt          |           }t
          j        	                    |           d|fcY d}~S d}~ww xY w)u5   토스페이먼츠 결제 상태 조회 공통 함수)Nu*   payToken 또는 orderNo가 필요합니다rO   Content-Typeapplication/jsonrK   )apiKeypayTokenorderNo
   headersjsontimeout   u)   토스페이먼츠 상태 조회 성공: Nu)   토스페이먼츠 상태 조회 실패:  - u-   토스페이먼츠 상태 조회 중 오류: )requestspostTOSS_CONFIGstatus_coderm   r   rR   infotextr[   r\   r]   )	pay_tokenorder_nostatus_responsestatus_data	error_msgrb   s         r$   fetch_toss_statusr|   u   sN    	F 	FEE"-%#%78%i0%# 
 	
 	
 	
 &#--)..00K##$]P[$]$]^^^$$zOD_zzdsdxzzI$$Y///?"   LCFFLL	  +++Ys)   B6 A8B6 4B6 6
C? 4C:4C?:C?c                    	 t          |           \  }}|rd|fS |                    d          p|                    d          }t          |                    d          p|                    d          pd          }t          j                            d| d	|            |d
k    rH|dk    r|n|}| ||dd}t          |          }	|	r$t          j                            d|            dS dS t          j                            d|            dd| fS # t          $ r?}
dt          |
           }t          j        
                    |           d|fcY d}
~
S d}
~
ww xY w)u5   토스페이먼츠 결제 성공 처리 공통 함수rw   F	payStatusstatusamount	payAmountr   u%   토스페이먼츠 상태: payStatus=	, amount=PAY_COMPLETEDONE
paymentKeyorderIdr   r   u0   토스페이먼츠 결제 성공 처리 완료: )TN)Fu   구독 생성 실패u5   토스페이먼츠 상태가 PAY_COMPLETE가 아님: u   결제 미완료: u4   토스페이먼츠 결제 성공 처리 중 오류: N)r|   r>   intr   rR   ru   create_toss_subscriptionrS   r\   r]   r[   )rw   order_idr   rz   r[   
pay_statuspaid_amountactual_amountpayment_resultsuccessrb   r{   s               r$   process_toss_payment_successr      s   % .CCCU 	 %< !__[11N[__X5N5N
+//(33X{{7S7SXWXYY j
 j j]h j jkkk''+6??KKM (#' 	 N /~>>G 5"''(e[c(e(efff!z44&&'k_i'k'klll;z;;;;      S3q66SS	  +++i s)   D CD 1(D 
E#$4EE#E#c                     t          j                    }| dk    r|t          d          z   S | dk    r|t          d          z   S |t          d          z   S )u8   결제 주기에 따른 종료일 계산 (오늘 제외)monthly   daysr*   il  )r
   nowr   )r(   r   s     r$   calculate_end_dater      se    
,..C	!!YB'''''	(	"	"YC(((((YB'''''r&   z/api/v2/payments/toss/preparePOST)methodsc                  :	   	 t          j        d          } | st          ddd          dfS t          j                    }|                    d          }|                    d          }|                    d          }|                    d	          }t          ||||g          st          d
di          dfS t          |t                    r|dk    rt          d
di          dfS d|  dt          j	                    j
        dd          d| d| dt          t          j                                                               
}ddi}t          |dz            }||z
  }	||d||	|t          d         dddt           d| dt            d| d}
	 t#          j        t          d         ||
d           }t&          j                            d!|j         d"|j                    |j        d#k    r|                                }|                    d$          }t&          j                            d%| d&|            t&          j                            d'| d(| d)|	 d*           	 dd+lm} dd,lm} d-} |rt;          |          }|r|}  || d|||t<          j        d.||||t          j                    /          }t@          j         !                    |           t@          j         "                                 t&          j                            d0|j#         d&|            nF# tH          $ r9}t&          j        %                    d1tM          |                      Y d}~nd}~ww xY wt          |||||                    d2d3          dd4          S t&          j        '                    d5|j         d"|j                    t          d6| |||d3dd4          S # t"          j(        j)        $ rQ}t&          j        '                    d7tM          |                      t          d6| |||dd8          cY d}~S d}~ww xY w# tH          $ rL}t&          j        %                    d9tM          |                      t          d
d:i          d;fcY d}~S d}~ww xY w)<u4   토스페이먼츠 결제 준비 - 결제 키 생성user_idF   로그인이 필요합니다.r   r[     
product_idproduct_namer   r(   r[   u'   필수 정보가 누락되었습니다.  r   u$   유효하지 않은 금액입니다.mlink__N   re   rf   皙?rK   Tz*https://pay.toss.im/payfront/demo/callbackV2z&/api/v2/payments/toss/success?orderno=z&status=PAY_COMPLETEuX   /payment/fail?code=PAY_PROCESS_CANCELED&message=결제가 취소되었습니다&orderId=)ri   r   amountTaxFreeamountTaxable	amountVatproductDescrg   autoExecuteresultCallbackcallbackVersionretUrlretCancelUrlrM   rj   rk   u   토스페이먼츠 API 응답: rp   ro   rh   u)   토스페이먼츠 결제 준비 완료: z - payToken: u   세금 정보 - 총액:    원, 과세:    원, 부가세:    원PaymentHistorySubscriptionStatus1toss_payments)r   subscription_idpayment_keyr   r   r   payment_methodr   r   product_pricer(   
created_atu&   임시 payment_history 생성 완료: u&   임시 payment_history 생성 실패: checkoutPage )r   r   r   	orderNamepayUrl
simulationuB   토스페이먼츠 API 오류 - 시뮬레이션 모드로 동작: sim_payment_key_uI   토스페이먼츠 API 호출 실패 - 시뮬레이션 모드로 동작: )r   r   r   r   r   u)   토스페이먼츠 결제 준비 실패: u/   결제 준비 중 오류가 발생했습니다.  )*r   r>   r   r   get_jsonall
isinstancer   uuiduuid4hexr
   r   	timestamprs   rC   r9   rq   rr   r   rR   ru   rt   rv   rm   src.models.paymentr   src.models.subscriptionr   r   r   PENDINGr   addcommitidr\   r[   r]   rS   
exceptionsRequestException)r   datar   r   r   r(   r   rl   amount_taxable
amount_vatpayment_dataresponseresultrw   r   r   parsedtemp_payment_historyrb   s                      r$   prepare_toss_paymentr      sI   CZ+i(( 	^u7VWWXXZ]]]!!XXl++
xx//(##11 JfmDEE 	VG%NOPPRUUU &#&& 	S&A++G%KLMMsRR xGwwdjll&6rr&:wwVwwmwwVYZbZfZhZhZrZrZtZtVuVuww .

 Vc\**n,
  +#'!),J#!ggggg(  M  M  CK  M  M
 
 O	}J'!	  H ##$nhFZ$n$n_g_l$n$nooo#s**!"JJz22	"''(vT\(v(vkt(v(vwww"''  )H6  )H  )HXf  )H  )H  yC  )H  )H  )H  I  I  I`AAAAAAJJJJJJ "G -!:8!D!D! -&,G ,:> '(,$-!)%,4'6#-%1&,&3#+<>>, , ,( JNN#7888J%%'''&++  -GUiUl  -G  -G  |E  -G  -G  H  H  H  H  ` ` `&,,-^VYZ[V\V\-^-^________` "+'$!-$jj<<"'       "**  ,Ypx  qE  ,Y  ,Y  JR  JW  ,Y  ,Y  Z  Z  Z"?X"?"?'$!- "&       "3 	 	 	&&'{svwxsysy'{'{|||;;;# )"         	  Z Z Z  !USQRVV!U!UVVV!RSTTVYYYYYYYYZs   )Q BQ 9-Q 'B)Q CO 'B<L$ #O $
M'./M"O "M'',O AO Q0AP<6Q7Q <QQ 
RARRRz/api/v2/payments/toss/callbackc                     	 t           j                            d          pt           j                            d          } | rt          j        d          }t	          || t
          d                   s2t          j                            d           t          ddi          d	fS t          j        
                    d
           nt          j                            d           t          j                    }t          j        
                    d|            |                    d          }|                    d          }|                    d          }|                    d          }|dk    r|rt          |||          \  }}|r4t          j        
                    d|            t          ddd          S t          j                            d|            	 t          |||dd           t          ddd          S # t          $ rM}	t          j                            dt!          |	                      t          d|d          dfcY d}	~	S d}	~	ww xY wt          j                            d|            t          ddd          S # t          $ rL}
t          j                            dt!          |
                      t          dd i          dfcY d}
~
S d}
~
ww xY w)!u.   토스페이먼츠 결제 완료 콜백 처리X-Toss-SignatureX-SignatureTas_textrL   u.   토스페이먼츠 콜백 서명 검증 실패r[   Invalid signaturer   u.   토스페이먼츠 콜백 서명 검증 성공u=   토스페이먼츠 콜백 서명이 없음 - 검증 건너뜀u"   토스페이먼츠 콜백 수신: ri   r   rh   r   r   u)   토스페이먼츠 콜백 처리 완료: u   결제 완료 처리됨)r   messageu)   토스페이먼츠 콜백 처리 실패: r   r   u"   결제 완료 처리됨 (fallback)u   콜백 fallback 처리 실패: Fr   r   Nu    결제 미완료 또는 오류: u   결제 미완료u/   콜백 처리 중 오류가 발생했습니다.)r   rl   r>   get_datarc   rs   r   rR   r[   r   ru   rS   r   r   r   r\   r]   )r_   r^   r   r   r   rw   r   r   r[   fallback_errorrb   s              r$   toss_payment_callbackr   T  s2   0ZO''(:;;aw?R?RS`?a?a	 	h&t444G()[=VWW D"(()YZZZ)<=>>CC##$TUUUU&&'fggg!! KT K KLLL 88I&&(##HHZ((	(##^###9)XvVVNGU L"''(^T\(^(^___4<UVVWWW"(()\UZ)\)\]]]
L,&/#+"("(	. .    #t@d#e#efff  L L L&,,-dsSaObOb-d-deee"uu#E#EFFKKKKKKKL &&'P$'P'PQQQu9KLLMMM Z Z Z  !USQRVV!U!UVVV!RSTTVYYYYYYYYZsW   B"J %DJ ?"J "%H 
IAIIJ I6J 
K, AK'!K,'K,z/api/v2/payments/toss/webhookc                  0   	 t           j                            d          pt           j                            d          } | s2t          j                            d           t          ddi          dfS t          j        d          }t          || t          d	                   s2t          j                            d
           t          ddi          dfS t          j        
                    d           t          j                    }t          j        
                    d|            |                    d          }|                    d          }|                    d          }|                    d          }|dk    r|rt          |||          \  }}|r5t          j        
                    d|            t          ddi          dfS t          j                            d|            t          d|i          dfS t          j        
                    d| d|            t          ddi          dfS # t          $ rL}	t          j                            dt          |	                      t          ddi          dfcY d}	~	S d}	~	ww xY w)u7   토스페이먼츠 웹훅 처리 (서명 검증 포함)r   r   u*   토스페이먼츠 웹훅 서명이 없음r[   zMissing signaturer   Tr   rL   u.   토스페이먼츠 웹훅 서명 검증 실패r   u.   토스페이먼츠 웹훅 서명 검증 성공u"   토스페이먼츠 웹훅 수신: ri   r   rh   r   r   u)   토스페이먼츠 웹훅 처리 완료: r   ro   u)   토스페이먼츠 웹훅 처리 실패: r   u)   토스페이먼츠 웹훅 무시: status=z, order_id=ignoredu-   토스페이먼츠 웹훅 처리 중 오류: zWebhook processing errorN)r   rl   r>   r   rR   r[   r   r   rc   rs   ru   r   r   r\   r]   )
r_   r^   r   r   r   rw   r   r   r[   rb   s
             r$   toss_payment_webhookr     s   'CO''(:;;aw?R?RS`?a?a	 	@$$%QRRRG%89::C?? "4000$Wi\9RSS 	@$$%UVVVG%89::C?? PQQQ!! KT K KLLL 88I&&(##HHZ((	(##^###9)XvVVNGU 6"''(^T\(^(^___)455s::"(()\UZ)\)\]]]/00#55##$mPV$m$mck$m$mnnnHi011366 C C C  !YQTUVQWQW!Y!YZZZ!;<==sBBBBBBBCs9   A1H? 4A"H? C:H? 4H? 7H? ?
J	AJ
JJz)/api/v2/payments/toss/create-subscriptionc                  f   	 t          j                    } |                     d          }|                     d          }t          j                            d| d|            |r|st          ddi          dfS t          ||          \  }}|rt          dd	||d
          S t          j                            d|            t          d|d          dfS # t          $ rL}t          j                            dt          |                      t          ddi          dfcY d}~S d}~ww xY w)u6   토스페이먼츠 결제 완료 후 구독 생성 APIrh   r   u2   토스페이먼츠 구독 생성 요청: payToken=z
, orderId=r[   u'   payToken과 orderId가 필요합니다.r   Tu0   구독이 성공적으로 생성되었습니다.)r   r   rh   r   u   구독 생성 실패: Fr   )   토스페이먼츠 구독 생성 실패: u/   구독 생성 중 오류가 발생했습니다.r   N)r   r   r>   r   rR   ru   r   r   r[   r\   r]   )r   rw   r   r   r[   rb   s         r$   create_toss_subscription_apir     s   Z!!HHZ((	88I&& tU^ t tjr t tuuu 	V 	VG%NOPPRUUU 6iJJ 	M%#	     $$%Ee%E%EFFF      
  Z Z Z  !USQRVV!U!UVVV!RSTTVYYYYYYYYZs+   A8C ;(C $5C 
D0$AD+%D0+D0z/api/v2/payments/toss/successGETc                  
   	 t          j        d          } | st          ddd          dfS t          j                            d          }t          j                            d          }t          j                            d          }t
          j                            d	| d
| d|            t          |          o|	                    d          pd|v }|s	 ddl
m} |j                            |t          j        |                                           }|r1|j        r*|j        }t
          j                            d|            n&t
          j                            d|            	 	 d7S nJ# t&          $ r=}t
          j                            dt)          |                      	 	 d8cY d}~S d}~ww xY wt+          |          \  }}	|r9t-          |                    d          p|                    d          pd          nd}
|r	 ddl
m}m} |j                            ||j                                                  }|rm|j        |_        t3          j                    |_        t8          j                                          t
          j                            d|j         d|
            n"t
          j                            d |            	 dd!l m!}  ||||
"           t
          j                            d#           n9# t&          $ r,}t
          j                            d$|            Y d}~nd}~ww xY wnF# t&          $ r9}t
          j                            d%t)          |                      Y d}~nd}~ww xY wd&|
d'd(| d)| d*|
 d+tD           d,S tG          ||          \  }}|rd}	 ddl
m}m} |j                            ||j                                                  }|r-tI          |d-          r|j%        rt-          |j%        pd          }nH# t&          $ r;}t
          j                            d.t)          |                      d}Y d}~nd}~ww xY wd/|
d'd0| d)| d*|
 d1| d+tD           d,S t
          j                            d2|            d3| d4dfS # t&          $ r=}t
          j                            d5t)          |                      	 	 d9cY d}~S d}~ww xY w):uN   토스페이먼츠 결제 성공 페이지 - payToken 조회 후 구독 생성r   Fr   r   r   ordernorh   r   u<   토스페이먼츠 결제 성공 페이지 접근: order_id=z, payToken=z	, status=mlink_usage__usage_r   r   )r   r   r   u)   payment_histories에서 payToken 조회: u*   payToken을 찾을 수 없음 - order_id:   
                    <!DOCTYPE html>
                    <html>
                    <head>
                        <title>결제 오류</title>
                    </head>
                    <body>
                        <h1>결제 정보를 찾을 수 없습니다.</h1>
                        <p>고객센터에 문의해주세요.</p>
                    </body>
                    </html>
                    r   u   payToken 조회 실패: {  
                <!DOCTYPE html>
                <html>
                <head>
                    <title>결제 오류</title>
                </head>
                <body>
                    <h1>결제 처리 중 오류가 발생했습니다.</h1>
                    <p>고객센터에 문의해주세요.</p>
                </body>
                </html>
                r   Nr~   r   r   r   r   )r   r   u1   [Settlement] PENDING → COMPLETED 갱신: ph_id=r   u,   [Settlement] PENDING PH 미발견: order_id=)finish_settlement_then_refund)r   rw   r   uC   [Settlement] 사가 트리거 완료: finish_settlement_then_refundu&   [Settlement] 사가 트리거 실패: u   [Settlement] 처리 실패: u   
            <!DOCTYPE html>
            <html>
            <head><title>정산 결제 완료</title></head>
            <body>
                <h1>정산 결제가 완료되었습니다.</h1>
                <p>결제 금액: ₩,u   원</p>
                <script>
                    if (window.opener) {
                        window.opener.postMessage({
                            type: 'SETTLEMENT_SUCCESS',
                            orderId: 'z*',
                            payToken: 'z'',
                            amount: z
                        }, '*');
                        window.close();
                    } else {
                        window.location.href = 'zn/mypage';
                    }
                </script>
            </body>
            </html>
            carryover_credit_dayszcarryover days lookup failed: u   
            <!DOCTYPE html>
            <html>
            <head>
                <title>결제 완료</title>
            </head>
            <body>
                <h1>결제가 완료되었습니다.</h1>
                <p>결제 금액: ₩u   원</p>
                <script>
                    if (window.opener) {
                        window.opener.postMessage({
                            type: 'PAYMENT_SUCCESS',
                            orderId: 'z*,
                            creditDays: u   결제 성공 처리 실패: u   
            <!DOCTYPE html>
            <html>
            <head>
                <title>결제 오류</title>
            </head>
            <body>
                <h1>결제 처리 중 오류가 발생했습니다.</h1>
                <p>오류: ut   </p>
                <p>고객센터에 문의해주세요.</p>
            </body>
            </html>
            u:   토스페이먼츠 결제 성공 페이지 처리 실패: #  
        <!DOCTYPE html>
        <html>
        <head>
            <title>결제 오류</title>
        </head>
        <body>
            <h1>결제 처리 중 오류가 발생했습니다.</h1>
            <p>고객센터에 문의해주세요.</p>
        </body>
        </html>
        )r   r   )r   r   )r   r   )&r   r>   r   r   argsr   rR   ru   bool
startswithr   r   query	filter_byr   r   firstr   r[   r\   r]   r|   r   	COMPLETEDr   r
   r   
updated_atr   r   r   rS    src.services.cancel_orchestratorr   r9   r   hasattrr   )r   r   rw   r   is_settlementr   payment_historyrb   rz   r   r   PHStatusphr   saga_errr   r[   carryover_daystemp_phs                      r$   toss_payment_successr    s   u+i(( 	^u7VWWXXZ]]]<##I..L$$Z00	!!(++  !Q_g  !Q  !Qt}  !Q  !Q  IO  !Q  !Q  	R  	R  	R XiH,?,?,O,O,hS\`hSh  (	'======"0"6"@"@%(0# #A # # %''	   # 'B  / ;I&++,cXa,c,cdddd&,,-dZb-d-deee   e     "(()LCFF)L)LMMM         +Y???Q]hoc+//(33X{{7S7SXWXYYYno  /	RXXXXXXXX#)33XhN^3__eegg j ( 2BI$,LNNBMJ%%'''&++,}`b`e,},}p{,},}~~~~&../h^f/h/hiiib^^^^^^118yalmmmm&++,qrrrr  b b b&,,-`V^-`-`aaaaaaaab  R R R"(()PA)P)PQQQQQQQQR
 '2   (0  )2  &1 " 2;#   2 6iJJ 4	N#XXXXXXXX(.88(S[Sc8ddjjll Mww0GHH MWMj M%()F)K!%L%LN # # #"(()R#a&&)R)RSSS!"# '2   (0  )2  &1   *8! ( 2;)   6 $$%LU%L%LMMM "          !f^abc^d^d!f!fggg  	 	 	 	 	 	s   )R< B/R< BE5 4R< 5
F<?2F71F<2R< 7F<<AR< CM  3L M 
M
"M M M

M R< 
N/NR< NR< ,R< A*P/ .R< /
Q491Q/*R< /Q44R< )R< <
T2S>8T>Tc                 B   	 ddl m}m} ddlm} t
          j                            d|             |                     d          }|                     d          }|                     d          }|                     dd	          }t          j
                            |j        |j        |j        |j        |j        |j        |j                                      |j        |k    |j        |j        k                                              }d}		 t          j
                            |j                                      |j        |k    |j        |j        k                                              }
|
r|
d         rt1          |
d         pd          }	nH# t2          $ r;}t
          j                            d
t7          |                      d}	Y d}~nd}~ww xY w|r9|\  }}}}}}}t
          j                            d| d| d| d| d| 
           n-d}d}|}d}d}d}d}t
          j                            d           |r|}nd}|rd|v r~	 |                    d          }t;          |          dk    r|d         }|dv r|}nF# t2          $ r9}t
          j                            dt7          |                      Y d}~nd}~ww xY wt<          j                            ||j                                                   }d }|rtt
          j                            d|j!                    |	dk    rt
          j                            d|	            tE          j#                    }||_$        ||_%        |} ||tM          d !          z
  |          }|tM          |	!          z   }t
          j                            d"|j$         d#| d$|            nMt
          j                            d%|j!                    |j$        }|tM          d !          z   } |||          }|	dk    r||_        tN          j(        |_)        ||_*        tW          |          |_,        t7          |          |_        ||_-        ||_$        ||_.        tE          j#                    |_%        t_          ||          \  }}}||_0        ||_1        ||_2        |}n/||_        ||_$        ||_.        tE          j#                    |_%        |}|dk    rd&nd'}  |dJi d(|d)|j!        d*|d+|d|d|j3        d,d-d.|d/|d0|d1|d2| |	z   d3|d4|d5|d6|d7tE          j#                    }!t          j
        4                    |!           ntE          j#                    }" ||"tM          d !          z
  |          }#|	dk    r|#tM          |	!          z   }#t_          |"|          \  }}}t=          |||j         tN          j(        |tW          |          t7          |          |"|#|#|||tE          j#                    tE          j#                    8          }t          j
        4                    |           |dk    rd&nd'}  |dJi d(|d)dd*|d+|d|d|j3        d,d-d.|d/|d0|d1|d2| |	z   d3|"d4|#d5|d6|d7tE          j#                    }!t          j
        4                    |!           t          j
        5                                 |j!        |!_6        	 dd9l7m8}$ ts          |          }%|%rd:|%_:        nF# t2          $ r9}t
          j                            d;t7          |                      Y d}~nd}~ww xY wt          j
        ;                                 	 dd<l7m8}$m<}& dd=l=m>}' ts          |j                  }(|(r|(j?        |&j@        k    r |'|j        |j!                  })|)d>         r1t
          j                            d?|j         d@|)dA                     n5t
          j                            dB|)                    dC                      nF# t2          $ r9}t
          j        A                    dDt7          |                      Y d}~nd}~ww xY wt
          j                            dE|j!         dF| d|	            dGS # t2          $ rX}t
          j        A                    dHt7          |                      t          j
        B                                 Y d}~dIS d}~ww xY w)Ku9   토스페이먼츠 결제 성공 시 구독 생성/연장r   r   r   u)   토스페이먼츠 구독 생성 시작: r   r   r   r   r   u   carryover days 조회 스킵: Nu   PENDING PH 추출: product_id=z, name=z, price=z, cycle=z, carryover_days=M   Basicr   u2   PENDING PaymentHistory 없음 — 기본값 사용r   r   r      )r   r*   u-   주문 ID에서 billing_cycle 추출 실패: )r   r   c                 <    |dk    rdnd}| t          |          z   S )Nr      m  r   )r   )base_dtcycler   s      r$   _add_cycle_daysz1create_toss_subscription.<locals>._add_cycle_days  s+    )++22DYD11111r&   u$   기존 활성 구독 처리: sub_id=u%   플랜 변경 감지: carryover_days=r   r   u'   플랜 변경: 기존 구독 종료일=u   , 새 플랜 시작일=u   , 새 플랜 종료일=u   기간 연장: sub_id=r  r  r   r   r   r   r   r   r   r   r   r(   subscription_dayssubscription_start_datesubscription_end_dater   carryover_credit_amountr   )r   r   r   r   
payment_idr   r(   r'   end_datenext_billing_dater1   r5   r6   r   r  )Userrole_prou$   역할 업데이트 실패(무시): )r  SubscriptionType)renew_subscription_creditsr   u(   구독 크레딧 추가 완료: user_id=z, added=addedu    구독 크레딧 추가 실패: r[   u-   구독 크레딧 추가 중 오류 (무시): u$   구독 생성/연장 완료: sub_id=z
, user_id=Tr   F )Cr   r   r   r   r   r   rR   ru   r>   r   r   r   r   r   r   r(   r  r   r   filterr   r   r   r   r   r\   rS   r]   splitlenr   r   ACTIVEr   r
   r   r  r  r   r   TOSS_PAYMENTSr   r  floatr   r'   r  r7   r1   r5   r6   r   r   flushr   src.models.userr  r   roler   r   src.utils.credit_managerr!  subscription_typeCREDITr[   rollback)*r   r   r  r   r   r   r   r   ph_rowr	  	carry_rowrb   r   r   r   ph_cycler  r   r   r(   partsmaybe_cycleexistingr  todaynew_start_datenew_end_datecurrent_endr1   r5   r6   subscriptionr  r  r'   r  r  ur   r!  usercredit_results*                                             r$   r   r     s9   APPPPPPPP>>>>>> 	 \N \ \]]] %((66$((33$((22$((6:: *"""-"/"0"0":"8"*  6.1X=(/83CCE E577 	 
	)).*NOO &!8H!D!/!6(:J!JL L%''   8Yq\ 8!$Yq\%6Q!7!7 	 	 	&&'PA'P'PQQQNNNNNN	
  	]yvJmX?VXmov## d  d  dL  d  dZg  d  dqy  d  d  Mb  d  d   
 J"L"MH$%!&'#G&&'[\\\  	i$MM%M iH00i$NN3//E5zzQ&+Dk&*???,7M  i i i&../g_bcd_e_e/g/ghhhhhhhhi  %//%, 0 
 
 %'' 		2 	2 	2
  P	\##$X8;$X$XYYY!!"''(`P^(`(`aaa  %*!&+# "'.uya7H7H7H/H-XX  ,i^.L.L.LL"''  )rRZRc  )r  )r  }K  )r  )r  dp  )r  )r  s  s  s  s "''(N(N(NOOO&/!,ya/@/@/@!@.{MJJ !!&0#*7*E'&1#"'--),]););&&4#$0!-9*&.lnn#Ot"MP PL(*:<L 5M1,<),<)' '1#$0!-9*&.lnn#' '4y&@&@c    , (K "	
 v  ))  / &: *\ ,m ,m #4n"D"D )7 '3l '<&;  )@(?!" $<>>>#B& JNN2 "J(iQ6G6G6G)GWWH!!#i^&D&D&DD LqML LH$&68H (%)0,:&V}}!-00%!"*)A!1!1#<>>#<>>  L" JNN<((( '4y&@&@c    $ (K "	
 v  ))  / &: *\ ,m ,m #4n"D"D )3
 '/h '<&;  )@(?!" $<>>>#B& JNN2J!-B\000000$W-- ('AF \ \ \"**+ZRUVWRXRX+Z+Z[[[[[[[[\ 	
	_>>>>>>>>KKKKKK#L$899D p.2B2III : :<;OQ]Q` a a + p&++  -NWcWk  -N  -N  vC  DK  vL  -N  -N  O  O  O  O&../nR_RcRcdkRlRl/n/nooo 	_ 	_ 	_$$%]UXYZU[U[%]%]^^^^^^^^	_ 	  !M|  !M  !Mbi  !M  !M  }K  !M  !M  	N  	N  	Nt     !USQRVV!U!UVVV

uuuuus   Db< BF b< 
G1Gb< GA8b< 6J b< 
K
/K b< K

P?b< 
\) (b< )
],3/]'"b< '],,!b< B8a b< 
b
/b b< b

0b< <
dAddz/api/v2/payments/refundc            
         	 t          j                    } |                     d          }|                     d          }|                     dd          }|r|st          ddd          dfS d	d
l}d |j                    j        d
d          }t          |dz            }||z
  }t          d         |||d	||d	|d	}t          j
        t          d         ddi|          }	|	j        dk    ru|	                                }
t          j                            d|
            t          j                            d| d| d| d           t          d||||dd          S t          j                            d|	j         d|	j                    t          dd|	j         d          dfS # t$          $ rM}t          j                            d t'          |                      t          dd!d          d"fcY d
}~S d
}~ww xY w)#u    토스페이먼츠 환불 처리rh   r   reasonu   반품 취소Fu-   payToken과 환불 금액이 필요합니다.r   r   r   Nrefund_   r   rK   )	rg   rh   refundNor   r   r   r   amountServiceFeer@  rN   re   rf   )rl   rm   ro   u"   토스페이먼츠 환불 성공: u   환불 세금 정보 - 총액: r   r   r   Tu0   환불이 성공적으로 처리되었습니다.)r   	refund_nor   r   r   r   u"   토스페이먼츠 환불 실패: rp   u   환불 처리 실패: u)   토스페이먼츠 환불 처리 실패: u/   환불 처리 중 오류가 발생했습니다.r   )r   r   r>   r   r   r   r   r   rs   rq   rr   rt   rm   r   rR   ru   r[   rv   r\   r]   )r   rw   refund_amountr@  r   rE  refund_amount_taxablerefund_amount_vatrefund_datar   r   rb   s               r$   refund_paymentrJ    s   A!!HHZ((	**(O44 	 	 H      	5jdjll.ss355	 !$MC$7 8 8),AA "),!!#2* !

 

 =%#%78
 
 
 3&&]]__F##$Q$Q$QRRR##  %`m  %`  %`bw  %`  %`  J[  %`  %`  %`  a  a  a&'"7/M     $$%r(J^%r%rckcp%r%rsss A(-AA     
      !USQRVV!U!UVVVF
 
    	 	 	 	 	 	s-   A*F- -C4F- "A
F- -
H7AG?9H?Hz/api/v2/payments/toss/executec                     t          j                    } |                     d          }|st          ddi          dfS t	          j        dddit          d         |d	d
          }t          j        	                    d|j
         d|j                    |j
        dk    rt          d|j        d          dfS |                                }t          d|d          S )ur   
    결제 승인(Execute): PAY_APPROVED 상태의 결제건을 최종 승인.
    req: { payToken: string }
    rh   r[   u   payToken이 필요합니다.r   rJ   re   rf   rK   )rg   rh   rj   rk   zExecute resp:  ro   u   승인 실패)r[   rawT)r   r   )r   r   r>   r   rq   rr   rs   r   rR   ru   rt   rv   rm   )r   rw   rr   s       r$   execute_toss_paymentrO    s     D$$I G!?@AA3FF,!34!),!
 
 	 	 	A EQ]EEQVEEFFF}@@AA3FFVVXXFtv66777r&   z/api/v2/payments/toss/statusc                  Z   t           j                            d          pt           j                            d          } t           j                            d          }|s| st          ddi          dfS t	          ||           \  }}|rt          d|i          dfS t          |          S )uB   토스페이먼츠 결제 상태 조회 API (공통 함수 사용)ri   r   rh   r[   u   payToken 또는 orderNo 필요r   rw   rx   r   r   r>   r   r|   )rx   rw   rz   r[   s       r$   status_toss_paymentrS    s     |	**Igl.>.>y.I.IH  ,,I IX I!ABCCSHH +YRRRK .'((#--;r&   z/api/payments/statusc                  $   t           j                            d          p=t           j                            d          pt           j                            d          } t           j                            d          }| s|st          ddd          dfS t	          || 	          \  }}|rt          d|d          d
fS |pi                     d          p|pi                     d          }d}|dk    rd}n|dv rd}t          d|d          d
fS )u   
    프론트 레거시 호환:
    /api/payments/status?orderId=... -> { success: bool, status: 'COMPLETED'|'PENDING'|'FAILED' }
    r   r   ri   rh   Fu   orderId 또는 payToken 필요r   r   rQ  ro   r   r   r   r   r   )
PAY_CANCELCANCELEDFAILEDFAILrW  T)r   r   rR  )r   rw   r   errpay_statmappeds         r$   legacy_status_aliasr\    s1    |	**hgl.>.>y.I.IhW\M]M]^gMhMhH  ,,I [I [53STTUUWZZZ!IIIIID#
 >537788#==
,,J0@0@0J0JHF>!!	A	A	Atv6677<<r&   )NN)N)?flaskr   r   r   r   r   flask_loginr   r	   r<   r   rq   base64rT   rW   r
   r   r   r   calendarr   r   r   r   r   r   src.config.env_loaderr   src.utils.user_refr   r   __name__payments_v2_bpr   r%   r]   r7   rA   rE   r9   rC   logging	getLoggerrR   ru   r=   r>   rs   rc   r|   r   r   router   r   r   r   r  r   rJ  rO  rS  r\  r#  r&   r$   <module>rh     s   C C C C C C C C C C C C C C 4 4 4 4 4 4 4 4 				      8 8 8 8 8 8 8 8 8 8 8 8       R R R R R R R R R R R R % % % % % % J J J J J J J J=(33 t            Hh Hs H H H H*# # ## # # MOO	<>> 		8	$	$   E"*..*V*V  E  Edm  E  E  {C  E  E  F  F  F z~~n--*..!2335657   6   >'  '  '  ' R	( 	( 	( 5xHHEZ EZ IHEZN 6II2Z 2Z JI2Zh 5xHH)C )C IH)CV AF8TTZ Z UTZB 5wGGw w HGwrC C CP /&BBC C CBCP 5xHH8 8 IH8< 4ugFF    GF   ,ug>>= = ?>= = =r&   