fix(billing): stop back-office edits from changing Payple renewal charges
This commit is contained in:
parent
957e136789
commit
f456d737c4
8 changed files with 639 additions and 3 deletions
|
|
@ -8,7 +8,6 @@ import {
|
|||
actorEmail,
|
||||
adminErrorResponse,
|
||||
adminJsonResponse,
|
||||
adminRpcError,
|
||||
parsePagination,
|
||||
parseSubscriptionMutationRequest,
|
||||
readAdminJson,
|
||||
|
|
@ -19,6 +18,7 @@ import {
|
|||
validateQueryKeys,
|
||||
validateSubscriptionRpcResult,
|
||||
} from '../_shared/admin-contract.ts'
|
||||
import { subscriptionRpcError } from './rpc-error.ts'
|
||||
|
||||
const SUBSCRIPTION_COLUMNS = 'id, user_id, tier, status, provider, payment_provider, current_period_start, current_period_end, overage_credits, admin_note, cancel_at, created_at, updated_at'
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ async function mutateSubscription(req: Request, action: SubscriptionAction): Pro
|
|||
p_admin_note: mutation.adminNote ?? null,
|
||||
p_memo: mutation.memo,
|
||||
})
|
||||
if (error) throw adminRpcError(error)
|
||||
if (error) throw subscriptionRpcError(error)
|
||||
const response = validateSubscriptionRpcResult(data, mutation)
|
||||
return adminJsonResponse(response, corsHeaders, action === 'create' ? 201 : 200)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
import { PROVIDER_MANAGED_SUBSCRIPTION, subscriptionRpcError } from './rpc-error.ts'
|
||||
|
||||
function assert(condition: boolean, message: string): asserts condition {
|
||||
if (!condition) throw new Error(message)
|
||||
}
|
||||
|
||||
Deno.test('provider-owned subscription edits surface as a specific 409', () => {
|
||||
const error = subscriptionRpcError({ code: '23514', message: 'provider_managed_subscription' })
|
||||
assert(error.status === 409, `status 409, got ${error.status}`)
|
||||
assert(error.code === PROVIDER_MANAGED_SUBSCRIPTION, `code ${error.code}`)
|
||||
})
|
||||
|
||||
Deno.test('other subscription RPC errors keep the shared admin mapping', () => {
|
||||
const forbidden = subscriptionRpcError({ code: '42501', message: 'admin_role_required' })
|
||||
assert(forbidden.status === 403 && forbidden.code === 'admin_role_required', 'admin role mapping kept')
|
||||
const conflict = subscriptionRpcError({ code: '23514', message: 'some_other_check' })
|
||||
assert(conflict.status === 409 && conflict.code === 'admin_operation_conflict', 'generic conflict kept')
|
||||
})
|
||||
20
server/supabase/functions/admin-subscriptions/rpc-error.ts
Normal file
20
server/supabase/functions/admin-subscriptions/rpc-error.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// server/supabase/functions/admin-subscriptions/rpc-error.ts
|
||||
// admin_mutate_subscription_v1 오류를 공개 오류 코드로 바꾼다. 구독 전용 거절 사유를
|
||||
// 먼저 판별하고, 나머지는 공통 관리자 RPC 매핑(adminRpcError)에 맡긴다.
|
||||
|
||||
import { AdminPublicError, adminRpcError } from '../_shared/admin-contract.ts'
|
||||
|
||||
type AdminRpcErrorLike = Parameters<typeof adminRpcError>[0]
|
||||
|
||||
/**
|
||||
* 결제 사업자(Payple·스토어)가 소유한 구독의 등급·상태·기간을 관리자 화면에서 바꾸려 할 때
|
||||
* SQL이 던지는 사유. 사업자가 청구 조건의 정본이므로 관리자 수정은 충돌(409)로 거절한다.
|
||||
*/
|
||||
export const PROVIDER_MANAGED_SUBSCRIPTION = 'provider_managed_subscription'
|
||||
|
||||
export function subscriptionRpcError(error: AdminRpcErrorLike): AdminPublicError {
|
||||
if ((error.message ?? '').includes(PROVIDER_MANAGED_SUBSCRIPTION)) {
|
||||
return new AdminPublicError(409, PROVIDER_MANAGED_SUBSCRIPTION)
|
||||
}
|
||||
return adminRpcError(error)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue