I have a multi-step form for a user to register in a conference, all steps are in the same registration.blade.php page, in step 1 and step 2 is done an ajax request to validate the form fields.

这些步骤是:

  • Step1 is to collect some info about the user (name and tin number)
  • 第2步是收取付款方式(credit card or references)
  • Step 3 is the payment
  • 第4步显示成功消息(this step only appears after a successful payment with a credit card, with the references payment method this step don't appear, with references payment method only the step 1, 2 and 3 appears)

我的怀疑介于第二步和第三步之间.

If the selected payment method references is necessary to execute the code below, that generates some payment references and then present that references to the user in step 3. When the user pays the system receives a notification and should be inserted in the payments table the price, payment_method_id, registration_id and status (paid).

Code to process payments with references:

    public function ReferencesCharge(Request $request)
        {
           $payment_info = [
        'name' => "user name",
        'email' => 'user email',
        'value' => 'registration total price',
        'id' => 'registration id',
    ];

    $newPayment = new Payment($payment_info);
    $reference = $newPayment->gererateReferences();

    //$reference returns an array with necessary codes to present to the user so he can pay

    // after generate references is necessary:
            // show in step 3 the generated references
            // insert an entry in the payments table when the system receives a notification from 3rd party service informing that the user did the payment

}

如果 Select 的付款是信用卡,则需要执行下面的代码以向信用卡收费,然后将其插入付款表pricepayment_method_idregistration_idstatus(paid).然后,用户应该被重定向到步骤4,以显示一条成功消息:

Code to process credit card payments:

public function creditCardCharge(Request $request)
    {
        Stripe::setApiKey(config('services.stripe.secret'));
        $source = $request->stripeToken;

        try{
            Charge::create([
                'currency' => 'eur',
                'amount' => 2500,
                'source' => $source,
            ]);
        }
        catch(\Exception $e){
            return response()->json(['status' => $e->getMessage()], 422);
        }

        // after charging the card with success:
            // insert an entry in the payments table 
            // redirect to success confirmation step to inform the user that payment was done with success 
    }

My doubt is how the flow should be, where the code to handle the payment with references and the code to handle the payment with a credit card should be placed. So is possible to achieve this scenario:

enter image description here

For now, I just have the step 1 and step 2 working properly. To handle step1 and step2 I have the RegistrationController. In the step1 the info introduced by the user is validated using an ajax post request to the storeUserInfo() method of the RegistrationController if returns 200 the user goes to step2.

In the step2, the user selects the payment method and clicks in "go to step 3" is also done an ajax request to the storePaymentMethods() of the RegistrationController to validate if the user selected at least 1 payment method. My doubt is after this method return code 200 how the process should be.

根据付款方式的不同,需要运行上面的相应代码(code that generates payment references or code to charge credit card).

因此,我怀疑如何从控制器和方法的Angular 组织这些代码,根据所选的支付方法,将应该执行的代码放在何处.你知道流程应该如何实现这一点吗?

Maybe an approach can be something like below in storePaymentMethods() but it doesn't seem very correct do everything in this method:

public function storePaymentMethods(Request $request){
       $request->validate([
            'payment_method' => 'required',
        ]);

        if($request->payment_method == "references"){
          // generate codes and present to the user that codes
        }
        else if($request->payment_method == "credit_card"){
          // show credit card inputs to the user
          // and process the credit card payment with stripe
        }



        return response()->json([
            'success' => true,
            'message' => 'success',
            'payment_method' => $request->payment_method,
        ], 200);
    }

A full summary of the flow of the registration with the multistep form that I have for now:

So for the step1, there is the form:

<div>
    <form method="post" id="step1form" action="">
        {{csrf_field()}}
        <!-- fields of the step 1-->
        <input type="submit" href="#step2" id="goToStep2" class="btn next-step" value="Go to step 2"/>
    </form>
</div>

step1 image to explain better:

enter image description here

当用户点击"Go to Step 2"按钮时,AJAX请求验证数据,如果没有错误,则返回代码200,用户转到步骤2:

$('#goToStep2').on('click', function (event) {
    event.preventDefault();
    var custom_form = $("#" + page_form_id_step1);
    $.ajax({
        method: "POST",
        url: '{{ route('conferences.storeRegistrationInfo', compact('id','slug') ) }}',
        data: custom_form.serialize(),
        datatype: 'json',
        success: function (data, textStatus, jqXHR) {
            var $active = $('.nav-pills li a.active');
            nextTab($active);
        },
        error: function (data) {    
            // show errors
        }
    });
});

Then in the ConferencesController there is teh storeRegistrationInfo() to handle the above ajax request:

public function storeRegistrationInfo(Request $request, $id, $slug = null, Validator $validator){  
    $rules = [];
    $messages = [];

    $rules["name_invoice"] = 'required|max:255|string';
    $rules["TIN_invoice"] = ['required', 'string', new ValidTIN()];

    $validator = Validator::make($request->all(), $rules, $messages);

    $errors = $validator->errors();
    $errors =  json_decode($errors);

    if($validator->fails()) {
        return response()->json([
            'success' => false,
            'errors' => $errors
        ], 422);
    }
    return response()->json([
        'success' => true,
        'message' => 'success'
    ], 200);
}

因此,如果返回代码200,则用户在step2form中:

<div>
    <form method="post" id="step2form" action="">
        {{csrf_field()}}
        <!-- fields of the step 2-->
         <input type="submit" href="#step3" id="goToStep3" class="btn next-step" value="Go to step 3"/>
    </form>
</div>

Step2图像更好地解释:

enter image description here

当用户点击"转到步骤3"按钮时,会发出ajax请求以验证数据,如果没有错误,则返回代码200,用户转到步骤3,ajax请求:

$("#credit_card_section").hide();
$("#references_section").hide();

var page_form_id_step2 = "step2form";

    $('#goToStep3').on('click', function (event) {
        event.preventDefault();
        var custom_form = $("#" + page_form_id_step2);
        $.ajax({
            method: "POST",
            url: '{{ route('conferences.storePaymentMethods', compact('id','slug') ) }}',
            data: custom_form.serialize(),
            datatype: 'json',
            success: function (data, textStatus, jqXHR) {
                var result = data;
                if(result['payment_method'] == 'credit_card'){
                    $("#credit_card_section").show();
                    $("#references_section").hide();
                }else{
                    $("#references_section").show();
                    $("#credit_card_section").hide();
                }
                var $active = $('.nav-pills li a.active');
                nextTab($active);
            },
            error: function (data) {
               // show errors
            }
        });
    });

ConferenceController使用storePayment()来处理上面的Ajax请求,它验证用户是否 Select 了支付方式,如果 Select 了,则返回代码200:

public function storePaymentMethods(Request $request){
       $request->validate([
            'payment_method' => 'required',
        ]);
        return response()->json([
            'success' => true,
            'message' => 'success',
            'payment_method' => $request->payment_method,
        ], 200);
    }

Then there is the step3 div. In the step3 div it will appear the div #credit_card_section visible or #references_section visible depending on the payment method selected in the previous step (credit card or references):

<div>
    <form method="post" id="step3form" action="">
            {{csrf_field()}}
            <div id="credit_card_section">
                <!-- present necessary fields to
                payments with credit card-->
            </div>
              <div id="references_section">
        <!-- present generated reference to the user so he can pay-->
            </div>
    </form>
</div>

step3 image to explain better, depending on the payment method the info that is necessary to show in step 3 is different. If the payment method was credit card also appears a step4 div showing a success message after a successful charge with a credit card:

enter image description here

然后是step 4 div,在使用信用卡完成支付后,它将显示成功消息:

<div id="step4">
   <p>
   <i class="fa fa-plus" aria-hidden="true"></i>
   Payment and registration completed with  success.
   </p>
</div>

//继续我目前拥有的RegistrationController的方法,RegistrationController是我拥有的处理多步骤表单的控制器

class RegistrationController extends Controller
{
    public :function storeQuantities(Request $request, $id, $slug = null){
        // method that stores in session the ticket types 
       // selected by the user in the conference details page
        Session::put('selectedRtypes', $selectedRtypes);
        Session::put('allParticipants' , $allParticipants);
        Session::put('customQuestions' ,  $selectedRtypes[$rtype->name]['questions']);

        // and then redirects the user to the registartion page registration.blade.php 
        // using the route 'conferences.registration
        // this route is associated with the displayRegistrationPage() method
        return redirect(route('conferences.registration',['id' => $id, 'slug' => $slug]));
    }


  // method of the route 'conferences.registration' that displays
 //  the registration.blade.php that is the page with the multi step form
    public function displayRegistrationPage(Request $request, $id, $slug=null){
        // get the session values
        $selectedRtypes =  Session::get('selectedRtypes');
        $allParticipants = Session::get('allParticipants');
        $customQuestions = Session::get('customQuestions');

   // redirect the user to the registration.blade.php
        if(isset($selectedRtypes)) {
            return view('conferences.registration',
                ['selectedRtypes' => $selectedRtypes, 'customQuestions' => $customQuestions, 'id' => $id, 'slug' => $slug]);
        }
        else{
            // return user to the conference details page
            return redirect(route('conferences.show',['id' => $id, 'slug' => $slug]));
        }
    }

   /* the following methods are to handle the registration
      multi step  form of the registration.blade.php view */

   // method to handle the step1 of the multi step form
    public function storeRegistrationInfo(Request $request, $id, $slug = null, Validator $validator){

        // get and validate the fields of the step1 
       // and returns code 200 if al is ok

        return response()->json([
            'success' => true,
            'message' => 'success'
        ], 200);
    }


   // method to handle the step2 of the multi step form
    public function storePaymentMethods(Request $request){

        // validate if the payment_method field was filled
        // if was filled return code 200 
        // and returns the payment_method 
        //so in the step 3 div is possible to show a section for
       // when the payment_method is credit card (#credit_card_section) 
          or transfers ("transfers_section")
        return response()->json([
            'success' => true,
            'message' => 'success',
            'payment_method' => $request->payment_method,
        ], 200);
    }
}

step1人路由:

Route::post('/conference/{id}/{slug?}/registration/storeRegistrationInfo', [
    'uses' => 'RegistrationController@storeRegistrationInfo',
    'as'   =>'conferences.storeRegistrationInfo'
]);

Route for step2:

Route::post('/conference/{id}/{slug?}/registration/storePaymentMethods', [
    'uses' => 'RegistrationController@storePaymentMethods',
    'as'   =>'conferences.storePaymentMethods'
]);

推荐答案

As in your doubts, to better structure your code and separate logic (DRY concept), you should do few things:

  • Create PaymentsController with 3 functions (for the start, you will definitely add more here)

    1. for processing your references
    2. for processing credit cards
    3. 用于存储支付方式(在会话中存储支付方式,直到用户完成步骤3)

    You are totally free, on how you name these functions, but I would suggest something like processViaReferences, processViaCreditCard and storePaymentMethod.

    It will be much easier to read and validate, if you have them separated.

    Create corresponding post routes for them and reference appropriately, in cour code.

  • 创建仅包含窗体的部件视图.

    Then include, these part views via @include to have it separated on view level. For your references in javascript/jQuery, remember to keep correct ids of them. You can extract javascript, to other view part views or separate js files also, if you have not done it already.

    Your view/form code should go to these part views...

Laravel相关问答推荐

哈希:check()不返回预期结果Laravel 10

在Laravel Lumen中迭代连接查询数据

使用MAATWebSite/EXCEL导入Exel时,不会创建Laravel模型

运行NPM Prod时出现VUE问题

Laravel mail send Amazon SES不再支持TLS 1.0和TLS 1.1连接

laravel Eloquent 模型更新事件未触发

Laravel & Docker:无法打开流或文件/var/www/html/storage/logs/laravel.log:无法打开流:权限被拒绝

Laravel belongsTo 关系 - 试图获取非对象的属性

插入重复键时,laravel eloquent 忽略错误

Eloquent: hasNot 带参数

Lumen和 MongoDB?

Laravel:如何通过 id 从集合中删除项目

在 laravel 如何将额外的数据传递给 mutators 和 accessors

带有消息...必须返回关系实例的 LogicException.

从 sqlite DB 登录 Laravel,得到PDOException 找不到驱动程序

如何对模型执行删除操作?

当表中不存在列时如何将 paginate() 与 having() 子句一起使用

在 Laravel 中按用户名查找用户

在 Laravel artisan 命令中使用详细

使用迁移更改表 Laravel 5