반응형
◆ 신용카드 결제 처리
▶ 스트라이프 API 의 테스트 환경을 위한 API 와 신용카드 번호
https://stripe.com/docs/testing
▶ 프론트엔드의 스트라이프 API를 이용한 토큰 생성
let { token } = await this.props.stripe.createToken({ name: this.state.name });
▶ 신용카드 결제를 처리하는데 필요한 정보
-
스트라이프 API가 제공하는 신용카드 토큰
-
주문자의 사용자 ID
-
주문하는 상품의 ID
-
상품판매가격
-
카드를 나중에 다시 사용할 수 있도록 해당 정보 저장 여부
-
미리 저장된 카드 사용 여부
▶ FrontEnd 프로젝트의 creditcard.js 파일의 메서드 수정
async handleSubmit(event) {
event.preventDefault();
let id = "";
if (!this.state.useExisting) {
let { token } = await this.props.stripe.createToken({ name: this.state.name });
if (token == null) {
console.log("invalid token");
this.setState({ status: FAILEDSTATE });
return;
}
id = token.id;
}
let response = await fetch("/users/charge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: id,
customer_id: this.props.user,
product_id: this.props.productid,
sell_price: this.props.price,
rememberCard: this.state.remember !== undefined,
useExisting: this.state.useExisting
})
});
// let response = await this.sendChargeRequest(token,false);
if (response.ok) {
console.log("Purchase Complete!");
this.setState({ status: SUCCESSSTATE });
} else {
this.setState({ status: FAILEDSTATE });
}
}
◆ BackEnd 에서 신용카드 결제 요청 처리
▶ 순서
-
프론트엔드가 보낸 토큰을 처리하는 *stripe.CustomerParams 타입 인스턴스를 생성하는데 SetToken() 메서드를 사용해 토큰을 설정
-
stripe.CustomerParams 타입을 전달받는 *stripe.Customer 타입 인스턴스를 생성하는데 customer.New() 함수를 사용
-
수량, 통화 등의 결제 관련 정보를 저장하는 *stripe.ChargeParams 타입 인스턴스를 생성
-
*stripe.ChargeParams 타입은 스트라이프 사용자 ID 없이 생성할 수 없는데 이 값은 2단계의 *stripe.Customer 인스턴스에 저장돼 있음
-
해당 신용카드 정보를 다음에 다시 사용하고 싶다면 스트라이프 사용자 ID 를 저장
-
*stripe.ChargeParams 타입 매개변수를 받는 charge.New() 메서드를 호출하고 결제를 요청
▶ handler.go 파일의 Charge 메서드 수정
func (h *Handler) Charge(c *gin.Context) {
if h.db == nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "server database error"})
return
}
//프론트엔드에서 전달받은 구조체를 정의
request := struct {
models.Order
Remember bool `json:"rememberCard"`
UseExisting bool `json:"useExisting"`
Token string `json:"token"`
}{}
//JSON 형식의 요청 데이터를 request 구조체로 변환
err := c.ShouldBindJSON(&request)
log.Printf("request: %+v \n", request)
if err != nil {
c.JSON(http.StatusBadRequest, request)
return
}
stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
//stripe.ChargeParams 타입 인스턴스를 생성
chargeP := &stripe.ChargeParams{
Amount: stripe.Int64(int64(request.Price)),
Currency: stripe.String("usd"),
Description: stripe.String("GoMusic charge..."),
}
//스트라이프 사용자 ID를 초기화
stripeCustomerID := ""
//이미지 저장해 둔 신용카드로 결제하는 경우라면 데이터베이스에서 스트라이프 사용자 ID를 조회
if request.UseExisting {
//저장된 카드 사용
log.Println("Getting credit card id...")
stripeCustomerID, err = h.db.GetCreditCardCID(request.CustomerID)
if err != nil {
log.Println(err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
} else {
cp := &stripe.CustomerParams{}
cp.SetSource(request.Token)
customer, err := customer.New(cp)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
stripeCustomerID = customer.ID
//스트라이프 사용자 ID를 저장하고 데이터베이스에 저장된 사용자 ID 와 연결
if request.Remember {
//save card!!
err = h.db.SaveCreditCardForCustomer(request.CustomerID, stripeCustomerID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
}
}
//결제 요청
chargeP.Customer = stripe.String(stripeCustomerID)
//신용카드 결제 요청
_, err = charge.New(chargeP)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
//데이터베이스에 주문 내용을 저장
err = h.db.AddOrder(request.Order)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
}
}
▶ dblayer.go 파일의 인터페이스에 메서드 추가
type DBLayer interface {
GetAllProducts() ([]models.Product, error)
GetPromos() ([]models.Product, error)
GetCustomerByName(string, string) (models.Customer, error)
GetCustomerByID(int) (models.Customer, error)
GetProduct(int) (models.Product, error)
AddUser(models.Customer) (models.Customer, error)
SignInUser(username, password string) (models.Customer, error)
SignOutUserById(int) error
GetCustomerOrdersByID(int) ([]models.Order, error)
AddOrder(models.Order) error
GetCreditCardCID(int) (string, error)
SaveCreditCardForCustomer(int, string) error
}
▶ orm.go 파일에서 메서드 구현
func (db *DBORM) AddOrder(order models.Order) error {
return db.Create(&order).Error
}
func (db *DBORM) GetCreditCardCID(id int) (string, error) {
cusomterWithCCID := struct {
models.Customer
CCID string `gorm:"column:cc_customerid"`
}{}
return cusomterWithCCID.CCID, db.First(&cusomterWithCCID, id).Error
}
func (db *DBORM) SaveCreditCardForCustomer(id int, ccid string) error {
result := db.Table("customers").Where("id=?", id)
return result.Update("cc_customerid", ccid).Error
}
▶ handler.go 파일의 NewHandler 파일 수정
func NewHandler(db, constring string) (HandlerInterface, error) {
db, err := dblayer.NewORM(db, constring)
if err != nil {
return nil, err
}
return &Handler{
db: db,
}, nil
}
반응형
'IT 초보코딩의 세계 > Go 언어' 카테고리의 다른 글
Go 언어 Back End 제작해보기(패스워드 해싱) 6장 (3) | 2023.05.26 |
---|---|
Go 언어 Back End 제작해보기(데이터베이스) 5장 (1) | 2023.05.25 |
Go 언어 Back End 제작해보기(보안) 4장 (8) | 2023.05.24 |
Go 언어 Back End 제작해보기(미들웨어) 3장 (4) | 2023.05.23 |
Go 언어 Back End 제작해보기(라우팅 설정) 2장 (10) | 2023.05.22 |
댓글