Лучшая практика для оплаты кошелька в laravel для системы бронирования авиабилетов - PullRequest
0 голосов
/ 13 февраля 2020

Предположим, что мы хотим создать систему бронирования рейсов, которая использует внешний API, у нас есть эти шаги, чтобы получить билет

  1. поиск рейсов
  2. выбор рейсов
  3. отправьте данные пассажира
  4. если на нашем кошельке достаточно средств можете заказать билет
  5. если у нас нет билета go на банковский шлюз и в обратном вызове в случае успеха оплата зарядить кошелек , а затем отправить в API на забронировать билет
  6. В случае неудачного платежа мы показываем ошибку и больше ничего не нужно делать

Для шага 5 я использую ATlpay API в качестве банковского шлюза, они работают с GET Обратный вызов

Я создаю базу данных транзакций с этими полями

Id             |             api_id     |   amount  |             status                         | user_id
Auto Increment | atlpay transaction id |  double   |  Enum('start' , 'failed' , 'success'  )    |  Auth::user()->id

*   default  status is start

Это сценарий отправки пользователя в банк Gateway

1.create transaction with price and user_id and status= 'start' as a default and return a transaction with id 7
    1.A and set **callback url** for bank like my_site.com/transaction/callback/7

2.post request to bank to get a url 
2.in successful request bank get us an url and atlpay_id like u3873873873873 that is unique
    2.A we save this id to transaction $transaction->api_id  = u3873873873873 ; $transaction->save();

3.redirect user to bank url like ( atlpay.com/transaction/u3873873873873)

4.after bank payment is complete bank redirect to our **callback url**  that set in step 1.A

после перенаправления банка на my_site.com/transaction/callback/7, я получаю транзакцию $ для этого пользователя и этот идентификатор транзакции (в данном примере - 7), если статус транзакции «старт»

и аф После этого я изменяю статус на Неудачный, на другой запрос не может попасть в эту транзакцию (Но я знаю, что это не гарантируется это требование! Я хочу найти наилучшую практику, чтобы только один запрос мог выполнить эту строку и другую строку после этого // ТОЛЬКО ОДИН ЗАПРОС ДОЛЖЕН достичь этого ++++

 $transaction= Auth::user()->transactions()
        ->where('status' , 'start')
        ->where('id' , $id)
        ->first();

    if(!$transaction)
        dd("You are not The owner");

//ONLY ONE REQUEST MUST achieve this ++++

    $transaction->status = 'failed';
    $transaction->save();

    $api_url = 'transactions/'.$transaction->api_id;
    $payment_data  = $this->get_transaction_payment_data($api_url);

    if(is_success_payment($payment_data )
       $this->charge_wallet($payment_data->price);

И моя функция charge_wallet равна

   public function charge_wallet($price)
{
    Wallet::where('user_id' , Auth::user()->id)->increment('amount', $price );
    return true;

}

1 Ответ

0 голосов
/ 13 февраля 2020

Я нашел решение для достижения критической секции, я не знаю, хорошо это или нет! Я использую вторую таблицу для генерации ключа

Table:transaction_keys
transaction_id  , key ( unique)  , user_id

Я хочу создать только один ключ для каждой транзакции и вставить в базу данных и в текущем сеансе . (для каждой транзакции может быть сгенерирован только один ключ, другой запрос отклонен mysql!), первичный ключ таблицы - транзакция_id

public function success_transaction($transaction , $price)
{

    $transaction->status = 'success';
    $transaction->save();
    $user_key  = $this->create_user_key( $transaction);

    if($this->is_valid_user_key($user_key)){
        $this->charge_wallet($price);

    }else{
        dd($user_key);
        //Log or smth else
    }




}


public function is_valid_user_key($user_key)
{
    return $user_key['status'] == 'success';
}


public function create_user_key($transaction)
{

    try{

        $int1 = rand(30,40);
        $int2 = rand(40,50);
        $unique_id = Str::random($int1) . uniqid() . Str::random($int2);

        $user_key  = new UserKey();
        $user_key->transaction_id = $transaction->id;
        $user_key->user_id = Auth::user()->id;
        $user_key->user_key = $unique_id;
        $user_key->save();

        request()->session()->forget('user_key' );
        request()->session()->put('user_key' , $user_key);
        $end_data['status'] = 'success';
        $end_data['key'] = $unique_id;
        return $end_data;


    }catch (\Exception $exception){
        dd($exception);
        $end_data['status'] = 'error';

        return $end_data;
        //Log or smth else

    }

}
...