o
    @]gp0                     @   s  d dl mZ d dlZd dl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 d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZmZ d dlmZ d dlmZ defddZ				d(dededeeee	f  dee de dee defddZ!dedededee fddZ"d)dededed ede
e f
d!d"Z#dedededefd#d$Z$d*ded%ee deee	f fd&d'Z%dS )+    )SessionN)datetime)HTTPException)OptionalDictAnyList)Order)	OrderItem)ShoppingCart)CartItem)Product)UserAddress)OrderCreateShippingDetails)point_service)address_servicereturnc                  C   s2   t  d} tt jdd }|  d| S )z:Generate a unique order number based on timestamp and UUIDz%Y%m%dN   -)r   nowstrftimestruuiduuid4int)	timestamp	unique_id r   "/app/app/services/order_service.pygenerate_order_number   s   r    Fdbuser_idshipping_details
address_idsave_addressaddress_titlec                 C   s(  |  ttj|k }|r|jstdddd}g }|jD ]\}	|  ttj|	j	k }
|
s<tdd|	j	 dd|
j
dkrLtdd	|
j d
d|
j|	jk rdtdd|
j d|
j d|	j d|
j|	j }||7 }||
j|	j|
j|d qt| |}||k rtdd| d| d|r|  ttj|ktj|k }|stdd| dd|j|j d|jpd d|j|j|j|jd}|stdddd}|r |r |r |s ddlm} |d dd}|d }t|dkr|d nd}|||d |||d |d |d |d dd	}t | ||}|j}t!|t" ||d |p+|d!}| #| | $  |D ]}t%|j|d" |d# |d$ |d% d&}| #| q9|jD ]}	|  ttj|	j	k }
|
 j|	j8  _qWtj&| |||j'|jd' |jD ]}| (| q| )  | *| |S )(a*  
    Create a new order from the user's shopping cart.
    
    Steps:
    1. Get the user's shopping cart
    2. Check if the cart exists and has items
    3. Check product availability (stock)
    4. Check if user has enough points
    5. Get shipping details (from address_id or directly provided)
    6. If save_address is True, save the shipping details as a new address
    7. Create the order and order items
    8. Update product stock
    9. Deduct points from user's balance
    10. Clear the shopping cart
    11. Return the created order
      zShopping cart is emptystatus_codedetailr   zProduct with ID z
 not found     z	Product 'z' is not available for purchasezNot enough stock for product 'z'. Available: z, Requested: )
product_idquantitypoints_per_itemtotal_pointszNot enough points. Required: z, Available: zAddress with ID ,  )nameaddresscitypostal_codecountryphonezShipping details are requiredN)AddressCreater4   r3   r5   r6   r7   r8   F)	titlerecipient_nameaddress_line1address_line2r5   r6   r7   r8   
is_defaultPENDING)r"   order_numberr0   r#   statusr$   r-   r.   r/   r0   )order_idr-   r.   r/   r0   )r!   r"   amountr@   rB   )+queryr   filterr"   firstitemsr   r   idr-   rA   r3   stockr.   points_requiredappendr   get_user_pointsr   r;   r<   r=   stripr5   r6   r7   r8   app.schemas.user_addressr9   splitlenr   Zcreate_addressr	   r    addflushr
   deduct_points_for_orderr@   deletecommitrefresh)r!   r"   r#   r$   r%   r&   cartr0   Zorder_items_data	cart_itemproductZitem_total_pointsZuser_available_pointsr4   Zsaved_address_idr9   Zaddress_partsr<   r=   Znew_addressZsaved_address	new_orderZ	item_data
order_itemitemr   r   r   create_order_from_cart   s   







	

	
r]   rB   c                 C   sn   |  ttj|ktj|k }|r5|jD ]}|  ttj|jk }|r4|j	|_
|j|_|j|_q|S )z=Get an order by ID, ensuring it belongs to the specified user)rD   r	   rE   rH   r"   rF   rG   r   r-   r3   product_namerJ   product_price	thumbnailproduct_image)r!   rB   r"   orderr\   rY   r   r   r   get_order_by_id   s   

rc   d   skiplimitc                 C   s   |  ttj|ktj ||	 }|D ]$}|j
D ]}|  ttj|jk }|r>|j|_|j|_|j|_q q|S )z"Get all orders for a specific user)rD   r	   rE   r"   order_by
created_atdescoffsetrf   allrG   r   rH   r-   rF   r3   r^   rJ   r_   r`   ra   )r!   r"   re   rf   ordersrb   r\   rY   r   r   r   get_user_orders   s   

rm   c                 C   s   t | ||}|stdddddg}|j|vr(tdd|j dd	| d
dd|_|jD ]}| ttj|j	k
 }|rH| j|j7  _q.d|j }tj| ||jd|d |   | | |S )u   
    주문을 취소하고 관련 처리를 수행합니다.
    
    처리 항목:
    1. 주문 상태를 "CANCELLED"로 변경
    2. 제품 재고 복원
    3. 사용한 포인트 환불
    
    Returns:
        업데이트된 주문 객체
    r'   zOrder not foundr(   r?   
PROCESSINGr,   zCannot cancel order in 'z' status. Only r1   z orders can be cancelled.	CANCELLEDzRefund for cancelled order #etc)r!   r"   rC   transaction_typedescription)rc   r   rA   joinrG   rD   r   rE   rH   r-   rF   rI   r.   r@   r   
add_pointsr0   rU   rV   )r!   rB   r"   rb   Zcancelable_statusesr[   rY   rr   r   r   r   cancel_order   s4   

	
ru   datec                 C   s
  ddl m}m} ddlm}m} |du r| }||| d }||j|j|j	ddd}||dd }||j|j|j	ddd}| 
||tjd	|tjd
|tjdtj||tjdk}| }	|	jprd}
|	jpwd}|	jp|d}|
||||dS )u  
    특정 주(week)의 주문 요약 정보를 제공합니다.
    - 주간 고유 사용자 수
    - 주간 총 주문 건수
    - 주간 총 포인트

    Args:
        db (Session): 데이터베이스 세션
        date (Optional[datetime]): 기준 날짜. 제공되지 않으면 오늘을 기준으로 합니다.

    Returns:
        Dict[str, Any]: 주간 주문 요약 정보를 포함하는 딕셔너리
    r   )funcdistinct)r   	timedeltaN)days      ;   unique_users_countorder_countr0   ro   )r~   r   r0   
start_dateend_date)
sqlalchemyrw   rx   r   ry   r   weekdayyearmonthdayrD   countr	   r"   labelrH   sumr0   rE   rh   betweenrA   rF   r~   r   )r!   rv   rw   rx   r   ry   start_of_weekZend_of_weekrD   resultr~   r   r0   r   r   r   get_weekly_order_summary'  s8   	


r   )NNFN)r   rd   )N)&sqlalchemy.ormr   r   r   fastapir   typingr   r   r   r   Zapp.models.orderr	   Zapp.models.order_itemr
   app.models.shopping_cartr   app.models.cart_itemr   Zapp.models.productr   Zapp.models.user_addressr   app.schemas.orderr   r   app.servicesr   r   r   r    r   boolr]   rc   rm   ru   r   r   r   r   r   <module>   sN    

 7$(3