Commit 6e0e826d authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

카카오페이 결제실패 및 예매내역삭제

parent 432e3eb3
...@@ -15,8 +15,9 @@ import AdminPage from "./pages/AdminPage/AdminPage"; ...@@ -15,8 +15,9 @@ import AdminPage from "./pages/AdminPage/AdminPage";
import TicketingPage from "./pages/TicketingPage"; import TicketingPage from "./pages/TicketingPage";
import TicketingSeatPage from './pages/TicketingSeatPage' import TicketingSeatPage from './pages/TicketingSeatPage'
import SearchPage from "./pages/SearchPage"; import SearchPage from "./pages/SearchPage";
import Payment from "./pages/PaymentPage/PaymentPage"; import PaymentPage from "./pages/PaymentPage/PaymentPage";
import PaymentCompletePage from "./pages/PaymentCompletePage"; import PaymentCompletePage from "./pages/PaymentCompletePage";
import PaymentFailPage from "./pages/PaymentFailPage";
function App() { function App() {
...@@ -39,8 +40,9 @@ function App() { ...@@ -39,8 +40,9 @@ function App() {
<Route path="/guest" component={GuestPage}/> <Route path="/guest" component={GuestPage}/>
<Route path="/ticket/seat" component={TicketingSeatPage}/> <Route path="/ticket/seat" component={TicketingSeatPage}/>
<Route path="/ticket" component={TicketingPage} /> <Route path="/ticket" component={TicketingPage} />
<Route path="/payment" component={Payment} /> <Route path="/payment" component={PaymentPage} />
<Route path="/paymentcomplete" component={PaymentCompletePage} /> <Route path="/paymentcomplete" component={PaymentCompletePage} />
<Route path="/paymentfail" component={PaymentFailPage} />
<Route path="/theater" component={TheaterPage}/> <Route path="/theater" component={TheaterPage}/>
<Route path="/search" component={SearchPage} /> <Route path="/search" component={SearchPage} />
</Switch> </Switch>
......
import axios from "axios";
import { baseUrl } from "../utils/baseUrl.js";
const approveReq = async (info) => {
const url = `${baseUrl}/api/kakaopay/test/single`;
const { data } = await axios.post(url,info);
return data
}
const approveSuccess = async (info) => {
const url = `${baseUrl}/api/kakaopay/success`;
const { data } = await axios.post(url,info);
return data
}
const paymentCancel = async (info) => {
const url = `${baseUrl}/api/kakaopay/cancel`;
const { data } = await axios.post(url,info);
return data
}
const kakaopayApi = {
approveReq,
approveSuccess,
paymentCancel
}
export default kakaopayApi
\ No newline at end of file
...@@ -4,7 +4,7 @@ import { baseUrl } from "../utils/baseUrl.js"; ...@@ -4,7 +4,7 @@ import { baseUrl } from "../utils/baseUrl.js";
const findReservedSeats = async (timeTable) => { const findReservedSeats = async (timeTable) => {
console.log(timeTable) console.log(timeTable)
const url = `${baseUrl}/api/reservation/findreservation`; const url = `${baseUrl}/api/reservation/findreservation`;
const { data } = await axios.post(url,{timeTable:timeTable}); const { data } = await axios.post(url, { timeTable: timeTable });
return data return data
} }
...@@ -25,12 +25,26 @@ const save = async (save) => { ...@@ -25,12 +25,26 @@ const save = async (save) => {
const url = `${baseUrl}/api/reservation/save`; const url = `${baseUrl}/api/reservation/save`;
const { data } = await axios.post(url, save); const { data } = await axios.post(url, save);
return data return data
}
const saveTid = async (tid) => {
const url = `${baseUrl}/api/reservation/savetid`;
const { data } = await axios.post(url, tid);
return data
} }
const reservationApi = {
const deleteReservation = async () => {
const url = `${baseUrl}/api/reservation/delete`;
const { data } = await axios.get(url);
return data
}
const reservationApi = {
findReservation, findReservation,
findReservedSeats, findReservedSeats,
findOneReservation, findOneReservation,
save save,
saveTid,
deleteReservation
} }
export default reservationApi export default reservationApi
\ No newline at end of file
import kakaopayApi from "../apis/kakaopay.api"
import catchErrors from "../utils/catchErrors"
const KakaopaymentCancelBtn = () => {
const [error, setError] = useState()
async function paymentCancel() {
try {
setError("")
//실행하기 전에 먼저 reservation에서 해당하는 예매건에 대한 tid가져오기
const response = await kakaopayApi.paymentCancel({
cid: 'TC0ONETIME',
tid: '',
cancel_amount: '',
cancel_tax_free_amount:0,
})
} catch (error) {
catchErrors(error,setError)
}
}
return (
<button className="btn btn-warning" onClick={paymentCancel }>결제취소</button>
)
}
\ No newline at end of file
...@@ -60,7 +60,7 @@ const TheaterInfo = () => { ...@@ -60,7 +60,7 @@ const TheaterInfo = () => {
information: response.transportation information: response.transportation
}) })
} catch (error) { } catch (error) {
catchErrors(error, setError) // catchErrors(error, setError)
console.log(error) console.log(error)
} }
} }
......
...@@ -66,7 +66,7 @@ const MoviePage = ({ location }) => { ...@@ -66,7 +66,7 @@ const MoviePage = ({ location }) => {
</div> </div>
<div className="col-sm-6" style={{ color: "white" }}> <div className="col-sm-6" style={{ color: "white" }}>
<h1 className="pb-3">{movieInfo.title}</h1> <h1 className="pb-3">{movieInfo.title}</h1>
<p>예매율:{Math.round((movieInfo.ticket_sales / (movieInfo.totalReservationRate.totalReservationRate || 1)) * 100)}% 누적관객수: {movieInfo.ticket_sales}</p> <p>예매율: {Math.round((movieInfo.ticket_sales / (movieInfo.totalReservationRate.totalReservationRate || 1)) * 100)}% 누적관객수: {movieInfo.ticket_sales}</p>
{movieInfo.director || movieInfo.cast {movieInfo.director || movieInfo.cast
? ?
<> <>
...@@ -80,7 +80,7 @@ const MoviePage = ({ location }) => { ...@@ -80,7 +80,7 @@ const MoviePage = ({ location }) => {
if (idx !== 0) return acc + ', ' + cur.name if (idx !== 0) return acc + ', ' + cur.name
else return acc + cur.name else return acc + cur.name
}, "")}</p> }, "")}</p>
<p>개봉일:{movieInfo.release_date}</p> <p>개봉일: {movieInfo.release_date}</p>
<div className="text-end"> <div className="text-end">
<Link to={{ <Link to={{
pathname: `/ticket`, pathname: `/ticket`,
......
...@@ -4,6 +4,7 @@ import moment from 'moment'; ...@@ -4,6 +4,7 @@ import moment from 'moment';
import { useAuth } from '../context/auth_context' import { useAuth } from '../context/auth_context'
import catchErrors from '../utils/catchErrors' import catchErrors from '../utils/catchErrors'
import reservationApi from '../apis/reservation.api' import reservationApi from '../apis/reservation.api'
import kakaopayApi from '../apis/kakaopay.api';
const PaymentCompletePage = () => { const PaymentCompletePage = () => {
const { user } = useAuth() const { user } = useAuth()
...@@ -25,9 +26,10 @@ const PaymentCompletePage = () => { ...@@ -25,9 +26,10 @@ const PaymentCompletePage = () => {
async function saveGuestReservation() { async function saveGuestReservation() {
try { try {
setError("")
const response = await axios.get(`/api/auth/guestinfo/${user.id}`); const response = await axios.get(`/api/auth/guestinfo/${user.id}`);
const response2 = await reservationApi.findOneReservation() const response2 = await reservationApi.findOneReservation()
console.log("예매내역=====", response2) const response3 = await reservationApi.saveTid({ tid: localStorage.getItem('tid')})
if (response.data || response2) { if (response.data || response2) {
const responseEmail = await axios.post('/api/email/send', { const responseEmail = await axios.post('/api/email/send', {
reservationData: response2.map(el => { return { "row": el.row, "col": el.col } }), reservationData: response2.map(el => { return { "row": el.row, "col": el.col } }),
...@@ -37,7 +39,7 @@ const PaymentCompletePage = () => { ...@@ -37,7 +39,7 @@ const PaymentCompletePage = () => {
theater: response2[0].theater.theaterName, theater: response2[0].theater.theaterName,
time: response2[0].timetable.date.split('T')[0] + ' ' + moment(response2[0].timetable.start_time).format('HH:mm') time: response2[0].timetable.date.split('T')[0] + ' ' + moment(response2[0].timetable.start_time).format('HH:mm')
}) })
console.log(responseEmail.data) localStorage.removeItem('tid')
} }
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
...@@ -46,18 +48,23 @@ const PaymentCompletePage = () => { ...@@ -46,18 +48,23 @@ const PaymentCompletePage = () => {
async function saveUserReservation() { async function saveUserReservation() {
try { try {
setError("")
const response = await axios.post(`/api/auth/getuserinfo`, { const response = await axios.post(`/api/auth/getuserinfo`, {
id: user.id id: user.id
}) })
const response2 = await reservationApi.findOneReservation()
// if (response.data) { const response3 = await reservationApi.saveTid({ tid: localStorage.getItem('tid')})
// const responseEmail = await axios.post('/api/email/send', { if (response.data || response2) {
// ...response2.data, const responseEmail = await axios.post('/api/email/send', {
// ...response.data, reservationData: response2.map(el => { return { "row": el.row, "col": el.col } }),
userData: { ...response.data },
// }) cinema: "Butter Studio 조치원",
// console.log(responseEmail.data) title: response2[0].title,
// } theater: response2[0].theater.theaterName,
time: response2[0].timetable.date.split('T')[0] + ' ' + moment(response2[0].timetable.start_time).format('HH:mm')
})
localStorage.removeItem('tid')
}
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
} }
...@@ -65,9 +72,10 @@ const PaymentCompletePage = () => { ...@@ -65,9 +72,10 @@ const PaymentCompletePage = () => {
async function approveKakaopay(tid) { async function approveKakaopay(tid) {
try { try {
setError("")
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const pg_token = urlParams.get('pg_token'); const pg_token = urlParams.get('pg_token');
const response = await axios.post(`/api/kakaopay/success`, { const response = await kakaopayApi.approveSuccess({
'tid': tid, 'tid': tid,
cid: 'TC0ONETIME', cid: 'TC0ONETIME',
partner_order_id: 'butter_studio', partner_order_id: 'butter_studio',
...@@ -81,10 +89,18 @@ const PaymentCompletePage = () => { ...@@ -81,10 +89,18 @@ const PaymentCompletePage = () => {
} }
return ( return (
<div className="text-center"> <div className="container text-center py-5">
<h3>예매가 정상적으로 완료되었습니다.</h3> <h3 className="my-3 text-white">예매가 정상적으로 완료되었습니다.</h3>
<button>홈으로</button> {user.role === "member"
{user.role === "member" ? <button>마이페이지</button> : <></>} ?
<a href="/mypage">
<button className="btn btn-warning mx-1">마이페이지</button>
</a>
:
<a href="/">
<button className="btn btn-warning mx-1">홈으로</button>
</a>
}
</div> </div>
) )
} }
......
import { useEffect, useState } from 'react'
import { useAuth } from '../context/auth_context'
import catchErrors from '../utils/catchErrors'
import reservationApi from '../apis/reservation.api'
const PaymentCompletePage = () => {
const [error, setError] = useState()
useEffect(() => {
deleteReservation()
}, [])
async function deleteReservation() {
try {
const response = await reservationApi.deleteReservation()
localStorage.removeItem('tid')
} catch (error) {
catchErrors(error, setError)
}
}
return (
<div className="container text-center py-5">
<h3 className="my-3 text-white">결제에 실패하셨습니다.</h3>
<a href="/ticket">
<button className="btn btn-warning mx-1">다시 예매하기</button>
</a>
<a href="/">
<button className="btn btn-warning mx-1">홈으로</button>
</a>
</div>
)
}
export default PaymentCompletePage
\ No newline at end of file
import axios from 'axios' import axios from 'axios'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import authApi from '../../apis/auth.api' import authApi from '../../apis/auth.api'
import kakaopayApi from '../../apis/kakaopay.api'
import reservationApi from '../../apis/reservation.api' import reservationApi from '../../apis/reservation.api'
import { useAuth } from '../../context/auth_context' import { useAuth } from '../../context/auth_context'
import catchErrors from '../../utils/catchErrors' import catchErrors from '../../utils/catchErrors'
...@@ -73,23 +74,25 @@ const Payment = ({ location }) => { ...@@ -73,23 +74,25 @@ const Payment = ({ location }) => {
userType: "member", userType: "member",
user: userInfo.id, user: userInfo.id,
...ticketInfo, ...ticketInfo,
timetable: 1 timetableId: 1
}) })
const responsekakao = await axios.post('/api/kakaopay/test/single', { const responsekakao = await kakaopayApi.approveReq({
cid: 'TC0ONETIME', cid: 'TC0ONETIME',
partner_order_id: 'butter_studio', partner_order_id: 'butter_studio',
partner_user_id: '000000'+ (userInfo.id || guestInfo.id), partner_user_id: '000000' + guestID,
item_name: ticketInfo.title, item_name: ticketInfo.title,
item_code: ticketInfo.movieId,
quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior, quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior,
total_amount: ticketInfo.totalFee, total_amount: ticketInfo.totalFee,
vat_amount: 0, vat_amount: 0,
tax_free_amount: 0, tax_free_amount: 0,
approval_url: 'http://localhost:3000/paymentcomplete', approval_url: 'http://localhost:3000/paymentcomplete',
fail_url: 'http://localhost:3000/ticket', fail_url: 'http://localhost:3000/paymentfail',
cancel_url: 'http://localhost:3000/ticket', cancel_url: 'http://localhost:3000/paymentfail',
}) })
if (response && responsekakao) { if (response && responsekakao) {
window.location.href = responsekakao.data.redirect_url localStorage.setItem('tid', responsekakao.tid)
window.location.href = responsekakao.redirect_url
} }
} else { } else {
if (guestID) { if (guestID) {
...@@ -99,10 +102,10 @@ const Payment = ({ location }) => { ...@@ -99,10 +102,10 @@ const Payment = ({ location }) => {
...ticketInfo, ...ticketInfo,
timetableId: 1 timetableId: 1
}) })
const responsekakao = await axios.post('/api/kakaopay/test/single', { const responsekakao = await kakaopayApi.approveReq({
cid: 'TC0ONETIME', cid: 'TC0ONETIME',
partner_order_id: 'butter_studio', partner_order_id: 'butter_studio',
partner_user_id: '000000'+ guestID, partner_user_id: '000000' + guestID,
item_name: ticketInfo.title, item_name: ticketInfo.title,
item_code: ticketInfo.movieId, item_code: ticketInfo.movieId,
quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior, quantity: ticketInfo.adult + ticketInfo.youth + ticketInfo.senior,
...@@ -110,12 +113,12 @@ const Payment = ({ location }) => { ...@@ -110,12 +113,12 @@ const Payment = ({ location }) => {
vat_amount: 0, vat_amount: 0,
tax_free_amount: 0, tax_free_amount: 0,
approval_url: 'http://localhost:3000/paymentcomplete', approval_url: 'http://localhost:3000/paymentcomplete',
fail_url: 'http://localhost:3000/ticket', fail_url: 'http://localhost:3000/paymentfail',
cancel_url: 'http://localhost:3000/ticket', cancel_url: 'http://localhost:3000/paymentfail',
}) })
if (response||responsekakao) { if (response && responsekakao) {
localStorage.setItem('tid',responsekakao.data.tid) localStorage.setItem('tid', responsekakao.tid)
window.location.href = responsekakao.data.redirect_url window.location.href = responsekakao.redirect_url
} }
} else { } else {
alert("비회원 정보를 모두 입력 후 비회원 정보 저장 버튼을 눌러주세요.") alert("비회원 정보를 모두 입력 후 비회원 정보 저장 버튼을 눌러주세요.")
......
...@@ -25,7 +25,7 @@ const TheaterPage = () => { ...@@ -25,7 +25,7 @@ const TheaterPage = () => {
<TheaterInfo /> <TheaterInfo />
</div> </div>
<div className="tab-pane fade" id="stillcut" role="tabpanel" aria-labelledby="stillcut-tab"> <div className="tab-pane fade" id="stillcut" role="tabpanel" aria-labelledby="stillcut-tab">
<div>상영시간표</div> <div className="pb-5">상영시간표</div>
</div> </div>
<div className="tab-pane fade" id="review" role="tabpanel" aria-labelledby="review-tab"> <div className="tab-pane fade" id="review" role="tabpanel" aria-labelledby="review-tab">
<div className="row justify-content-center"> <div className="row justify-content-center">
......
import axios from 'axios' import axios from 'axios'
import config from "../config/app.config.js"; import config from "../config/app.config.js";
const success = async(req, res) => { const success = async (req, res) => {
try { try {
// const { cid, tid, partner_order_id, partner_user_id, pg_token } = req.body // const { cid, tid, partner_order_id, partner_user_id, pg_token } = req.body
const item = req.body const item = req.body
...@@ -20,12 +20,10 @@ const success = async(req, res) => { ...@@ -20,12 +20,10 @@ const success = async(req, res) => {
}) })
const resp = response.data const resp = response.data
console.log('resp', resp) console.log('resp', resp)
res.json({...resp}) res.json({ ...resp })
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
} }
const fail = (req, res) => { const fail = (req, res) => {
...@@ -34,10 +32,27 @@ const fail = (req, res) => { ...@@ -34,10 +32,27 @@ const fail = (req, res) => {
}) })
} }
const cancel = (req, res) => { const cancel = async (req, res) => {
return res.json({ try {
message: 'Canceled' const item = req.body
}) const data = []
for (let property in item) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(item[property]);
data.push(encodedKey + "=" + encodedValue);
}
const bodyData = data.join('&')
const response = await axios.post('https://kapi.kakao.com/v1/payment/cancel', bodyData, {
headers: {
'Authorization': `KakaoAK ${config.kakaoAdminKey}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
})
const resp = response.data
res.json(resp)
} catch (error) {
console.log(error)
}
} }
const singleTest = async (req, res) => { const singleTest = async (req, res) => {
......
...@@ -81,9 +81,46 @@ const saveReservation = async (req, res) => { ...@@ -81,9 +81,46 @@ const saveReservation = async (req, res) => {
} }
} }
const saveTid = async (req, res) => {
try {
const { tid } = req.body
const token = req.cookies.butterStudio;
const { id, role } = jwt.verify(token, config.jwtSecret);
await Reservation.update({ tid: tid }, {
where: {
userType: role,
user: id
}
})
res.json({ message: 'Tid 저장 OK' })
} catch (error) {
console.log(error)
res.status(500).send(error.message || "예매DB에 Tid 저장 실패")
}
}
const deleteReservation = async(req,res)=>{
try {
const token = req.cookies.butterStudio;
const { id, role } = jwt.verify(token, config.jwtSecret);
await Reservation.destroy({
where: {
userType: role,
user: id
}
});
res.json({ message: '결제실패로 인한 예매DB삭제' })
} catch (error) {
console.log(error)
res.status(500).send(error.message || "예매DB 삭제실패")
}
}
export default { export default {
findReservedSeats, findReservedSeats,
findReservation, findReservation,
findOneReservation, findOneReservation,
saveReservation saveReservation,
saveTid,
deleteReservation
} }
\ No newline at end of file
...@@ -10,7 +10,7 @@ dotenv.config({ ...@@ -10,7 +10,7 @@ dotenv.config({
}); });
sequelize sequelize
.sync({ force: true }) .sync({ force: false })
.then(async () => { .then(async () => {
await Promise.all( await Promise.all(
Object.keys(ROLE_NAME).map((name) => { Object.keys(ROLE_NAME).map((name) => {
......
...@@ -11,9 +11,6 @@ const ReservationModel = (sequelize) => { ...@@ -11,9 +11,6 @@ const ReservationModel = (sequelize) => {
primaryKey: true, primaryKey: true,
autoIncrement: true, autoIncrement: true,
}, },
// reservationNum: {
// type: DataTypes.INTEGER,
// },
movieId: { movieId: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
}, },
......
...@@ -15,4 +15,10 @@ router.route('/findonereservation') ...@@ -15,4 +15,10 @@ router.route('/findonereservation')
router.route('/save') router.route('/save')
.post(reservationCtrl.saveReservation) .post(reservationCtrl.saveReservation)
router.route('/savetid')
.post(reservationCtrl.saveTid)
router.route('/delete')
.get(reservationCtrl.deleteReservation)
export default router; export default router;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment