본문 바로가기
Programming/Django

[게르만 민족 프로젝트]Django로 카카오페이 API 사용하기2

by IN.0 2020. 6. 10.
728x90
반응형

프로젝트를 어느 정도 진행한 후 지난번에 작성한 카카오페이 API 사용 후기와 달라진 점이 많아서

2탄을 만들었다

 

지난번 게시글 ↓

https://in0-pro.tistory.com/16

 

[게르만 민족 프로젝트]Django로 카카오페이 API 사용하기

SSAFY 스터디원들과 Django 토이 프로젝트 배달 웹을 만들어보기로 했다. 총 4명이 진행하며, 각자 역할은 사다리 타기로 정했다. 나는 결제 관련 구현을 담당하게 되었다. 수업 중에 공공 API 맛보기

in0-pro.tistory.com

 

 


1. 원래 kakaopay 앱 안에 index에 있던 내용을 shopping 앱 안에 show_cart로 옮겼다.

 

그리고, 코드도 많은 부분 수정되었다.

@login_required
def show_cart(request):
    User = get_user_model()
    user = get_object_or_404(User, pk=request.user.pk)
    current_site = request.build_absolute_uri()[:-10]
    cart = Cart(request.session)
    cnt = 0
    cart_item = 'none'
    status = 0
    store_pk = -1
    location = ''
    store = ''
    for item in cart.items:
        cnt += 1
        if cnt == 1:
            cart_item = '{}'.format(item.product.menu_name)
            status = 1

            store_pk = item.product.store.pk
    if status:
        store = get_object_or_404(Store, pk=store_pk)
        location = request.COOKIES['adr']+' '+request.COOKIES['dadr']
        store = store.store_name
    if cnt > 1:
        cart_item += '외 {}건'.format(cnt-1)
    if request.method == "POST":    # 버튼 누르면
        URL = 'https://kapi.kakao.com/v1/payment/ready'
        headers = {
            "Authorization": "KakaoAK " + "965c38ccc1d83d33c9577c0b870eb506",   # 변경불가
            "Content-type": "application/x-www-form-urlencoded;charset=utf-8",  # 변경불가
        }
        params = {
            "cid": "TC0ONETIME",    # 변경불가. 실제로 사용하려면 카카오와 가맹을 맺어야함. 현재 코드는 테스트용 코드
            "partner_order_id": "{}_{}".format(store_pk, '임시'),     # 주문번호 (스토어 번호_주문 번호)
            "partner_user_id": "{}".format(user),    # 유저 아이디
            "item_name": "{}".format(cart_item),        # 구매 물품 이름
            "quantity": "{}".format(cnt),                # 구매 물품 수량
            "total_amount": "{}".format(cart.total),  # 구매 물품 가격
            "tax_free_amount": "0",         # 구매 물품 비과세 (0으로 고정)
            "approval_url": "{}kakaopay/approval/".format(current_site),    # 결제 성공 시 이동할 url
            "cancel_url": "{}kakaopay/cancel/".format(current_site),               # 결제 취소 시 이동할 url
            "fail_url": "{}kakaopay/fail/".format(current_site),                 # 결제 실패 시 이동할 url
        }

        res = requests.post(URL, headers=headers, params=params)
        request.session['tid'] = res.json()['tid']  # 결제 승인시 사용할 tid를 세션에 저장
        request.session['order_id'] = "{}_{}".format(store_pk, '임시')
        request.session['store_pk'] = store_pk
        next_url = res.json()['next_redirect_pc_url']  # 결제 페이지로 넘어갈 url을 저장
        return redirect(next_url)

    context = {
        'status': status,
        'location': location,
        'store': store,
    }

    return render(request, 'shopping/show_cart.html', context)

model을 연결하기위해 user, cart(세션), store를 불러온다.

그리고 다음 페이지로 넘길 url의 도메인이 필요하므로 current_site = request.build_absolute_uri()[:-10]를 사용한다.

도메인만 깔끔하게 뽑아주는 기능이 있을법한데, 아직은 현재 uri를 가져오는 방법밖에 알지 못해서 이렇게 사용하였다.

cnt는 카트에 담긴 물건의 종류를 세기 위해 존재한다. '찹쌀탕수육 외 2건' 식으로 표현할 때 사용한다.

cart_item의 기본값은 0으로 두고 cnt를 세며 가장 처음으로 들어오는 메뉴명을 할당한다.

status가 0일 경우는 카트(장바구니)가 비어있는 상태이고, 1이면 장바구니에 물건이 있는 상태이다.

이 값은 context로 넘겨 상황에따라 보이는 화면을 다르게 구성하였다.

store와 location은 장바구니에 물건이 존재하지 않으면 빈 문자열로 존재하고, 장바구니가 차있으면 관련 값이 들어간다.

location은 쿠키에 문자열로 저장되어있다.

 

사용자가 카카오페이로 결제하기 버튼을 누르면(POST) 발생하는 메커니즘은 지난 포스팅과 동일하다.

그러나 들어가는 값이 동적으로 변화하도록 일부 수정되었다.

그리고 이에따라 approval 부분도 변경되었다.

 

def approval(request):
    User = get_user_model()
    user = get_object_or_404(User, pk=request.user.pk)
    cart = Cart(request.session)
    order_items = []
    for item in cart.items:
        cart_item = item.product.menu_name
        cart_quantity = item.quantity
        order_items.append('{}_{}'.format(cart_item, cart_quantity))

    order_list = OrderList.objects.create(
        user=user,
        store=get_object_or_404(Store, pk=request.session['store_pk']),
        order_condition=1,
        order_location=request.COOKIES['adr'] + ' ' + request.COOKIES['dadr'],
        order_name='/'.join(order_items),  # 메뉴_갯수/ 형식
        order_price=cart.total  # 장바구니의 총 가격
    )

    cart.clear()
    URL = 'https://kapi.kakao.com/v1/payment/approve'
    headers = {
        "Authorization": "KakaoAK " + "965c38ccc1d83d33c9577c0b870eb506",   # 변경불가
        "Content-type": "application/x-www-form-urlencoded;charset=utf-8",  # 변경불가
    }
    params = {
        "cid": "TC0ONETIME",    # 변경불가. 실제로 사용하려면 카카오와 가맹을 맺어야함. 현재 코드는 테스트용 코드
        "tid": request.session['tid'],  # 결제 요청시 세션에 저장한 tid
        "partner_order_id": request.session['order_id'],     # 주문번호
        "partner_user_id": "{}".format(user),    # 유저 아이디
        "pg_token": request.GET.get("pg_token"),     # 쿼리 스트링으로 받은 pg토큰
    }

    res = requests.post(URL, headers=headers, params=params)
    amount = res.json()['amount']['total']
    res = res.json()
    context = {
        'res': res,
        'amount': amount,
    }
    return render(request, 'kakaopay/approval.html', context)

결제가 완료된 건은 OrderList라는 테이블에 추가한다.

order_name은 "후라이드_1/양념_1"과 같은 문자열 형태로 저장할 수 있도록 order_items로 가져온 목록들을 join 시킨다.

그리고 cart.clear()를 사용하여 장바구니를 비운다.

나머지 부분은 전과 유사하다.

OrderList는 추후에 사장님 페이지에서 정산 시에 사용이 된다.

 

완성본 (개인정보는 가렸다)

728x90
반응형

댓글