Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
419a3c8
스프링 프로젝트 설정 및 기본 회원 데이터 세팅
P-Taeyoung Dec 23, 2025
bc5c885
Merge pull request #1 from P-Taeyoung/0001
P-Taeyoung Dec 23, 2025
b1b31e8
포스트 기본 데이터 세팅
P-Taeyoung Dec 23, 2025
73a51e3
0003
P-Taeyoung Dec 23, 2025
bebdca5
Merge pull request #2 from P-Taeyoung/0003
P-Taeyoung Dec 23, 2025
7c3927d
0004
P-Taeyoung Dec 23, 2025
a65e112
0005
P-Taeyoung Dec 23, 2025
5221197
0006
P-Taeyoung Dec 23, 2025
7010b4c
0007
P-Taeyoung Dec 23, 2025
06d0002
0008
P-Taeyoung Dec 24, 2025
4aaac18
0009
P-Taeyoung Dec 24, 2025
164f119
0010
P-Taeyoung Dec 24, 2025
5de539a
0011
P-Taeyoung Dec 24, 2025
949f639
0012
P-Taeyoung Dec 24, 2025
ca02d64
0013
P-Taeyoung Dec 24, 2025
23b8d9d
0014
P-Taeyoung Dec 24, 2025
237cbeb
0015
P-Taeyoung Dec 24, 2025
559c527
0016
P-Taeyoung Dec 24, 2025
01c51fa
0017
P-Taeyoung Dec 24, 2025
fd9f58c
0018,0019
P-Taeyoung Dec 24, 2025
e711e88
0020
P-Taeyoung Dec 24, 2025
5331caf
0021
P-Taeyoung Dec 24, 2025
a588b90
0022
P-Taeyoung Dec 24, 2025
81ade45
0023
P-Taeyoung Dec 26, 2025
2bc1235
0024
P-Taeyoung Dec 26, 2025
1f7a2a7
0025
P-Taeyoung Dec 26, 2025
e9780ef
0026
P-Taeyoung Dec 26, 2025
cfa892d
0027
P-Taeyoung Dec 26, 2025
19ca478
0028
P-Taeyoung Dec 26, 2025
04c2201
0029
P-Taeyoung Dec 26, 2025
aeeae79
0030
P-Taeyoung Dec 26, 2025
828918a
0031
P-Taeyoung Dec 29, 2025
e57bfb0
0032
P-Taeyoung Dec 29, 2025
f80bd02
0033
P-Taeyoung Dec 29, 2025
7e05d36
0034
P-Taeyoung Dec 29, 2025
9cd746d
0035
P-Taeyoung Dec 29, 2025
e382f5e
0036
P-Taeyoung Dec 29, 2025
24ac80e
0036
P-Taeyoung Dec 29, 2025
f9dc247
0036
P-Taeyoung Dec 29, 2025
16e1195
0037
P-Taeyoung Dec 29, 2025
3f16dbf
0038
P-Taeyoung Dec 29, 2025
a510551
0038
P-Taeyoung Dec 29, 2025
e60489d
0039
P-Taeyoung Dec 29, 2025
b32ae91
0039
P-Taeyoung Dec 29, 2025
bcbeeeb
0040
P-Taeyoung Dec 30, 2025
6613d87
0041
P-Taeyoung Dec 30, 2025
82f4bec
0042
P-Taeyoung Dec 30, 2025
d730af5
0043
P-Taeyoung Dec 30, 2025
dc4a87c
0044
P-Taeyoung Dec 30, 2025
cf91c9a
0045
P-Taeyoung Dec 30, 2025
750c425
0046
P-Taeyoung Dec 30, 2025
158f7a8
0047
P-Taeyoung Dec 30, 2025
7c0cf6d
0048
P-Taeyoung Dec 30, 2025
d8949a3
0049
P-Taeyoung Dec 31, 2025
cccc4d4
0050
P-Taeyoung Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ out/

### VS Code ###
.vscode/


