진단 크레딧 구매 서비스 + 컨트롤러 + 라우트
ID: d109c3f2-a8d2-43dc-a1cd-427b31bd829b
## 작업 내용
### 1. Payments::DiagnosisCreditPurchaseService (`app/services/payments/diagnosis_credit_purchase_service.rb`)
기존 `Payments::CreditPurchaseService` (워크스페이스용)를 참고하여 개인 진단 크레딧 구매 서비스 생성.
```ruby
module Payments
class DiagnosisCreditPurchaseService
PRICE_PER_CREDIT = 3_000 # 원 (VAT 포함)
def initialize(user:, quantity: 1, locale: "ko")
@user = user
@quantity = quantity.to_i
@locale = locale
end
# PG 결제 준비
def prepare_checkout!
amount = @quantity * PRICE_PER_CREDIT
order_id = OrderIdGenerator.generate(payment_type: "DIAG_CREDIT", user_id: @user.id)
payment = Payment.create!(
user: @user,
order_id: order_id,
amount: amount,
currency: "KRW",
provider: "toss_payments",
payment_type: "diagnosis_credit",
description: "진단 크레딧 #{@quantity}개",
status: "pending",
metadata: { "quantity" => @quantity, "product_type" => "diagnosis_credit" }
)
{
payment_id: payment.id,
order_id: order_id,
amount: amount,
order_name: "진단 크레딧 #{@quantity}개",
customer_key: "customer_#{@user.id}"
}
end
# 결제 완료 후 크레딧 지급
def self.complete_purchase!(payment)
quantity = payment.metadata&.dig("quantity").to_i
return unless quantity > 0
return unless payment.metadata&.dig("product_type") == "diagnosis_credit"
user = payment.user
credit = user.ensure_credit!
payment.with_lock do
return if CreditTransaction.exists?(payment_id: payment.id, credit_type: "diagnosis")
credit.add_diagnosis!(
quantity,
description: "진단 크레딧 구매 (#{quantity}개)",
payment: payment
)
end
end
end
end
```
### 2. Payment 모델 수정
- `payment_type` validation에 `diagnosis_credit` 추가 (기존 validation 확인 후)
### 3. ConfirmationService 수정 (`app/services/payments/confirmation_service.rb`)
- 결제 완료 후 처리 로직에 diagnosis_credit 케이스 추가:
```ruby
# 기존 complete_purchase 로직 안에
if payment.payment_type == "diagnosis_credit"
DiagnosisCreditPurchaseService.complete_purchase!(payment)
end
```
### 4. DiagnosisCreditsController (`app/controllers/diagnosis_credits_controller.rb`)
```ruby
class DiagnosisCreditsController < ApplicationController
layout "authenticated"
def new
# 구매 페이지 표시
@quantity = (params[:quantity] || 1).to_i
@price_per_credit = Payments::DiagnosisCreditPurchaseService::PRICE_PER_CREDIT
@total = @quantity * @price_per_credit
end
def create
quantity = (params[:quantity] || 1).to_i
service = Payments::DiagnosisCreditPurchaseService.new(
user: Current.user,
quantity: quantity,
locale: I18n.locale
)
checkout_data = service.prepare_checkout!
render json: checkout_data
end
end
```
### 5. 라우트 추가 (`config/routes.rb`)
locale scope 내부에:
```ruby
resources :diagnosis_credits, only: %i[new create]
```
### 6. Product seed (선택)
기존 Product 모델 확인 후 필요하면 seed 추가.
### 7. TDD
- `test/services/payments/diagnosis_credit_purchase_service_test.rb`:
- prepare_checkout!: Payment(pending) 생성, amount 검증
- complete_purchase!: diagnosis_balance 증가, 멱등성 검증
- `test/controllers/diagnosis_credits_controller_test.rb`:
- GET new: 200 응답
- POST create: checkout_data JSON 반환
## 완료 기준
- 진단 크레딧 구매 → PG 결제 → diagnosis_balance 증가
- 멱등성 보장 (중복 결제 방지)
- 테스트 통과
첨부 이미지
이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)
JPEG, PNG, GIF, WebP / 최대 10MB
활동 로그
-
팀팀리드 상태 변경: 리뷰 → 완료
2026년 03월 26일 06:35:51
-
팀팀리드 상태 변경: 할 일 → 리뷰
2026년 03월 26일 06:01:27