728x90
반응형
아임포트 웹훅-
https://docs.iamport.kr/tech/webhook
아임포트에서 제공하는 웹훅으로 결제가 완료된 후 다음 결제를 예약할 수 있다.
데이터베이스에 저장된 구독 남은 개월 수를 측정해서 카운팅한 후
남은 개월 수가 있을 경우 결제완료 후 다음 달로 결제 예약을 거는 시스템을 구현해보도록 하자.
1. 아임포트 관리자 콘솔에서 웹훅에 대한 설정을 해준다.
웹훅 발송 공통 URL을 내가 백엔드에서 요청받을 라우터로 지정해주면 결제가 완료될 때 원하는 행동을 할 수 있다.
2. 백엔드를 만들고 위에 이미지의 호출 테스트를 눌러본다.
router.post("/repayments", async function (req, res, next) {
const body = req.body
console.log("body : ", body)
try {
res.send({ success: true })
}
catch (Err) {
console.log("err : ", Err)
res.send({ success: false })
}
});
- 호출테스트 눌렀을 때 정상적인 경우
3. 라우터에 로직을 만든다.
결제가 잘되거나 예약결제가 시도되었을 땐 paid, 예약결제가 실패했을 땐 failed 결과값이 온다.
- 구독 테이블을 조회해서 남은 개월 수를 측정한다.
- 남은 개월 수가 0보다 클 경우 토큰을 발급받고 imp_uid 또는 merchant_uid로 결제 정보를 조회하고 잘 되었는지 확인한다.
- 예약결제가 정상적으로 이루어진 상태면 카운팅을 해주고 merchant_uid를 새로운 예약결제에 맞게 수정하며 다음 달에 예약을 걸고 쿠키를 수정한다.( 로그인 정보에 담아줘서 나중에 화면에 달리보이게 하기 위함)
- 만약 잔액 부족 등으로 결제가 안 된 상태면 로그인정보를 수정해서 구독 시 사용 가능한 서비스를 불가능하게 하고 다음날을 예약일로 요청한다. (구독에 관한 데이터는 남아있음).
- 남은 개월 수가 0일 경우 예약을 걸지 않고 구독해지를 해준다 로그인 정보를 바꾸고 해당 컬럼을 삭제한다.
router.post("/repayments", async function (req, res, next) {
const body = req.body;
const { imp_uid, merchant_uid } = req.body;
try {
// 1. 구독 테이블을 조회해서 남은 개월 수를 측정한다.
Subscribe.findOne({
where: {
subscribe_merchant_uid: merchant_uid
}
}).then(async (result) => {
if (result) {
// 2. 남은 개월 수가 0보다 클 경우 토큰을 발급받고 imp_uid 또는 merchant_uid로 결제 정보를 조회하고 잘 되었는지 확인한다.
if (result.subscribe_count > 0) {
// 액세스 토큰(access token) 발급 받기
const getToken = await axios({
url: "https://api.iamport.kr/users/getToken",
method: "post", // POST method
headers: { "Content-Type": "application/json" }, // "Content-Type": "application/json"
data: {
imp_key: process.env.IMP_API_KEY, // REST API 키
imp_secret: process.env.IMP_API_SECRET_KEY // REST API Secret
}
});
const { access_token } = getToken.data.response; // 인증 토큰
// imp_uid 또는 merchant_uid로 아임포트 서버에서 결제 정보 조회
const paymentResult = await axios({
url: 'https://api.iamport.kr/payments/' + imp_uid,
method: "get",
headers: { "Authorization": access_token }, // 인증 토큰을 Authorization header에 추가
data: {
imp_uid: imp_uid
}
});
console.log("repayments result : ", paymentResult)
var merchant_uid_date = moment().format('YYYY-MM-DD_HH:mm:ss');
if (paymentResult.data.response.status === 'paid') {
// 3. 예약결제가 정상적으로 이루어진 상태면 카운팅을 해주고 merchant_uid를 새로운 예약결제에 맞게 수정하며 다음 달에 예약을 걸고 로그인정보를 수정한다.( 로그인 정보에 담아줘서 나중에 화면에 달리보이게 하기 위함)
// 카운팅, merchant_uid 수정
Subscribe.update(
{
subscribe_count: result.subscribe_count - 1,
subscribe_merchant_uid: "subscribe_" + merchant_uid_date,
subscribe_type: "기본정기결제예약"
}, {
where: {
subscribe_merchant_uid: merchant_uid
}
}).then(async (updateResult) => {
// 로그인 정보를 수정해줌 ( 잔액부족 등으로 결제 실패 후 다시 결제 했을 때 서비스 이용 가능하게 함)
MUserInfo.update({
muser_subscribe_type: result.subscribe_type
}, {
where: {
muser_id: result.subscribe_muser_id
}
})
// 새로운 결제 예약
var today = new Date();
var schedule_at_time = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate());
await axios({
url: "https://api.iamport.kr/subscribe/payments/schedule", // 예: https://api.iamport.kr/subscribe/payments/schedule
method: "post",
headers: { "Authorization": access_token }, // 인증 토큰 Authorization header에 추가
data: {
customer_uid: result.subscribe_customer_uid, // 카드(빌링키)와 1:1로 대응하는 값
schedules: [
{
merchant_uid: "subscribe_" + merchant_uid_date, // 주문 번호
schedule_at: Math.floor(schedule_at_time.getTime() / 1000), // 결제 시도 시각 in Unix Time Stamp. 예: 다음 달 1일
amount: result.subscribe_amount,
name: "기본정기결제예약",
}
]
}
});
})
}
else {
// 4. 만약 잔액 부족 등으로 결제가 안 된 상태면 로그인정보를 수정해서 구독 시 사용 가능한 서비스를 불가능하게 하고 다음날을 예약일로 요청한다. (구독에 관한 데이터는 남아있음).
Subscribe.update(
{
subscribe_merchant_uid: "subscribe_" + merchant_uid_date,
subscribe_type: "기본정기결제예약"
}, {
where: {
subscribe_merchant_uid: merchant_uid
}
}).then((updateResult) => {
// 로그인 정보를 수정해줌 ( 구독 서비스를 이용하지 못하게 함. )
MUserInfo.update({
muser_subscribe_type: ""
}, {
where: {
muser_id: result.subscribe_muser_id
}
})
// 새로운 결제 예약
var today = new Date();
var schedule_at_time = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
axios({
url: "https://api.iamport.kr/subscribe/payments/schedule", // 예: https://api.iamport.kr/subscribe/payments/schedule
method: "post",
headers: { "Authorization": access_token }, // 인증 토큰 Authorization header에 추가
data: {
customer_uid: result.subscribe_customer_uid, // 카드(빌링키)와 1:1로 대응하는 값
schedules: [
{
merchant_uid: "subscribe_" + merchant_uid_date, // 주문 번호
schedule_at: Math.floor(schedule_at_time.getTime() / 1000), // 결제 시도 시각 in Unix Time Stamp. 예: 다음 달 1일
amount: result.subscribe_amount,
name: "기본정기결제예약",
}
]
}
});
})
}
}
// 5. 남은 개월 수가 0일 경우 예약을 걸지 않고 구독해지를 해준다 로그인 정보를 바꾸고 해당 컬럼을 삭제한다.
else {
MUserInfo.update({
muser_subscribe_type: ""
}, {
where: {
muser_id: result.subscribe_muser_id
}
})
}
}
else {
}
})
res.send({ success: true })
}
catch (Err) {
console.log("err : ", Err)
res.send({ success: false })
}
});
728x90
반응형
'Front-End > Next.js' 카테고리의 다른 글
Next.js | 아임포트 정기 결제(5) ( with TypeScript ) | 모바일 웹앱 환경에서 결제하기(KCP) (0) | 2022.05.18 |
---|---|
Next.js | 아임포트 정기 결제(4) ( with TypeScript ) | 구독 취소하기 (0) | 2022.05.18 |
Next.js | 아임포트 정기 결제(2) ( with TypeScript ) | 백엔드에서 토큰 인증받고 결제 요청하기 (0) | 2022.05.16 |
Next.js | 아임포트 정기 결제(1) ( with TypeScript ) | 클라이언트에서 빌링키 받기 (0) | 2022.05.16 |
Next.js | 사용자 접속 IP 확인하기 (0) | 2022.03.11 |