0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Stripeを使った決済の払い戻しの実装

Posted at

前回、Stripe APIを使用した支払い機能の実装方法を紹介しました。今回は、支払いの取り消し(払い戻し)機能を実装したので、その手順とコードをこちらで記載しておこうと思います。

今回実施する環境

バージョン: PHP 8.2.9
エディター: vsCode

stripe_paymentsテーブルを作成

払い戻し機能の実装に際しては、まず支払い記録を保存するテーブルを作成する必要があります。このテーブルは、Stripeで行われた支払いに関する情報を保存し、後の取り消し処理にも役立ちます。そこで、まずはstripe_paymentsテーブルを作成し、支払い記録を保存する仕組みを作ります。

php artisan make:migration create_payments_table --create=payments
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('stripe_payments', function (Blueprint $table) {
            $table->id('stripe_payment_id');
            $table->foreignId('appointment_id')
            ->nullable()    
            ->references('appointment_id')
            ->on('appointments')     
            ->onUpdate('cascade')
            ->onDelete('cascade');

            $table->string('charge_id');
            $table->decimal('amount', 10, 2);
            $table->string('customer_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('stripe_payments');
    }
};

appointment_id: ここでは、予約情報が保存されているappointmentsテーブルとStripeの支払い情報を関連付けるために、appointment_idを外部キーとして指定します。

charge_id: stripeの方で支払われた時に作成されるId
amount: 支払われた金額

customer_id: クレジット情報などをstripe側へ送信した際に発行されるId

php artisan migrate 

モデルを作成します

php artisan make:model StripePayment
Models/StripePayment
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;


class StripePayment extends Model
{
    use HasFactory;
    protected $table = 'stripe_payments';    
    protected $primaryKey = 'stripe_payment_id';    

    protected $fillable = [
        'appointment_id',
        'charge_id',
        'amount',
        'customer_id'   
    ];
}

stripe_paymentsテーブルデータの作成

支払い情報は、実際に予約が行われた時にstripe_paymentsテーブルに保存されるようにコードを記述していますが、その部分を説明すると本題から外れてしまいます。したがって、テストを行う際にはSeederを使用してデータを挿入し、動作を確認していただくことをお勧めします。

以下のようにデータを追加してテストを行ってください。
スクリーンショット 2024-11-12 22.46.50.png

予約の削除

今回は、予約が削除された際にその予約に対する払い戻しを行いたいため、予約IDを引数として受け取り、該当する予約に対して払い戻し処理を実行します。支払い処理はAppointmentControllerでは行わず、専用のServices/DeleteAppointmentクラスを作成して、そこで払い戻しと予約の削除処理を行うようにしています。

class AppointmentController extends Controller
{
 protected $storePaymentDetails;
 
  public function __construct(DeleteAppointment $deleteAppointment,)    
    {
        $this->deleteAppointment = $deleteAppointment;
    }
    <!--予約の実装などがありますが省略します-->
    /**
     * 予約の削除
     *
     * @param integer $appId
     * @return void
     */ 
    public function deleteAppointment(int $appId)
    {
        $deleteAppointment = $this->deleteAppointment->deleteAppointment($appId);
        return response()->json($deleteAppointment);
    }

払い戻し処理を行うファイルを作成

php artisan make:controller Services/DeleteAppointmentController

Services/DeleteAppointmentController
<?php

namespace App\Services;
use App\Models\Appointment; 
use Stripe\Stripe;  
use Stripe\Refund;  //支払いの処理を行う
use App\Models\StripePayment;   
use Exception;  

class DeleteAppointment
{
    /**
     * 予約の削除
     *
     * @param integer $appId
     * @return \Illuminate\Http\JsonResponse
     */ 
    public function deleteAppointment($appId)
    {
        $appointment = Appointment::query()->find($appId); 
        if ($appointment) {
        
            //支払い情報の取得
            $payment = StripePayment::query()->where('appointment_id', $appId)->first(); 

            try {
                if ($payment) {
                    $this->processRefund($payment);   
                }

                //予約の削除
                $appointment->delete();

                return response()->json(['message' => 'Deleted successfully',
            'refund_id' => $payment ? $payment->charge_id : null]); 
            } catch (Exception $e) {
                return response()->json([
                    'status' => 'error', 
                    'message' => 'Refund failed', 
                    'error' => $e->getMessage()
                ]);
            }
        } else {
            return response()->json(['message' => 'Record not found']);
        }
    }

     //ここでpaymentの情報を受け取り支払いの処理を行います。
    /*
     * 返金処理
     *
     * @param StripePayment $payment
     * @return void
     */ 
    private function processRefund($payment)
    {
        Stripe::setApiKey(env('STRIPE_SECRET'));

        $refund = Refund::create([
            'charge' => $payment->charge_id,
        ]); 
    }
}

実装の概要
今回の実装では、予約(Appointment)が削除された際に、関連する支払い情報を払い戻しする処理を行いました。予約削除時に払い戻しが必要なケースを想定し、StripeのAPIを利用して返金処理を行っています。実際には、予約に紐づく支払い情報があればその払い戻しを実行し、その後予約を削除する流れです。

もし予約以外のトリガーで支払い処理を行いたい場合は、Appointmentに関連する部分を別のモデルに置き換えていただければ、同様の処理が可能です。例えば、注文や購買など、他のシステムでも応用できると思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?