import express from "express"; import helper from "nestia-helper"; import * as nest from "@nestjs/common"; import { assertType } from "typescript-is"; import { v4 } from "uuid"; import { ITossBilling } from "../api/structures/ITossBilling"; import { ITossCardPayment } from "../api/structures/ITossCardPayment"; import { ITossPayment } from "../api/structures/ITossPayment"; import { FakeTossPaymentProvider } from "../providers/FakeTossPaymentProvider"; import { FakeTossStorage } from "../providers/FakeTossStorage"; import { FakeTossUserAuth } from "../providers/FakeTossUserAuth"; @nest.Controller("v1/billing") export class FakeTossBillingController { /** * 간편 결제 카드 등록하기. * * `billing.authorizations.card.store` 는 고객이 자신의 신록 카드를 서버에 등록해두고, * 매번 결제가 필요할 때마다 카드 정보를 반복 입력하는 일 없이 간편하게 결제를 * 진행하고자 할 때, 호출되는 API 함수이다. * * 참고로 `billing.authorizations.card.store` 는 클라이언트 어플리케이션이 토스 * 페이먼츠가 제공하는 간편 결제 카드 등록 창을 사용하는 경우, 귀하의 백엔드 서버가 이를 * 실 서비스에서 호출하는 일은 없을 것이다. 다만, 고객이 간편 결제 카드를 등록하는 * 상황을 시뮬레이션하기 위하여, 테스트 자동화 프로그램 수준에서 사용될 수는 있다. * * @param input 간편 결제 카드 등록 정보 * @returns 간편 결제 카드 정보 * * @author Jeongho Nam - https://github.com/samchon */ @helper.TypedRoute.Post("authorizations/card") public store( @nest.Request() request: express.Request, @nest.Body() input: ITossBilling.IStore, ): ITossBilling { FakeTossUserAuth.authorize(request); assertType<typeof input>(input); const billing: ITossBilling = { mId: "tosspyaments", method: "카드", billingKey: v4(), customerKey: input.customerKey, cardCompany: "신한", cardNumber: input.cardNumber, authenticatedAt: new Date().toString(), }; FakeTossStorage.billings.set(billing.billingKey, [billing, input]); return billing; } /** * 간편 결제로 등록한 수단 조회하기. * * `billing.authorizations.at` 은 고객이 간편 결제를 위하여 토스 페이먼츠 서버에 * 등록한 결제 수단을 조회하는 함수이다. * * 주로 클라이언트 어플리케이션이 토스 페이먼츠가 자체적으로 제공하는 결제 창을 사용하는 * 경우, 그래서 프론트 어플리케이션이 귀하의 백엔드 서버에 `billingKey` 와` customerKey` * 만을 전달해주어, 상세 간편 결제 수단 정보가 필요할 때 사용한다. * * @param billingKey 대상 정보의 {@link ITossBilling.billingKey} * @param input 고객 식별자 키 * @returns 간편 결제 수단 정보 * * @author Jeongho Nam - https://github.com/samchon */ @helper.TypedRoute.Post("authorizations/:billingKey") public at( @nest.Request() request: express.Request, @helper.TypedParam("billingKey", "string") billingKey: string, @nest.Body() input: ITossBilling.ICustomerKey, ): ITossBilling { FakeTossUserAuth.authorize(request); assertType<typeof input>(input); const tuple = FakeTossStorage.billings.get(billingKey); if (tuple[0].customerKey !== input.customerKey) throw new nest.ForbiddenException("Different customer."); return tuple[0]; } /** * 간편 결제에 등록한 수단으로 결제하기. * * `billing.pay` 는 간편 결제에 등록한 수단으로 결제를 진행하고자 할 때 호출하는 API * 함수이다. * * 그리고 `billing.pay` 는 결제 수단 중 유일하게, 클라이언트 어플리케이션이 토스 * 페이먼츠가 제공하는 결제 창을 사용할 수 없어, 귀하의 백엔드 서버가 토스 페이먼츠의 * API 함수를 직접 호출해야 하는 경우에 해당한다. 따라서 간편 결제에 관련하여 토스 * 페이먼츠와 연동하는 백엔드 서버 및 프론트 어플리케이션을 개발할 때, 반드시 이 상황에 * 대한 별도의 설계 및 개발이 필요하니, 이 점을 염두에 두기 바란다. * * 더하여 `billing.pay` 는 철저히 귀사 백엔드 서버의 판단 아래 호출되는 API 함수인지라, * 이를 통하여 이루어지는 결제는 일절 {@link payments.approve} 가 필요 없다. 다만 * `billing.pay` 는 이처럼 부차적인 승인 과정 필요없이 그 즉시로 결제가 완성되니, 이를 * 호출하는 상황에 대하여 세심히 주의를 기울일 필요가 있다 * * @param billingKey 간편 결제에 등록한 수단의 {@link ITossBilling.billingKey} * @param input 주문 정보 * @returns 결제 정보 * * @author Jeongho Nam - https://github.com/samchon */ @helper.TypedRoute.Post(":billingKey") public pay( @nest.Request() request: express.Request, @helper.TypedParam("billingKey", "string") billingKey: string, @nest.Body() input: ITossBilling.IPaymentStore, ): ITossPayment { FakeTossUserAuth.authorize(request); assertType<typeof input>(input); const tuple = FakeTossStorage.billings.get(billingKey); const card = tuple[1]; const payment: ITossCardPayment = { ...FakeTossPaymentProvider.get_common_props(input), method: "카드", type: "NORMAL", status: "DONE", approvedAt: new Date().toString(), discount: null, card: { company: "신한카드", number: card.cardNumber, installmentPlanMonths: 0, isInterestFree: true, approveNo: "temporary-card-approval-number", useCardPoint: false, cardType: "신용", ownerType: "개인", acquireStatus: "READY", receiptUrl: "somewhere-receipt-url", }, easyPay: null, }; FakeTossStorage.payments.set(payment.paymentKey, payment); return payment; } }