diff --git a/Api/build.gradle b/Api/build.gradle index 284f86ad..2c40fee9 100644 --- a/Api/build.gradle +++ b/Api/build.gradle @@ -1,5 +1,6 @@ repositories { mavenCentral() + maven { url 'https://jitpack.io' } } dependencies { @@ -8,6 +9,8 @@ dependencies { implementation project(':Common') implementation project(':Infra') implementation project(':Domain') + implementation 'com.github.iamport:iamport-rest-client-java:0.2.23' + } test { diff --git a/Api/src/main/java/picasso/server/api/exchange/controller/ExchangeController.java b/Api/src/main/java/picasso/server/api/exchange/controller/ExchangeController.java new file mode 100644 index 00000000..94ae0e05 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/controller/ExchangeController.java @@ -0,0 +1,38 @@ +package picasso.server.api.exchange.controller; + +import com.siot.IamportRestClient.IamportClient; +import com.siot.IamportRestClient.exception.IamportResponseException; +import com.siot.IamportRestClient.response.IamportResponse; +import com.siot.IamportRestClient.response.Payment; +import jakarta.servlet.http.HttpSession; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import picasso.server.api.exchange.model.request.PostCreateExchangeRequest; +import picasso.server.api.exchange.service.ExchangeService; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +@Slf4j +@RequestMapping("/exchange") +@RequiredArgsConstructor +@RestController +public class ExchangeController { + + private final ExchangeService exchangeService; + private IamportClient api = new IamportClient("REST API KEY", "REST SECRET KEY"); + private String impKey = System.getProperty("IMP"); + +} \ No newline at end of file diff --git a/Api/src/main/java/picasso/server/api/exchange/model/dto/ExchangeDTO.java b/Api/src/main/java/picasso/server/api/exchange/model/dto/ExchangeDTO.java new file mode 100644 index 00000000..ade117f3 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/model/dto/ExchangeDTO.java @@ -0,0 +1,14 @@ +package picasso.server.api.exchange.model.dto; + +import lombok.Builder; +import lombok.Getter; +import picasso.server.domain.domains.items.PaymentHistory; +import picasso.server.domain.domains.items.PGName; +import picasso.server.domain.domains.items.PayMethod; + +@Getter +@Builder +public class ExchangeDTO { + + +} diff --git a/Api/src/main/java/picasso/server/api/exchange/model/request/PostCreateExchangeRequest.java b/Api/src/main/java/picasso/server/api/exchange/model/request/PostCreateExchangeRequest.java new file mode 100644 index 00000000..6e417521 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/model/request/PostCreateExchangeRequest.java @@ -0,0 +1,12 @@ +package picasso.server.api.exchange.model.request; + +import jakarta.validation.Valid; +import lombok.Getter; +import lombok.NoArgsConstructor; +import picasso.server.api.exchange.model.dto.ExchangeDTO; + +@Getter +@NoArgsConstructor +public class PostCreateExchangeRequest { + +} diff --git a/Api/src/main/java/picasso/server/api/exchange/service/ExchangeService.java b/Api/src/main/java/picasso/server/api/exchange/service/ExchangeService.java new file mode 100644 index 00000000..f3823560 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/service/ExchangeService.java @@ -0,0 +1,20 @@ +package picasso.server.api.exchange.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import picasso.server.api.exchange.model.dto.ExchangeDTO; +import picasso.server.api.exchange.model.request.PostCreateExchangeRequest; +import picasso.server.api.exchange.validator.ExchangeValidator; +import picasso.server.domain.domains.items.PaymentHistory; +import picasso.server.domain.domains.repository.ExchangeRepository; + +@Service +@RequiredArgsConstructor +public class ExchangeService { + + private final ExchangeRepository exchangeRepository; + private final ExchangeValidator exchangeValidator; + + +} diff --git a/Api/src/main/java/picasso/server/api/exchange/util/ExchangeUtils.java b/Api/src/main/java/picasso/server/api/exchange/util/ExchangeUtils.java new file mode 100644 index 00000000..7c4c0664 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/util/ExchangeUtils.java @@ -0,0 +1,19 @@ +package picasso.server.api.exchange.util; + +import lombok.RequiredArgsConstructor; +import org.springframework.transaction.annotation.Transactional; +import picasso.server.domain.domains.items.PaymentHistory; +import picasso.server.domain.domains.repository.ExchangeRepository; + +@RequiredArgsConstructor +public class ExchangeUtils { + + private final ExchangeRepository exchangeRepository; + + @Transactional + public void save(PaymentHistory paymentHistory) { + exchangeRepository.save(paymentHistory); + } + + +} diff --git a/Api/src/main/java/picasso/server/api/exchange/validator/ExchangeValidator.java b/Api/src/main/java/picasso/server/api/exchange/validator/ExchangeValidator.java new file mode 100644 index 00000000..9a32c52b --- /dev/null +++ b/Api/src/main/java/picasso/server/api/exchange/validator/ExchangeValidator.java @@ -0,0 +1,17 @@ +package picasso.server.api.exchange.validator; + +import lombok.RequiredArgsConstructor; +import picasso.server.common.annotation.Validator; +import picasso.server.domain.domains.items.PaymentHistory; +import picasso.server.domain.domains.repository.ExchangeRepository; + +@Validator +@RequiredArgsConstructor +public class ExchangeValidator { + + private final ExchangeRepository exchangeRepository; + + public boolean isExchangeValid(PaymentHistory paymentHistory) { + return true; + } +} diff --git a/Api/src/main/resources/static/js/exchange.js b/Api/src/main/resources/static/js/exchange.js new file mode 100644 index 00000000..b073248d --- /dev/null +++ b/Api/src/main/resources/static/js/exchange.js @@ -0,0 +1,52 @@ +var IMP = window.IMP; +IMP.init("imp16618334"); // 재발급 받은 뒤 숨겨버릴 예정 + +var requestPayment = pg_name => { + return IMP.request_pay({ + pg : pg_name, + pay_method : 'card', + merchant_uid: "picasso_" + new Date().getMilliseconds(), // 계속 바뀌게 설정해야함. 결제에서 가장 중요한 정보 -> 이걸로 결제 하나하나를 식별함 + name : 'asdfasdf', + amount : 1004, + buyer_email : 'Iamport@chai.finance', + buyer_name : '아임포트 기술지원팀' + }); +} + +var paymentResult = obj => { + var pg_name = obj.value + return (requestPayment(pg_name), function(response) { + if (response.success) { + var msg = "결제 완료"; + msg += '고유ID : ' + response.imp_uid; + msg += '// 상점 거래ID : ' + response.merchant_uid; + msg += '// 결제 금액 : ' + response.paid_amount; + msg += '// 카드 승인번호 : ' + response.apply_num; + + postPayInfo(true); + alert("결제가 완료되었습니다."); + } else { + var msg = "결제 실패" + msg += "에러 내용" + response.error_msg; + postPayInfo(false); + alert("결제 실패입니다."); + } + }); +} + +function postPayInfo(tof, rsp) { + $.ajax({ + type : 'post', + url : '/pay', + data : { + "pay_result" : tof, + "buyer_name" : rsp.buyer_name, + "buyer_email" : rsp.buyer_email, + "merchant_uid" : rsp.merchant_uid, + "product_name" : rsp.name, + "pg_provider" : rsp.pg_provider, + "amount" : rsp.paid_amount, + "pay_method" : rsp.pay_method + }, + }) +} \ No newline at end of file diff --git a/Api/src/main/resources/templates/exchange.html b/Api/src/main/resources/templates/exchange.html new file mode 100644 index 00000000..9f339547 --- /dev/null +++ b/Api/src/main/resources/templates/exchange.html @@ -0,0 +1,27 @@ + + + + + + +
+

결제하기

+
+ + +
+

결제 금액

+ +
+ + + + + diff --git a/Common/src/main/java/picasso/server/common/annotation/Validator.java b/Common/src/main/java/picasso/server/common/annotation/Validator.java new file mode 100644 index 00000000..d9fc549f --- /dev/null +++ b/Common/src/main/java/picasso/server/common/annotation/Validator.java @@ -0,0 +1,19 @@ +package picasso.server.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.core.annotation.AliasFor; +import org.springframework.stereotype.Component; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface Validator { + @AliasFor(annotation = Component.class) + String value() default ""; +} + diff --git a/Docs/Picasso.dbml b/Docs/Picasso.dbml index 91748d7e..8063c579 100644 --- a/Docs/Picasso.dbml +++ b/Docs/Picasso.dbml @@ -105,26 +105,23 @@ Table Board.article_amount_history [ created_at datetime [default: 'now()', note: '해당 금액 갱신 시간'] } -Table Payment.payment_info [ - headercolor: #2563eb +Table Exchange.payment_history [ + headercolor: #2563eb, note: '결제 히스토리' ] { id long [pk, increment, note: '결제 정보 하나하나에 대한 ID'] - payment_id long - pg varchar(20) [not null, note: ''' + pg varchar [not null, note: ''' 결제 플랫폼 ex) 카카오페이, 토스페이, 이니시스 - ''' + '''] pay_method varchar(20) [not null, default: 'card', note: '결제 방법'] - merchant_uid int [not null, unique, note: '''' + merchant_uid int [not null, unique, note: ''' 주문 번호 : 서버에서 고유하게 지정할 예정. 아마 게시물(경매 물품)의 id를 변형할듯함 '''] - product_name varchar(100) [not null, note: '상품 이름'] + product_name varchar(100) [not null, note: '상품 이름', default: '피카소 포인트 환전'] amount int [not null, note: '결제 가격'] - buyer_id [not null, ref > Auth.user.id, note: '구매자 ID' - buyer_email [not null, note: '구매자 Email'] - buyer_name [not null, note: '구매자 이름'] + buyer_id int [not null, ref: > Auth.user.id, note: '구매자 ID'] } //사용자 정보 관련 그룹 @@ -139,3 +136,8 @@ TableGroup Board_Article { Board.article Board.article_amount_history } + +// 포인트 환전 관련 그룹 +TableGroup Exchange { + Exchange.payment_history +} diff --git a/Domain/src/main/java/picasso/server/domain/domains/items/PGName.java b/Domain/src/main/java/picasso/server/domain/domains/items/PGName.java new file mode 100644 index 00000000..4064bf1e --- /dev/null +++ b/Domain/src/main/java/picasso/server/domain/domains/items/PGName.java @@ -0,0 +1,14 @@ +package picasso.server.domain.domains.items; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PGName { + KAKAO("kakaopay.TC0ONETIME"), + TOSS("tosspay.tosstest"); + + private final String value; +} + diff --git a/Domain/src/main/java/picasso/server/domain/domains/items/PayMethod.java b/Domain/src/main/java/picasso/server/domain/domains/items/PayMethod.java new file mode 100644 index 00000000..1bd81cd8 --- /dev/null +++ b/Domain/src/main/java/picasso/server/domain/domains/items/PayMethod.java @@ -0,0 +1,14 @@ +package picasso.server.domain.domains.items; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PayMethod { + + CARD("카드결제"), + ; + + private final String method; +} diff --git a/Domain/src/main/java/picasso/server/domain/domains/items/PaymentHistory.java b/Domain/src/main/java/picasso/server/domain/domains/items/PaymentHistory.java new file mode 100644 index 00000000..aa269a2b --- /dev/null +++ b/Domain/src/main/java/picasso/server/domain/domains/items/PaymentHistory.java @@ -0,0 +1,36 @@ +package picasso.server.domain.domains.items; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +public class PaymentHistory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + private PGName pgName; + + @Enumerated(EnumType.STRING) + private PayMethod payMethod; + + @NotNull + private String productName; + + @NotNull + private int amount; + + @NotNull + private Long userId; +} diff --git a/Domain/src/main/java/picasso/server/domain/domains/repository/ExchangeRepository.java b/Domain/src/main/java/picasso/server/domain/domains/repository/ExchangeRepository.java new file mode 100644 index 00000000..54047400 --- /dev/null +++ b/Domain/src/main/java/picasso/server/domain/domains/repository/ExchangeRepository.java @@ -0,0 +1,8 @@ +package picasso.server.domain.domains.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import picasso.server.domain.domains.items.PaymentHistory; + +public interface ExchangeRepository extends JpaRepository { + +}