mcpField
S
stripe-refund-dispute-lifecycle

stripe-refund-dispute-lifecycle

github.com/josiahsiegel開発5979 回インストール19 週間前に更新
リポジトリ

stripe-refund-dispute-lifecycle について

Stripe の返金・異議申し立て Webhook に応じて、クレジットや支払い状態を変更する処理を実装する開発者向けスキルです。返金差額の算出、異議ステータスの明示的な判定、サブスクリプションとクレジットパックの返金区別を扱います。

主な機能

  1. 01返金差額の情報源の優先順位
  2. 02異議ステータスの復元許可リスト
  3. 03クレジットパックの比例失効
  4. 04サブスクリプションと支払いモードの区別

活用シーン

  1. 01Stripe 返金 Webhook の実装
  2. 02異議申し立ての開始と終了への対応
  3. 03返金後のクレジット比例失効

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill stripe-refund-dispute-lifecycle

インストール後、Claude Code で/stripe-refund-dispute-lifecycleを入力して読み込まれたか確認します。

詳細

クイックリファレンス

イベントアクション主なルール
charge.refunded返金差額に比例したクレジットを取り消しますG2 — previous_attributes.amount_refunded
charge.dispute.createdユーザーを past_due に設定し、チェックポイントを保存しますG1 + G9
charge.dispute.closedwon / warning_closed / prevented -> 復元、lost -> 何もしない(charge.refunded が処理)、それ以外 -> 何もしないG5 + G7
返金元の優先順位使用するタイミング
event.data.previous_attributes.amount_refunded (G2)第一候補 — 常に優先します
charge.refunds.data (created の降順でソート)previous_attributes がない場合のフォールバック
stripe.refunds.list({charge, limit:1})埋め込みデータがない場合の最終手段
charge.amount_refunded のみ絶対に使用しない(イベントごとの値ではなく累計値)

このスキルを使用するタイミング

Stripe の返金イベントまたは異議申し立てイベントに応じて、クレジットを取り消す、または有料ステータスのカラムを変更するハンドラーを実装する場合に使用します。

関連スキル:

  • getRefundDelta(G2 の差分ヘルパー)については、stripe-billing-master:stripe-list-pagination-previous-attributes を参照してください
  • 標準の返金ヘルパーと監査行の不変条件については、stripe-billing-master:stripe-credit-audit-trail を参照してください
  • すべての異議申し立てハンドラーがラップする G1 チェックポイントパターンについては、stripe-billing-master:stripe-webhook-idempotency を参照してください

基本ルール

G2:返金差分

stripe-billing-master:stripe-list-pagination-previous-attributes の getRefundDelta() を使用してください。このスキルが差分計算ヘルパーを管理しています。重要な保証:利用可能なソースがない場合、ヘルパーは null を返します。ハンドラーは推測して取り消すのではなく、取り消しをスキップしなければなりません。

G7:網羅的な shouldRestoreStatus
const shouldRestoreMap = {
  won: true,
  warning_closed: true,
  prevented: true,
  lost: false,
  needs_response: false,
  under_review: false,
  warning_needs_response: false,
  warning_under_review: false,
  charge_refunded: false,
} satisfies Record<Stripe.Dispute.Status, boolean>;

export const shouldRestoreStatus = (s: Stripe.Dispute.Status): boolean => shouldRestoreMap[s];

Stripe が将来の SDK バージョンで新しいステータスを追加すると、このオブジェクトはキーを追加するまでコンパイルエラーになります。これにより、G5 の許可リストについて意識的に判断する必要が生じます。

クレジットパックとサブスクリプションの返金
async function resolveCreditsToRevoke(charge: Stripe.Charge, refundAmount: number) {
  const sessions = await stripe.checkout.sessions.list({
    payment_intent: charge.payment_intent as string,
    limit: 1,
    expand: ["data.line_items"],
  });
  const session = sessions.data[0];
  if (session?.mode !== "subscription") {
    const pack = CREDIT_PACKS.find(p => session?.line_items?.data?.[0]?.price?.id === p.priceId);
    if (pack && session.amount_total && session.amount_total > 0) {
      // Proportional revocation: if they refunded 50% of the pack, revoke 50% of the credits
      return Math.round(pack.credits * (refundAmount / session.amount_total));
    }
  }
  // Subscription: 1 credit = 1 cent at cash-equivalent
  return refundAmount;
}

クレジットパックの計算に関する注意:パックはまとめ買い価格が設定されているため(例:1000 クレジットが $10 ではなく $9)、返金に比例した取り消しが重要です。refundAmount -> credits の一律換算では、取り消しすぎになります。必ず元の Checkout Session を参照し、mode: "subscription"(現金相当)と、既知のパック価格 ID を持つ mode: "payment" を区別してください。

コメント