iamport - ๋ชจ๋ฐ์ผ ์น ๊ฒฐ์ ๋ฅผ ์ฐธ๊ณ ํ์ต๋๋ค.
๊ฐ๋ฐ ๋ชจ๋์ผ ๋๋ ๋ชจ๋ฐ์ผ๋ก ํ
์คํธํ๊ธฐ ํ๋ค์ด์ ๋ฐ์คํฌํ ์น๋ธ๋ผ์ฐ์ ๋ง์ ์ด์ฉํด์ ํ
์คํธํ๊ณ ๋์ด๊ฐ์ต๋๋ค.
ํ์ง๋ง AWS-EC2
์ ๋ฐฐํฌํ๊ณ ๋ชจ๋ฐ์ผ๋ก ๋ค์ด๊ฐ์ ๊ฒฐ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํด๋ณด๋ ์ด์ํ๊ฒ๋ ๊ฒฐ์ ๋ก์ง์ ์ ์์ ์ผ๋ก ์๋ํ๋๋ฐ ๊ฒฐ์ ์ ๋ณด๊ฐ DB
์ ๊ธฐ๋ก๋์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ iamport
๊ณต์ ๋ฌธ์๋ฅผ ์ฐพ์๋ณด๋ฉด์ ๋ชจ๋ฐ์ผ ์น ๊ฒฐ์ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ฒ ๋์์ต๋๋ค.
์นด์นด์คํ์ด ๊ฒฐ์ ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ฐ์ผ ์น๊ณผ ๋ฐ์คํฌํ ์น์ ๊ฒฐ์ ๋ฐฉ์์ด ์กฐ๊ธ ๋ค๋ฆ
๋๋ค.
๋ฐ์คํฌํ ์น์ ๊ฒฝ์ฐ์๋ QR์ฝ๋๋ ํด๋ํฐ ๋ฒํธ/์๋
์์ผ์ ์ด์ฉํด์ ์นด์นด์คํก์ผ๋ก ๊ฒฐ์ ํ๊ฒ ํด์ค๋๋ค.
์ด๋ ๊ฒ ๊ฒฐ์ ํ๊ฒ ๋๋ฉด ์น๋ธ๋ผ์ฐ์ ๋ ๊ฐ๋งํ ์๊ณ ๋ค๋ฅธ ๊ณณ์์ ๊ฒฐ์ ๋ฅผ ์ฒ๋ฆฌํ๊ณ ๊ฒฐ๊ณผ๋ง ๋ฐ๊ฒ ๋ฉ๋๋ค.
๊ทธ ๊ฒฐ์ ๊ฒฐ๊ณผ๋ฅผ IMP.request_pay(data, callback)
์์ callback
์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฐ์์ ๊ฒฐ์ ๊ธฐ๋ก์ DB
์ ๋จ๊ธฐ๋๋ก ๊ตฌํํ์ต๋๋ค. ( ์์์์ rsp
๊ฐ ๊ฒฐ์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ )
const onPayment = useCallback(
(pg: "kakaopay" | "tosspay") => () => {
if (!process.env.NEXT_PUBLIC_IAMPORT_CODE)
return toast.error("iamport์ ๊ฐ๋งน์ ์๋ณ์ฝ๋๊ฐ ์์ต๋๋ค.");
if (!paymentData) {
toast.error(
"๊ฒฐ์ ํ ์ํ์ ์ ๋ณด๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค. ๋ฉ์ธ ํ๋ฉด์ผ๋ก ์ด๋๋ฉ๋๋ค."
);
return router.push("/");
}
// iamport๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ๊ฐ๋งน์ ์๋ณ์ฝ๋ ๋ฑ๋ก
window.IMP.init(process.env.NEXT_PUBLIC_IAMPORT_CODE);
const callback = async (rsp) => {
if (
!rsp.buyer_name ||
!rsp.buyer_addr ||
!rsp.paid_amount ||
!rsp.buyer_email ||
!rsp.buyer_tel ||
!rsp.pg_provider
)
return toast.warning("๊ฒฐ์ ์ ํ์ํ ๋ฐ์ดํฐ๊ฐ ๋ถ์กฑํฉ๋๋ค.");
if (rsp.success) {
try {
// >>> ๊ฒฐ์ ์๋ฃ DB ์ ์ฅ
await apiService.orderService.apiCreateOrder({
singleData: rsp.custom_data.singleData,
orderData: {
name: rsp.buyer_name,
address: rsp.buyer_addr,
residence: rsp.custom_data.residence,
message: rsp.custom_data.message,
amount: rsp.paid_amount,
email: rsp.buyer_email,
phone: rsp.buyer_tel,
provider: rsp.pg_provider,
},
});
toast.success(
"๊ฒฐ์ ๊ฐ ์๋ฃ๋์์ต๋๋ค. 2์ด๋ค์ ๊ฒฐ์ ๋ด์ญ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค.",
{ autoClose: 2000 }
);
setTimeout(() => router.push("/information/order"), 2000);
} catch (error) {
console.error("error >> ", error);
if (error instanceof AxiosError) {
toast.error(error.response?.data.message);
} else {
toast.error("์ ์ ์๋ ๋ฌธ์ ๋ก ์ธํด ๊ฒฐ์ ์ ์คํจํ์ต๋๋ค.");
}
}
} else {
toast.error("๊ฒฐ์ ์ ์คํจํ์ต๋๋ค. " + rsp.error_msg, {
autoClose: 2000,
});
}
};
window.IMP.request_pay({ ...paymentData, pg, pay_method: "card" }, callback);
},
[router, paymentData]
);
ํ์ง๋ง ๋ชจ๋ฐ์ผ ์น์ผ๋ก ์ ๊ทผํด์ ๊ฒฐ์ ํ๋ ๊ฒฝ์ฐ์๋ ํด๋ํฐ์ ์นด์นด์คํก์ด ์ค์น๋์ด ์์ผ๋ฏ๋ก ์ด๋ค ์นด์นด์คํก ์ ์ ๊ฐ ๊ฒฐ์ ๋ฅผ ์ํ๋์ง๋ฅผ ํ๋จํ ํ์ ์์ด ์นด์นด์คํก์ผ๋ก ๋ฐ๋ก ๋ค์ด๊ฐ์ ๋ก๊ทธ์ธํ ์ ์ ์๊ฒ ๊ฒฐ์ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ ๊ฒ ๋๋ฉด ๋ธ๋ผ์ฐ์ ์์ ์นด์นด์คํก์ผ๋ก ํ๋ฉด ์ ํ์ด ๋ฐ์ํ๊ฒ ๋๋ฉฐ ๊ฒฐ์ ๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๋ง์น๋ฉด ๊ฒฐ์ ํ ๋ ์
๋ ฅํ๋ m_redirect_url
์ ์ด์ฉํด์ ํด๋น url
๋ฆฌ๋ค์ด๋ ์
๋ฉ๋๋ค.
๋ฐ๋ผ์ ์ ๋ฐ์คํฌํ ์น์์ ๊ฒฐ์ ๋ฅผ ์งํํ์ ๋์ ๋ค๋ฅด๊ฒ callback
์ด ์คํ๋์ง ์์ DB
์ ๊ฒฐ์ ์ ๋ณด๊ฐ ๋ฑ๋ก๋์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์
๋๋ค.
( ๋ค๋ฅธ ๊ฒฐ์ ๋ฐฉ์์ ์ ํํด์ ๋ค๋ฅธ ์น์ฌ์ดํธ๋ ์ดํ๋ฆฌ์ผ์ด์
์ผ๋ก ๋ฆฌ๋ค์ด๋ ์
๋์ด์ ๊ฒฐ์ ๋ฅผ ์งํํฉ๋๋ค. )
์์ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด์ iamport
์์ ํน์ ๊ฒฐ์ ์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ์ป๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํด์ค๋๋ค.
๊ธฐ๋ณธ์ ์ธ ํ๋ฆ์ ์๋์ ๊ฐ์ต๋๋ค.
1. m_redirect_url
์์ ๊ฒฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ url
๋ฅผ ์ง์
2. iamport
์์ m_redirect_url
๋ก ๋ฆฌ๋ค์ด๋ ์
ํ ๋ imp_uid
์ merchant_uid
๊ฐ์ query string
์ผ๋ก ์ฒจ๋ถ
3. ํด๋น url
์์ REST API KEY
์ REST API SECRET KEY
๋ฅผ ์ด์ฉํด์ access_token
์ ์ป์
4. access_token
๊ณผ imp_uid
์ ์ด์ฉํด์ ํน์ ๊ฒฐ์ ์ ๋ํ ์ ๋ณด๋ฅผ ์ป์
5. ์ป์ ์ ๋ณด๋ฅผ ์ด์ฉํด์ DB
์ ๊ฒฐ์ ์ ๋ณด๋ฅผ ๊ธฐ๋กํจ
6. ๊ฒฐ์ ์ ๋ณด ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ์
ํจ
๊ณต์ ํ์ด์ง์ ์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ค๋ช ์ด ๋งค์ฐ ์๋์ด ์์ด์ ๊ตณ์ด ์ฝ๋ ์์๋ฅผ ์์ฑํ์ง๋ ์๊ฒ ์ต๋๋ค.
๋ค๋ง ํ ํฐ๊ณผ ๊ฒฐ์ ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ํ์ ๊ณผ api ์์ฒญ ํจ์๋ค์ ์ฒจ๋ถํ๊ฒ ์ต๋๋ค.
๋ํ ์ฌ์ฉํ๋ฉด์ ์ฃผ์ํด์ผ ํ ์ ์ผ๋ก custom_data
๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ string
ํ์
์ด๋ฏ๋ก JSON.parse()
๋ฅผ ์ด์ฉํด์ ํ์ฑํ๊ณ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
import axios from "axios";
// type
import type {
// IamportGetTokenBody,
IamportGetTokenResponse,
IamportGetPaymentDataBody,
IamportGetPaymentDataResponse,
} from "@src/types";
const iamportInstance = axios.create({
baseURL: "https://api.iamport.kr",
timeout: 10000,
});
/**
* 2022/09/14 - iamport ์์ธ์ค ํ ํฐ ๋ฐ๊ธ ๋ฐ๊ธฐ - by 1-blue
* @returns ์์ธ์ค ํ ํฐ
*/
const apiGetToken = () =>
iamportInstance.post<IamportGetTokenResponse>(
`/users/getToken`,
{
imp_key: process.env.IAMPORT_REST_API_KEY,
imp_secret: process.env.IAMPORT_REST_API_SECRET,
},
{
headers: {
"Content-Type": "application/json",
},
}
);
/**
* 2022/09/14 - iamport ์์ธ์ค ํ ํฐ์ ์ด์ฉํด ๊ฒฐ์ ์ ๋ณด ์กฐํ - by 1-blue
* @returns ๊ฒฐ์ ์ ๋ณด
*/
const apiGetPaymentData = ({
imp_uid,
access_token,
}: IamportGetPaymentDataBody) =>
iamportInstance.get<IamportGetPaymentDataResponse>(`/payments/${imp_uid}`, {
headers: { Authorization: access_token },
});
/**
* 2022/09/14 - iamport ๊ด๋ จ api ์์ฒญ ๊ฐ์ฒด - by 1-blue
*/
const iamportService = {
apiGetToken,
apiGetPaymentData,
};
export default iamportService;
type RequestPaymentData = {
amount: number;
apply_num: string;
bank_code: string | null;
bank_name: string | null;
buyer_addr: string;
buyer_email: string;
buyer_name: string;
buyer_postcode: string;
buyer_tel: string;
cancel_amount: number;
cancel_history: [];
cancel_reason: string | null;
cancel_receipt_urls: [];
cancelled_at: number;
card_code: string | null;
card_name: string | null;
card_number: string | null;
card_quota: number;
card_type: string | null;
cash_receipt_issued: false;
channel: string;
currency: string;
custom_data: string;
customer_uid: string | null;
customer_uid_usage: string | null;
emb_pg_provider: string | null;
escrow: false;
fail_reason: string | null;
failed_at: number;
imp_uid: string;
merchant_uid: string;
name: string;
paid_at: number;
pay_method: string;
pg_id: string;
pg_provider: string;
pg_tid: string;
receipt_url: string;
started_at: number;
status: string;
user_agent: string;
vbank_code: string | null;
vbank_date: number;
vbank_holder: string | null;
vbank_issued_at: number;
vbank_name: string | null;
vbank_num: string | null;
};
/**
* 2022/09/14 - iamport ์์ธ์ค ํ ํฐ ์์ฒญ ์ก์ ํ์
- by 1-blue
*/
export type IamportGetTokenBody = {};
/**
* 2022/09/14 - iamport ์์ธ์ค ํ ํฐ ์์ฒญ ์์ ํ์
- by 1-blue
*/
export type IamportGetTokenResponse = { response: { access_token: string } };
/**
* 2022/09/14 - iamport ๊ฒฐ์ ์ ๋ณด ์์ฒญ ์ก์ ํ์
- by 1-blue
*/
export type IamportGetPaymentDataBody = {
imp_uid: string;
access_token: string;
};
/**
* 2022/09/14 - iamport ๊ฒฐ์ ์ ๋ณด ์์ฒญ ์์ ํ์
- by 1-blue
*/
export type IamportGetPaymentDataResponse = { response: RequestPaymentData };