### Custom ###
db_dev.mv.db
db_dev.trace.db
.env
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-batch")
testImplementation("org.springframework.batch:spring-batch-test")
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
Expand Down
18 changes: 18 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
- # 토스 페이먼츠
- [토스 페이먼츠, 내 개발정보](https://developers.tosspayments.com/my/api-logs)
- API 개별 연동 키
- 테스트 클라이언트 키
- 시크릿 키
- API 로그
- 테스트 결제내역

# 토스 페이먼츠 테스트

- [결제시도](https://codepen.io/jangka44/debug/yyJBXaM)
- [소스코드](https://codepen.io/jangka44/pen/yyJBXaM?editors=1000)
- [최종승인](https://codepen.io/jangka44/debug/GgqKEWV)
- 직접 접근 금지
- [소스코드](https://codepen.io/jangka44/pen/GgqKEWV?editors=1000)
- [결제실패](https://codepen.io/jangka44/debug/xbOKrdJ)
- 직접 접근 금지
- [소스코드](https://codepen.io/jangka44/pen/xbOKrdJ?editors=1000)
2 changes: 2 additions & 0 deletions src/main/java/com/back/BackApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class BackApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.back.boundedContext.cash.app;

import org.springframework.stereotype.Service;

import com.back.boundedContext.cash.domain.CashLog;
import com.back.boundedContext.cash.domain.Wallet;
import com.back.global.eventPublisher.EventPublisher;
import com.back.shared.cash.event.CashOrderPaymentFailedEvent;
import com.back.shared.cash.event.CashOrderPaymentSucceededEvent;
import com.back.shared.market.dto.OrderDto;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CashCompleteOrderPaymentUseCase {
private final CashSupport cashSupport;
private final EventPublisher eventPublisher;

public void completeOrderPayment(OrderDto orderDto, long pgPaymentAmount) {
Wallet customerWallet = cashSupport.findWalletByHolderId(orderDto.getCustomerId()).get();
Wallet holdingWallet = cashSupport.findHoldingWallet().get();

if (pgPaymentAmount > 0) {
customerWallet.credit(
pgPaymentAmount,
CashLog.EventType.충전__PG결제_토스페이먼츠,
orderDto.getModelTypeCode(),
orderDto.getId()
);
}

boolean canPay = customerWallet.getBalance() >= orderDto.getSalePrice();

if (canPay) {
customerWallet.debit(
orderDto.getSalePrice(),
CashLog.EventType.사용__주문결제,
orderDto.getModelTypeCode(),
orderDto.getId()
);

holdingWallet.credit(
orderDto.getSalePrice(),
CashLog.EventType.임시보관__주문결제,
orderDto.getModelTypeCode(),
orderDto.getId()
);

eventPublisher.publish(
new CashOrderPaymentSucceededEvent(
orderDto,
pgPaymentAmount
)

);
} else {
eventPublisher.publish(
new CashOrderPaymentFailedEvent(
"400-1",
"충전은 완료했지만 %번 주문을 결제완료처리를 하기에는 예치금이 부족합니다.".formatted(orderDto.getId()),
orderDto,
pgPaymentAmount,
pgPaymentAmount - customerWallet.getBalance()
)
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.back.boundedContext.cash.app;

import org.springframework.stereotype.Service;

import com.back.boundedContext.cash.domain.CashLog;
import com.back.boundedContext.cash.domain.Wallet;
import com.back.shared.payout.dto.PayoutDto;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CashCompletePayoutUseCase {
private final CashSupport cashSupport;


public void completePayout(PayoutDto payout) {
Wallet holdingWallet = cashSupport.findHoldingWallet().get();
Wallet payeeWallet = cashSupport.findWalletByHolderId(payout.getPayeeId()).get();

holdingWallet.debit(
payout.getAmount(),
payout.isPayeeSystem() ? CashLog.EventType.정산지급__상품판매_수수료 : CashLog.EventType.정산지급__상품판매_대금,
payout.getModelTypeCode(),
payout.getId()
);

payeeWallet.credit(
payout.getAmount(),
payout.isPayeeSystem() ? CashLog.EventType.정산수령__상품판매_수수료 : CashLog.EventType.정산수령__상품판매_대금,
payout.getModelTypeCode(),
payout.getId()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.back.boundedContext.cash.app;

import org.springframework.stereotype.Service;

import com.back.boundedContext.cash.domain.CashMember;
import com.back.boundedContext.cash.domain.Wallet;
import com.back.boundedContext.cash.out.CashMemberRepository;
import com.back.boundedContext.cash.out.WalletRepository;
import com.back.shared.cash.dto.CashMemberDto;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CashCreateWalletUseCase {
private final CashMemberRepository cashMemberRepository;
private final WalletRepository walletRepository;

public Wallet createWallet(CashMemberDto member) {
CashMember _member = cashMemberRepository.getReferenceById(member.getId());
Wallet wallet = new Wallet(_member);

return walletRepository.save(wallet);
}
}
65 changes: 65 additions & 0 deletions src/main/java/com/back/boundedContext/cash/app/CashFacade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.back.boundedContext.cash.app;

import java.util.Optional;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.back.boundedContext.cash.domain.CashMember;
import com.back.boundedContext.cash.domain.Wallet;
import com.back.shared.cash.dto.CashMemberDto;
import com.back.shared.market.dto.OrderDto;
import com.back.shared.member.dto.MemberDto;
import com.back.shared.payout.dto.PayoutDto;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CashFacade {
private final CashSupport cashSupport;
private final CashSyncMemberUseCase cashSyncMemberUseCase;
private final CashCreateWalletUseCase cashCreateWalletUseCase;
private final CashCompleteOrderPaymentUseCase cashCompleteOrderPaymentUseCase;
private final CashCompletePayoutUseCase cashCompletePayoutUseCase;

@Transactional
public CashMember syncMember(MemberDto memberDto) {

return cashSyncMemberUseCase.syncMember(memberDto);
}

@Transactional
public Wallet createWallet(CashMemberDto holder) {

return cashCreateWalletUseCase.createWallet(holder);
}

@Transactional(readOnly = true)
public Optional<CashMember> findMemberByUserName(String userName) {

return cashSupport.findMemberByUserName(userName);
}

@Transactional(readOnly = true)
public Optional<Wallet> findWalletByHolder(CashMember holder) {

return cashSupport.findWalletByHolder(holder);
}

@Transactional
public void completeOrderPayment(OrderDto orderDto, long pgPaymentAmount) {
cashCompleteOrderPaymentUseCase.completeOrderPayment(orderDto, pgPaymentAmount);
}

@Transactional(readOnly = true)
public Optional<Wallet> findWalletByHolderId(int id) {
return cashSupport.findWalletByHolderId(id);
}

//정산 집행 후 시스템,회원 지갑에 정산 내역 반영
@Transactional
public void completePayout(PayoutDto payout) {
cashCompletePayoutUseCase.completePayout(payout);
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/back/boundedContext/cash/app/CashSupport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.back.boundedContext.cash.app;

import java.util.Optional;

import org.springframework.stereotype.Component;

import com.back.boundedContext.cash.domain.CashMember;
import com.back.boundedContext.cash.domain.CashPolicy;
import com.back.boundedContext.cash.domain.Wallet;
import com.back.boundedContext.cash.out.CashMemberRepository;
import com.back.boundedContext.cash.out.WalletRepository;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class CashSupport {
private final CashMemberRepository cashMemberRepository;
private final WalletRepository walletRepository;

public Optional<CashMember> findMemberByUserName(String userName) {
return cashMemberRepository.findByUserName(userName);
}

public Optional<Wallet> findWalletByHolder(CashMember holder) {
return walletRepository.findByHolder(holder);
}

public Optional <Wallet> findWalletByHolderId(int holderId) {
return walletRepository.findByHolderId(holderId);
}

public Optional <Wallet> findHoldingWallet() {
return walletRepository.findByHolderId(CashPolicy.HOLDING_MEMBER_ID);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.back.boundedContext.cash.app;

import org.springframework.stereotype.Service;

import com.back.boundedContext.cash.domain.CashMember;
import com.back.boundedContext.cash.out.CashMemberRepository;
import com.back.global.eventPublisher.EventPublisher;
import com.back.shared.cash.event.CashMemberCreateEvent;
import com.back.shared.member.dto.MemberDto;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CashSyncMemberUseCase {
private final CashMemberRepository cashMemberRepository;
private final EventPublisher eventPublisher;

public CashMember syncMember(MemberDto memberDto) {

boolean isNew = !cashMemberRepository.existsById(memberDto.getId());

CashMember _member = cashMemberRepository.save(
new CashMember(
memberDto.getId(),
memberDto.getCreateTime(),
memberDto.getModifyTime(),
memberDto.getUserName(),
"",
memberDto.getNickName(),
memberDto.getActivityScore()
)
);

if (isNew) {
eventPublisher.publish(
new CashMemberCreateEvent(
_member.toDto()
)
);
}

return _member;
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/back/boundedContext/cash/domain/CashLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.back.boundedContext.cash.domain;

import com.back.global.jpa.entity.BaseIdAndTime;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "CASH_CASH_LOG")
@NoArgsConstructor
public class CashLog extends BaseIdAndTime {
public enum EventType {
충전__무통장입금,
충전__PG결제_토스페이먼츠,
출금__통장입금,
사용__주문결제,
임시보관__주문결제,
정산지급__상품판매_수수료,
정산수령__상품판매_수수료,
정산지급__상품판매_대금,
정산수령__상품판매_대금,
}

@Enumerated(EnumType.STRING)
private EventType eventType;
private String relTypeCode;
private int relId;
@ManyToOne(fetch = FetchType.LAZY)
private CashMember member;
@ManyToOne(fetch = FetchType.LAZY)
private Wallet wallet;
private long amount;
private long balance;

public CashLog(EventType eventType, String relTypeCode, int relId, CashMember member, Wallet wallet, long amount, long balance) {
this.eventType = eventType;
this.relTypeCode = relTypeCode;
this.relId = relId;
this.member = member;
this.wallet = wallet;
this.amount = amount;
this.balance = balance;
}
}
Loading