코호트 일반결제 — Toss::PaymentService + checkout/confirm + Payment/CohortEnrollment 생성 + 테스트
ID: 0417fe3c-4546-4ab0-ab0d-d45d62d932eb
## 목표
PRD Section 11.2 기반 Toss::PaymentService 구현. 코호트 1회성 결제. checkout 파라미터 생성, confirm 처리, Payment + CohortEnrollment 생성.
## 현재 상태
- Toss::Client 구현 완료 (confirm_payment, cancel_payment, get_payment)
- Payment 모델: belongs_to :user, belongs_to :cohort(optional). toss_payment_key, toss_order_id, amount, status enum
- CohortEnrollment 모델: belongs_to :cohort, belongs_to :user. status enum
- Cohort 모델: name, price_cents 등
## PRD 코드 (Section 11.2)
```ruby
class Toss::PaymentService
def initialize(user:, plan:, cohort: nil)
@user = user
@plan = plan
@cohort = cohort
@client = Toss::Client.new
end
def checkout_params
{ amount: amount, orderId: generate_order_id, orderName: order_name,
customerKey: @user.toss_customer_key, customerName: @user.name,
customerEmail: @user.email_address,
successUrl: "#{ENV["APP_URL"]}/payments/success",
failUrl: "#{ENV["APP_URL"]}/payments/fail" }
end
def confirm(payment_key:, order_id:)
result = @client.confirm_payment(payment_key: payment_key, order_id: order_id, amount: amount)
return Result.failure(result.error_message) unless result.success?
save_payment(result.data, payment_key, order_id)
activate_plan
Result.success
end
private
def amount
case @plan
when "cohort" then @cohort&.price_cents || 2_990_000
else raise "일반결제는 cohort만 지원"
end
end
def order_name = "VALUEIT #{@cohort&.name || @plan.upcase}"
def generate_order_id = "valueit-#{@plan}-#{@user.id}-#{Time.current.to_i}"
def save_payment(data, payment_key, order_id)
@user.payments.create!(
cohort: @cohort,
toss_payment_key: payment_key, toss_order_id: order_id,
toss_order_name: order_name, amount: amount,
payment_method: data["method"],
card_company: data.dig("card", "company"),
card_number: data.dig("card", "number"),
status: :done, paid_at: Time.current
)
end
def activate_plan
if @plan == "cohort" && @cohort
@user.cohort_enrollments.create!(cohort: @cohort, status: :active, paid_at: Time.current)
@user.update!(role: :cohort)
end
end
end
```
## 구현 사항
1. **app/services/toss/payment_service.rb** — PRD 코드 기반
2. **Result 패턴**: 간단한 Result struct (success/failure) — 또는 OpenStruct 사용
3. **⚠️ PRD의 `@user.email`을 `@user.email_address`로 변경** (Rails 8 auth generator가 email_address 컬럼 사용)
4. **⚠️ PRD의 `plan:` 컬럼은 payments 테이블에 없음** — save_payment에서 plan 컬럼 제거
5. **의존성 주입**: client: 파라미터로 테스트 용이성
6. **테스트**: checkout_params 생성, confirm 성공(Payment+CohortEnrollment 생성, User role 변경), confirm 실패
### ⚠️ 주의
- services/toss/ 범위만 (developer-2는 launch/ 작업 중)
- Payment, CohortEnrollment, User, Cohort 모델 건드리지 않기
- email_address 컬럼명 주의 (PRD의 email과 다름)
### 완료 기준
- checkout 파라미터 생성
- confirm → Payment + CohortEnrollment 생성 + User role :cohort
- 실패 시 Result.failure
- bin/rails test 전체 통과
첨부 이미지
이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)
JPEG, PNG, GIF, WebP / 최대 10MB
활동 로그
-
Ddeveloper-1 상태 변경: 할 일 → 리뷰
2026년 03월 26일 11:28:55